Skip to content

Commit

Permalink
Add ldn_mitm as a network client for LDN (#5656)
Browse files Browse the repository at this point in the history
* Add relevant files from private repo

Hopefully I didn't miss anything.

JsonHelper.cs is a debug only change
I only added line 810-812 in IUserLocalCommunicationService.cs
for the new Spacemeowx2Ldn case.

* Add a small README.md

just for fun

* Add note about NetCoreServer update to 5.1.0

* Fix a few issues

Fix usage of wrong broadcast address
Log warning if empty userstring was received
and don't add them to outNetworkInfo

* Add warning about incompatibility with public LDN version

* Add missing changes from old_master

* Adjust ldn_mitm for Ryujinx/Ryujinx#3805

* ldn: Adapt to changes from #4582

* ldn_mitm: First cleanup iteration

* ldn_mitm: Second cleanup iteration

* Credit spacemeowx2 in README.md

* Address first review comments by AcK

Adhere to Ryujinx coding style
Remove leftover log calls
Change category of a few log calls
Remove leftover debug notes

* Replace return type with void for methods always returning true

* Address first review comments by riperiperi

Purely stylistic changes:
- Adhere to naming style for internal fields
- Improve code formatting

* Throw InvalidOperationException when calling wrong ldn proxy methods

* Add missing newlines in LanDiscovery.Scan()

* Fix Linux not receiving broadcast packets

* Remove ILdnUdpSocket

It's very unlikely that we will ever need a udp client.
Thus we should simplify LanDiscovery initialization
and remove the parameter of InitUdp().

* ldn_mitm: Improve formatting

* fixup! Fix Linux not receiving broadcast packets

By opening the udp server on 'LocalBroadcastAddr'
Linux refused to answer packets going to LocalAddr.
So in order to fix this problem, Linux now opens two LdnProxyUdpServers.

* ldn_mitm: Fix assigning incorrect NodeIds

This just made connecting a lot more reliable! Thanks @riperiperi

* Fix node ids when leaving/joining

* Change NodeId behaviour to work like RyuLdn

* Change timing for accept and network info being reported.

* Wait for connection before sending anything.

* Remove ConnectAsync() from ILdnTcpSocket

* Only broadcast scan responses if we're hosting a network.

* Fix some filters, scan network duplication.

* Fix silly mistake

* Don't die on duplicates, just replace.

* Lock around node updates

These can happen from multiple threads.

* ldn_mitm: Fix namespaces for Types

Improve formatting
Add warning if compression failed

* Add quicker scan, forgetting networks that disappear.

* Always force a network sync when updating AdvertiseData

* Fix TCP frame size being too large for compressed frames

* Allow ldn_mitm to pass -1 id for room localcommunicationids.

* ldn_mitm: Match server socket options

* ldn_mitm: Use correct socket options

* ldn_mitm: Remove TCP broadcast socket options

* config: Rename Spacemeowx2Ldn to LdnMitm

* ldn_mitm: Generate random fake SSID

* ldn_mitm: Adjust logging statements/levels

* ldn_mitm: Add missing Stop() call for udp2

* ldn_mitm: Adjust formatting

* ldn_mitm: Add stub comments and adjust existing ones

* ldn: Add LdnConst class & set tx/rx buffer sizes correctly

* Move LdnConst out of UserServiceCreator

Replace a few values with LdnConsts

* ldn: Adjust namespaces and client names

* ldn_mitm: Adjust formatting

* ldn: Rename RyuLdn to LdnRyu

* Replace LanProtocol.Read() refs with scoped refs

* Add MIT license for ldn_mitm

* Clarify that network interface is also used for LDN

Although it's currently only used by ldn_mitm,
it would probably be more confusing to exclude RyuLdn there.

* Fix giving a station node id 0

* Update Nuget packages

* Remove LdnHelper

* Add update functions for EnableInternetAccess setting

* ldn: Log MultiplayerMode and DisableP2P

* ldn: Adjust namespaces

* Apply formatting

* Conform to Ryujinx code style

* Remove ldn_mitm from THIRDPARTY.md

It shouldn't have been there in the first place.

* Improve formatting

---------

Co-authored-by: riperiperi <[email protected]>
Co-authored-by: Ac_K <[email protected]>
  • Loading branch information
3 people authored Oct 25, 2023
1 parent 171b46e commit c14ce4d
Show file tree
Hide file tree
Showing 43 changed files with 1,556 additions and 43 deletions.
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageVersion Include="OpenTK.Core" Version="4.7.7" />
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,5 @@ See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY

- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
2 changes: 1 addition & 1 deletion distribution/legal/THIRDPARTY.md
Original file line number Diff line number Diff line change
Expand Up @@ -710,4 +710,4 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
</details>
</details>
6 changes: 6 additions & 0 deletions src/Ryujinx.Ava/AppHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ public AppHost(
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;

ConfigurationState.Instance.System.EnableInternetAccess.Event += UpdateEnableInternetAccessState;
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
ConfigurationState.Instance.Multiplayer.Mode.Event += UpdateMultiplayerModeState;

Expand Down Expand Up @@ -408,6 +409,11 @@ private void UpdateAudioVolumeState(object sender, ReactiveEventArgs<float> e)
});
}

private void UpdateEnableInternetAccessState(object sender, ReactiveEventArgs<bool> e)
{
Device.Configuration.EnableInternetAccess = e.NewValue;
}

private void UpdateLanInterfaceIdState(object sender, ReactiveEventArgs<string> e)
{
Device.Configuration.MultiplayerLanInterfaceId = e.NewValue;
Expand Down
2 changes: 1 addition & 1 deletion src/Ryujinx.Ava/Assets/Locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@
"UserEditorTitle": "Edit User",
"UserEditorTitleCreate": "Create User",
"SettingsTabNetworkInterface": "Network Interface:",
"NetworkInterfaceTooltip": "The network interface used for LAN features",
"NetworkInterfaceTooltip": "The network interface used for LAN/LDN features",
"NetworkInterfaceDefault": "Default",
"PackagingShaders": "Packaging Shaders",
"AboutChangelogButton": "View Changelog on GitHub",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
public enum MultiplayerMode
{
Disabled,
LdnMitm,
}
}
5 changes: 5 additions & 0 deletions src/Ryujinx.Common/Utilities/NetworkHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,10 @@ public static uint ConvertIpv4Address(string ipAddress)
{
return ConvertIpv4Address(IPAddress.Parse(ipAddress));
}

public static IPAddress ConvertUint(uint ipAddress)
{
return new IPAddress(new byte[] { (byte)((ipAddress >> 24) & 0xFF), (byte)((ipAddress >> 16) & 0xFF), (byte)((ipAddress >> 8) & 0xFF), (byte)(ipAddress & 0xFF) });
}
}
}
2 changes: 1 addition & 1 deletion src/Ryujinx.HLE/HLEConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public class HLEConfiguration
/// <summary>
/// Control if the guest application should be told that there is a Internet connection available.
/// </summary>
internal readonly bool EnableInternetAccess;
public bool EnableInternetAccess { internal get; set; }

/// <summary>
/// Control LibHac's integrity check level.
Expand Down
12 changes: 12 additions & 0 deletions src/Ryujinx.HLE/HOS/Services/Ldn/LdnConst.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Ryujinx.HLE.HOS.Services.Ldn
{
static class LdnConst
{
public const int SsidLengthMax = 0x20;
public const int AdvertiseDataSizeMax = 0x180;
public const int UserNameBytesMax = 0x20;
public const int NodeCountMax = 8;
public const int StationCountMax = NodeCountMax - 1;
public const int PassphraseLengthMax = 0x40;
}
}
2 changes: 1 addition & 1 deletion src/Ryujinx.HLE/HOS/Services/Ldn/Types/LdnNetworkInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;

namespace Ryujinx.HLE.HOS.Services.Ldn.Types
Expand Down
2 changes: 1 addition & 1 deletion src/Ryujinx.HLE/HOS/Services/Ldn/Types/NodeInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;

namespace Ryujinx.HLE.HOS.Services.Ldn.Types
Expand Down
4 changes: 2 additions & 2 deletions src/Ryujinx.HLE/HOS/Services/Ldn/Types/NodeLatestUpdate.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;

namespace Ryujinx.HLE.HOS.Services.Ldn.Types
Expand Down Expand Up @@ -48,7 +48,7 @@ public static NodeLatestUpdate[] ConsumeLatestUpdate(this Array8<NodeLatestUpdat
{
result[i].Reserved = new Array7<byte>();

if (i < 8)
if (i < LdnConst.NodeCountMax)
{
result[i].State = array[i].State;
array[i].State = NodeLatestUpdateFlags.None;
Expand Down
2 changes: 1 addition & 1 deletion src/Ryujinx.HLE/HOS/Services/Ldn/Types/SecurityConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;

namespace Ryujinx.HLE.HOS.Services.Ldn.Types
Expand Down
2 changes: 1 addition & 1 deletion src/Ryujinx.HLE/HOS/Services/Ldn/Types/Ssid.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;

namespace Ryujinx.HLE.HOS.Services.Ldn.Types
Expand Down
2 changes: 1 addition & 1 deletion src/Ryujinx.HLE/HOS/Services/Ldn/Types/UserConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;

namespace Ryujinx.HLE.HOS.Services.Ldn.Types
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.HLE.HOS.Services.Ldn.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Network.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.RyuLdn.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Types;
using System;

namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
Expand Down Expand Up @@ -30,7 +29,7 @@ public void Dispose()
_parent.NetworkClient.NetworkChange -= NetworkChanged;
}

private void NetworkChanged(object sender, RyuLdn.NetworkChangeEventArgs e)
private void NetworkChanged(object sender, NetworkChangeEventArgs e)
{
LatestUpdates.CalculateLatestUpdate(NetworkInfo.Ldn.Nodes, e.Info.Ldn.Nodes);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using Ryujinx.HLE.HOS.Services.Ldn.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Network.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.RyuLdn.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Types;
using System;

namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.RyuLdn
namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
{
interface INetworkClient : IDisposable
{
bool NeedsRealId { get; }

event EventHandler<NetworkChangeEventArgs> NetworkChange;

void DisconnectNetwork();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Ldn.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.RyuLdn;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnMitm;
using Ryujinx.Horizon.Common;
using Ryujinx.Memory;
using System;
Expand Down Expand Up @@ -395,7 +395,7 @@ private ResultCode ScanImpl(ServiceCtx context, bool isPrivate = false)
}
else
{
if (scanFilter.NetworkId.IntentId.LocalCommunicationId == -1)
if (scanFilter.NetworkId.IntentId.LocalCommunicationId == -1 && NetworkClient.NeedsRealId)
{
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented.
ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
Expand Down Expand Up @@ -546,7 +546,7 @@ public ResultCode CreateNetworkImpl(ServiceCtx context, bool isPrivate = false)
context.RequestData.BaseStream.Seek(4, SeekOrigin.Current); // Alignment?
NetworkConfig networkConfig = context.RequestData.ReadStruct<NetworkConfig>();

if (networkConfig.IntentId.LocalCommunicationId == -1)
if (networkConfig.IntentId.LocalCommunicationId == -1 && NetworkClient.NeedsRealId)
{
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented.
ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
Expand All @@ -555,7 +555,7 @@ public ResultCode CreateNetworkImpl(ServiceCtx context, bool isPrivate = false)
}

bool isLocalCommunicationIdValid = CheckLocalCommunicationIdPermission(context, (ulong)networkConfig.IntentId.LocalCommunicationId);
if (!isLocalCommunicationIdValid)
if (!isLocalCommunicationIdValid && NetworkClient.NeedsRealId)
{
return ResultCode.InvalidObject;
}
Expand All @@ -568,13 +568,13 @@ public ResultCode CreateNetworkImpl(ServiceCtx context, bool isPrivate = false)
networkConfig.Channel = CheckDevelopmentChannel(networkConfig.Channel);
securityConfig.SecurityMode = CheckDevelopmentSecurityMode(securityConfig.SecurityMode);

if (networkConfig.NodeCountMax <= 8)
if (networkConfig.NodeCountMax <= LdnConst.NodeCountMax)
{
if ((((ulong)networkConfig.LocalCommunicationVersion) & 0x80000000) == 0)
{
if (securityConfig.SecurityMode <= SecurityMode.Retail)
{
if (securityConfig.Passphrase.Length <= 0x40)
if (securityConfig.Passphrase.Length <= LdnConst.PassphraseLengthMax)
{
if (_state == NetworkState.AccessPoint)
{
Expand Down Expand Up @@ -678,7 +678,7 @@ public ResultCode SetAdvertiseData(ServiceCtx context)
return _nifmResultCode;
}

if (bufferSize == 0 || bufferSize > 0x180)
if (bufferSize == 0 || bufferSize > LdnConst.AdvertiseDataSizeMax)
{
return ResultCode.InvalidArgument;
}
Expand Down Expand Up @@ -848,10 +848,10 @@ private ResultCode ConnectImpl(ServiceCtx context, bool isPrivate = false)

context.Memory.Read(bufferPosition, networkInfoBytes);

networkInfo = MemoryMarshal.Cast<byte, NetworkInfo>(networkInfoBytes)[0];
networkInfo = MemoryMarshal.Read<NetworkInfo>(networkInfoBytes);
}

if (networkInfo.NetworkId.IntentId.LocalCommunicationId == -1)
if (networkInfo.NetworkId.IntentId.LocalCommunicationId == -1 && NetworkClient.NeedsRealId)
{
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented.
ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
Expand All @@ -860,7 +860,7 @@ private ResultCode ConnectImpl(ServiceCtx context, bool isPrivate = false)
}

bool isLocalCommunicationIdValid = CheckLocalCommunicationIdPermission(context, (ulong)networkInfo.NetworkId.IntentId.LocalCommunicationId);
if (!isLocalCommunicationIdValid)
if (!isLocalCommunicationIdValid && NetworkClient.NeedsRealId)
{
return ResultCode.InvalidObject;
}
Expand Down Expand Up @@ -1061,10 +1061,16 @@ public ResultCode InitializeImpl(ServiceCtx context, ulong pid, int nifmRequestI
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
MultiplayerMode mode = context.Device.Configuration.MultiplayerMode;

Logger.Info?.PrintMsg(LogClass.ServiceLdn, $"Initializing with multiplayer mode: {mode}");

switch (mode)
{
case MultiplayerMode.LdnMitm:
NetworkClient = new LdnMitmClient(context.Device.Configuration);
break;
case MultiplayerMode.Disabled:
NetworkClient = new DisabledLdnClient();
NetworkClient = new LdnDisabledClient();
break;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using Ryujinx.HLE.HOS.Services.Ldn.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Network.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.RyuLdn.Types;
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.Types;
using System;

namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.RyuLdn
namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
{
class DisabledLdnClient : INetworkClient
class LdnDisabledClient : INetworkClient
{
public bool NeedsRealId => true;

public event EventHandler<NetworkChangeEventArgs> NetworkChange;

public NetworkError Connect(ConnectRequest request)
Expand Down
Loading

0 comments on commit c14ce4d

Please sign in to comment.