mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-23 13:02:08 +00:00
fix RyuLDN proxy routing and add Mii DB logging
Fix is not currently functionnal, i'm just committing this so i can work on another branch locally, but there has been progress in regards of mii sharing. a substatial part of this code doesn't go towards resolving mii sharing over LDN, its just WIP stuff
This commit is contained in:
parent
76f8446391
commit
7c2dae6360
7 changed files with 450 additions and 25 deletions
|
|
@ -1,4 +1,8 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Services.Ldn.Types;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
||||
{
|
||||
|
|
@ -6,6 +10,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
|||
{
|
||||
private const int NifmRequestId = 90;
|
||||
|
||||
private bool _actionFrameEnabled;
|
||||
|
||||
protected override bool ValidateLocalCommunicationId => false;
|
||||
|
||||
public ISystemLocalCommunicationService(ServiceCtx context) : base(context) { }
|
||||
|
||||
// NOTE: This overrides the parent's Initialize method with the same command ID (402)
|
||||
|
|
@ -19,6 +27,123 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
|||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(500)] // 18.0.0+
|
||||
// EnableActionFrame(nn::ldn::ActionFrameSettings)
|
||||
public ResultCode EnableActionFrame(ServiceCtx context)
|
||||
{
|
||||
byte[] settings = context.RequestData.ReadBytes(0x80);
|
||||
|
||||
_actionFrameEnabled = true;
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn, new
|
||||
{
|
||||
localCommunicationId = System.BitConverter.ToUInt64(settings, 0),
|
||||
securityMode = System.BitConverter.ToUInt16(settings, 0x3c),
|
||||
passphraseSize = System.BitConverter.ToUInt16(settings, 0x3e),
|
||||
});
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(501)] // 18.0.0+
|
||||
// DisableActionFrame()
|
||||
public ResultCode DisableActionFrame(ServiceCtx context)
|
||||
{
|
||||
_actionFrameEnabled = false;
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(502)] // 18.0.0+
|
||||
// SendActionFrame(buffer<unknown, 0x21>, nn::ldn::MacAddress, nn::ldn::MacAddress, s16 channel, u32 flags)
|
||||
public ResultCode SendActionFrame(ServiceCtx context)
|
||||
{
|
||||
Array6<byte> destination = context.RequestData.ReadStruct<Array6<byte>>();
|
||||
Array6<byte> bssid = context.RequestData.ReadStruct<Array6<byte>>();
|
||||
short channel = context.RequestData.ReadInt16();
|
||||
_ = context.RequestData.ReadInt16();
|
||||
uint flags = context.RequestData.ReadUInt32();
|
||||
|
||||
(ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x21();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn, new
|
||||
{
|
||||
enabled = _actionFrameEnabled,
|
||||
bufferPosition,
|
||||
bufferSize,
|
||||
destination,
|
||||
bssid,
|
||||
channel,
|
||||
flags,
|
||||
});
|
||||
|
||||
return _actionFrameEnabled && bufferPosition != 0 && bufferSize != 0
|
||||
? ResultCode.Success
|
||||
: ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
[CommandCmif(503)] // 18.0.0+
|
||||
// RecvActionFrame(u32 flags, buffer<unknown, 0x22>) -> nn::ldn::MacAddress, nn::ldn::MacAddress, s16 channel, u32 size, s32 link_level
|
||||
public ResultCode RecvActionFrame(ServiceCtx context)
|
||||
{
|
||||
uint flags = context.RequestData.ReadUInt32();
|
||||
(ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x22();
|
||||
|
||||
if (bufferPosition != 0 && bufferSize != 0)
|
||||
{
|
||||
MemoryHelper.FillWithZeros(context.Memory, bufferPosition, (int)bufferSize);
|
||||
}
|
||||
|
||||
context.ResponseData.WriteStruct(new Array6<byte>());
|
||||
context.ResponseData.WriteStruct(new Array6<byte>());
|
||||
context.ResponseData.Write((short)0);
|
||||
context.ResponseData.Write((ushort)0);
|
||||
context.ResponseData.Write(0u);
|
||||
context.ResponseData.Write(0);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn, new
|
||||
{
|
||||
enabled = _actionFrameEnabled,
|
||||
bufferSize,
|
||||
flags,
|
||||
});
|
||||
|
||||
return _actionFrameEnabled ? ResultCode.Success : ResultCode.InvalidState;
|
||||
}
|
||||
|
||||
[CommandCmif(505)] // 18.0.0+
|
||||
// SetHomeChannel(s16 channel)
|
||||
public ResultCode SetHomeChannel(ServiceCtx context)
|
||||
{
|
||||
short channel = context.RequestData.ReadInt16();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn, new { channel });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(600)] // 18.0.0+
|
||||
// SetTxPower(s32 power)
|
||||
public ResultCode SetTxPower(ServiceCtx context)
|
||||
{
|
||||
int power = context.RequestData.ReadInt32();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn, new { power });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(601)] // 18.0.0+
|
||||
// ResetTxPower()
|
||||
public ResultCode ResetTxPower(ServiceCtx context)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(403)]
|
||||
// InitializeWithVersion(s32 version, pid)
|
||||
public ResultCode InitializeWithVersion(ServiceCtx context)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
|||
private AccessPoint _accessPoint;
|
||||
private Station _station;
|
||||
|
||||
protected virtual bool ValidateLocalCommunicationId => true;
|
||||
|
||||
private ushort CheckDevelopmentChannel(ushort channel)
|
||||
{
|
||||
return (ushort)(!IsDevelopment ? 0 : channel);
|
||||
|
|
@ -531,7 +533,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
|||
|
||||
[CommandCmif(200)]
|
||||
// OpenAccessPoint()
|
||||
public ResultCode OpenAccessPoint(ServiceCtx context)
|
||||
public virtual ResultCode OpenAccessPoint(ServiceCtx context)
|
||||
{
|
||||
if (_nifmResultCode != ResultCode.Success)
|
||||
{
|
||||
|
|
@ -620,7 +622,9 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
|
|||
networkConfig.IntentId.LocalCommunicationId = (long)controlProperty.LocalCommunicationId[0];
|
||||
}
|
||||
|
||||
bool isLocalCommunicationIdValid = CheckLocalCommunicationIdPermission(context, (ulong)networkConfig.IntentId.LocalCommunicationId);
|
||||
bool isLocalCommunicationIdValid = !ValidateLocalCommunicationId ||
|
||||
CheckLocalCommunicationIdPermission(context, (ulong)networkConfig.IntentId.LocalCommunicationId);
|
||||
|
||||
if (!isLocalCommunicationIdValid && NetworkClient.NeedsRealId)
|
||||
{
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceLdn, "CreateNetworkImpl: Invalid object!");
|
||||
|
|
|
|||
|
|
@ -473,6 +473,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
|||
public bool CreateNetwork(CreateAccessPointRequest request, byte[] advertiseData)
|
||||
{
|
||||
_timeout.DisableTimeout();
|
||||
_apConnected.Reset();
|
||||
|
||||
ConfigureAccessPoint(ref request.RyuNetworkConfig);
|
||||
|
||||
|
|
@ -528,6 +529,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
|||
public bool CreateNetworkPrivate(CreateAccessPointPrivateRequest request, byte[] advertiseData)
|
||||
{
|
||||
_timeout.DisableTimeout();
|
||||
_apConnected.Reset();
|
||||
|
||||
ConfigureAccessPoint(ref request.RyuNetworkConfig);
|
||||
|
||||
|
|
@ -600,6 +602,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
|||
public NetworkError Connect(ConnectRequest request)
|
||||
{
|
||||
_timeout.DisableTimeout();
|
||||
_apConnected.Reset();
|
||||
|
||||
if (!EnsureConnected())
|
||||
{
|
||||
|
|
@ -622,6 +625,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu
|
|||
public NetworkError ConnectPrivate(ConnectPrivateRequest request)
|
||||
{
|
||||
_timeout.DisableTimeout();
|
||||
_apConnected.Reset();
|
||||
|
||||
if (!EnsureConnected())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
private readonly uint _subnetMask;
|
||||
private readonly uint _localIp;
|
||||
private readonly uint _broadcast;
|
||||
private bool _tcpWarningLogged;
|
||||
|
||||
public LdnProxy(ProxyConfig config, IProxyClient client, RyuLdnProtocol protocol)
|
||||
{
|
||||
|
|
@ -43,9 +44,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
public bool Supported(AddressFamily domain, SocketType type, ProtocolType protocol)
|
||||
{
|
||||
if (protocol == ProtocolType.Tcp)
|
||||
if (protocol == ProtocolType.Tcp && !_tcpWarningLogged)
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.ServiceLdn, "Tcp proxy networking is untested. Please report this game so that it can be tested.");
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceLdn, "LDN proxy TCP networking is experimental.");
|
||||
_tcpWarningLogged = true;
|
||||
}
|
||||
|
||||
return domain == AddressFamily.InterNetwork && (protocol == ProtocolType.Tcp || protocol == ProtocolType.Udp);
|
||||
|
|
@ -115,53 +117,168 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
}
|
||||
}
|
||||
|
||||
private void ForConnectionResponseSockets(ProxyInfo info, Action<LdnProxySocket> action)
|
||||
{
|
||||
lock (_sockets)
|
||||
{
|
||||
foreach (LdnProxySocket socket in _sockets)
|
||||
{
|
||||
if (socket.ProtocolType != info.Protocol ||
|
||||
socket.LocalEndPoint is not IPEndPoint localEndpoint ||
|
||||
localEndpoint.Port != info.DestPort ||
|
||||
socket.RemoteEndPoint is not IPEndPoint remoteEndpoint ||
|
||||
remoteEndpoint.Port != info.SourcePort)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
action(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ForDataSockets(ProxyInfo info, Action<LdnProxySocket> action)
|
||||
{
|
||||
lock (_sockets)
|
||||
{
|
||||
foreach (LdnProxySocket socket in _sockets)
|
||||
{
|
||||
if (socket.ProtocolType != info.Protocol ||
|
||||
socket.LocalEndPoint is not IPEndPoint localEndpoint ||
|
||||
localEndpoint.Port != info.DestPort ||
|
||||
!EndpointMatches(localEndpoint, info.DestIpV4))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info.Protocol == ProtocolType.Tcp &&
|
||||
(!socket.Connected ||
|
||||
socket.RemoteEndPoint is not IPEndPoint remoteEndpoint ||
|
||||
remoteEndpoint.Port != info.SourcePort ||
|
||||
!EndpointMatches(remoteEndpoint, info.SourceIpV4)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
action(socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleConnectionRequest(LdnHeader header, ProxyConnectRequest request)
|
||||
{
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy connect received: {FormatInfo(request.Info)}");
|
||||
|
||||
bool routed = false;
|
||||
|
||||
ForRoutedSockets(request.Info, (socket) =>
|
||||
{
|
||||
routed = true;
|
||||
socket.HandleConnectRequest(request);
|
||||
});
|
||||
|
||||
if (!routed)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceLdn, $"ProxyConnect had no listening socket: {FormatInfo(request.Info)}");
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleConnectionResponse(LdnHeader header, ProxyConnectResponse response)
|
||||
{
|
||||
ForRoutedSockets(response.Info, (socket) =>
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy connect reply received: {FormatInfo(response.Info)}");
|
||||
|
||||
bool routed = false;
|
||||
|
||||
ForConnectionResponseSockets(response.Info, (socket) =>
|
||||
{
|
||||
routed = true;
|
||||
socket.HandleConnectResponse(response);
|
||||
});
|
||||
|
||||
if (!routed)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceLdn, $"ProxyConnectReply had no connecting socket: {FormatInfo(response.Info)}");
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleData(LdnHeader header, ProxyDataHeader proxyHeader, byte[] data)
|
||||
{
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy data received: {data.Length} bytes, {FormatInfo(proxyHeader.Info)}");
|
||||
|
||||
ProxyDataPacket packet = new() { Header = proxyHeader, Data = data };
|
||||
|
||||
ForRoutedSockets(proxyHeader.Info, (socket) =>
|
||||
bool routed = false;
|
||||
|
||||
ForDataSockets(proxyHeader.Info, (socket) =>
|
||||
{
|
||||
routed = true;
|
||||
socket.IncomingData(packet);
|
||||
});
|
||||
|
||||
if (!routed)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceLdn, $"ProxyData had no receiving socket: {FormatInfo(proxyHeader.Info)}");
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleDisconnect(LdnHeader header, ProxyDisconnectMessage disconnect)
|
||||
{
|
||||
ForRoutedSockets(disconnect.Info, (socket) =>
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy disconnect received: {FormatInfo(disconnect.Info)}");
|
||||
|
||||
bool routed = false;
|
||||
|
||||
ForDataSockets(disconnect.Info, (socket) =>
|
||||
{
|
||||
routed = true;
|
||||
socket.HandleDisconnect(disconnect);
|
||||
});
|
||||
|
||||
if (!routed)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceLdn, $"ProxyDisconnect had no connected socket: {FormatInfo(disconnect.Info)}");
|
||||
}
|
||||
}
|
||||
|
||||
private uint GetIpV4(IPEndPoint endpoint)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(endpoint);
|
||||
|
||||
if (endpoint.AddressFamily != AddressFamily.InterNetwork)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
if (endpoint.Address.Equals(IPAddress.Any))
|
||||
{
|
||||
return _localIp;
|
||||
}
|
||||
|
||||
byte[] address = endpoint.Address.GetAddressBytes();
|
||||
Array.Reverse(address);
|
||||
|
||||
return BitConverter.ToUInt32(address);
|
||||
}
|
||||
|
||||
private bool EndpointMatches(IPEndPoint endpoint, uint ipv4)
|
||||
{
|
||||
return endpoint.Address.Equals(IPAddress.Any) ||
|
||||
endpoint.Address.Equals(IPAddress.IPv6Any) ||
|
||||
GetIpV4(endpoint) == ipv4;
|
||||
}
|
||||
|
||||
private static string FormatInfo(ProxyInfo info)
|
||||
{
|
||||
return $"{FormatIp(info.SourceIpV4)}:{info.SourcePort} -> {FormatIp(info.DestIpV4)}:{info.DestPort} ({info.Protocol})";
|
||||
}
|
||||
|
||||
private static string FormatIp(uint ipv4)
|
||||
{
|
||||
byte[] address = BitConverter.GetBytes(ipv4);
|
||||
Array.Reverse(address);
|
||||
|
||||
return new IPAddress(address).ToString();
|
||||
}
|
||||
|
||||
private ProxyInfo MakeInfo(IPEndPoint localEp, IPEndPoint remoteEP, ProtocolType type)
|
||||
{
|
||||
return new ProxyInfo
|
||||
|
|
@ -185,6 +302,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
Info = MakeInfo(localEp, remoteEp, type)
|
||||
};
|
||||
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy connect sent: {FormatInfo(request.Info)}");
|
||||
|
||||
_parent.SendAsync(_protocol.Encode(PacketId.ProxyConnect, request));
|
||||
}
|
||||
|
||||
|
|
@ -197,6 +316,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
Info = MakeInfo(localEp, remoteEp, type)
|
||||
};
|
||||
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy connect reply sent: {FormatInfo(request.Info)}");
|
||||
|
||||
_parent.SendAsync(_protocol.Encode(PacketId.ProxyConnectReply, request));
|
||||
}
|
||||
|
||||
|
|
@ -210,6 +331,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
DisconnectReason = 0 // TODO
|
||||
};
|
||||
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy disconnect sent: {FormatInfo(request.Info)}");
|
||||
|
||||
_parent.SendAsync(_protocol.Encode(PacketId.ProxyDisconnect, request));
|
||||
}
|
||||
|
||||
|
|
@ -224,6 +347,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
DataLength = (uint)buffer.Length
|
||||
};
|
||||
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy data sent: {buffer.Length} bytes, {FormatInfo(request.Info)}");
|
||||
|
||||
_parent.SendAsync(_protocol.Encode(PacketId.ProxyData, request, buffer.ToArray()));
|
||||
|
||||
return buffer.Length;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
|
||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
|
@ -41,6 +42,12 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
private bool _readShutdown;
|
||||
// private bool _writeShutdown;
|
||||
private bool _closed;
|
||||
private long _bytesReceived;
|
||||
private long _bytesSent;
|
||||
private int _receiveWouldBlockCount;
|
||||
private bool _closeSummaryLogged;
|
||||
private string _sentPreview;
|
||||
private string _receivedPreview;
|
||||
|
||||
private readonly Dictionary<SocketOptionName, int> _socketOptions = new()
|
||||
{
|
||||
|
|
@ -118,7 +125,16 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
}
|
||||
}
|
||||
public bool Writable => Connected || ProtocolType == ProtocolType.Udp;
|
||||
public bool Error => false;
|
||||
public bool Error
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_errors)
|
||||
{
|
||||
return _errors.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LdnProxySocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, LdnProxy proxy)
|
||||
{
|
||||
|
|
@ -152,13 +168,12 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
return localEp;
|
||||
}
|
||||
|
||||
public LdnProxySocket AsAccepted(IPEndPoint remoteEp)
|
||||
public LdnProxySocket AsAccepted(IPEndPoint localEp, IPEndPoint remoteEp)
|
||||
{
|
||||
Connected = true;
|
||||
LocalEndPoint = localEp;
|
||||
RemoteEndPoint = remoteEp;
|
||||
|
||||
IPEndPoint localEp = EnsureLocalEndpoint(true);
|
||||
|
||||
_proxy.SignalConnected(localEp, remoteEp, ProtocolType);
|
||||
|
||||
return this;
|
||||
|
|
@ -190,6 +205,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
{
|
||||
_receiveQueue.Enqueue(packet);
|
||||
}
|
||||
|
||||
_bytesReceived += packet.Data.Length;
|
||||
_receivedPreview ??= FormatPayloadPreview(packet.Data);
|
||||
|
||||
_receiveEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -200,6 +220,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy socket accept waiting on {LocalEndPoint}");
|
||||
|
||||
// Accept a pending request to this socket.
|
||||
|
||||
lock (_connectRequests)
|
||||
|
|
@ -228,12 +250,15 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
// Is this request made for us?
|
||||
IPEndPoint endpoint = GetEndpoint(request.Info.DestIpV4, request.Info.DestPort);
|
||||
|
||||
if (Equals(endpoint, LocalEndPoint))
|
||||
if (MatchesLocalEndpoint(endpoint))
|
||||
{
|
||||
// Yes - let's accept.
|
||||
IPEndPoint remoteEndpoint = GetEndpoint(request.Info.SourceIpV4, request.Info.SourcePort);
|
||||
|
||||
LdnProxySocket socket = new LdnProxySocket(AddressFamily, SocketType, ProtocolType, _proxy).AsAccepted(remoteEndpoint);
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy socket accepted {remoteEndpoint} on {LocalEndPoint}");
|
||||
|
||||
LdnProxySocket socket = new LdnProxySocket(AddressFamily, SocketType, ProtocolType, _proxy)
|
||||
.AsAccepted((IPEndPoint)LocalEndPoint, remoteEndpoint);
|
||||
|
||||
lock (_listenSockets)
|
||||
{
|
||||
|
|
@ -247,6 +272,18 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
}
|
||||
}
|
||||
|
||||
private bool MatchesLocalEndpoint(IPEndPoint endpoint)
|
||||
{
|
||||
if (LocalEndPoint is not IPEndPoint localEndpoint || endpoint.Port != localEndpoint.Port)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return localEndpoint.Address.Equals(IPAddress.Any) ||
|
||||
localEndpoint.Address.Equals(IPAddress.IPv6Any) ||
|
||||
endpoint.Address.Equals(localEndpoint.Address);
|
||||
}
|
||||
|
||||
public void Bind(EndPoint localEP)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(localEP);
|
||||
|
|
@ -269,6 +306,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
public void Close()
|
||||
{
|
||||
LogCloseSummary("close");
|
||||
|
||||
_closed = true;
|
||||
|
||||
_proxy.UnregisterSocket(this);
|
||||
|
|
@ -291,7 +330,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
public void Connect(EndPoint remoteEP)
|
||||
{
|
||||
if (_isListening || !IsBound)
|
||||
if (_isListening)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
|
@ -303,6 +342,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
IPEndPoint localEp = EnsureLocalEndpoint(true);
|
||||
|
||||
RemoteEndPoint = (IPEndPoint)remoteEP;
|
||||
_connecting = true;
|
||||
|
||||
_proxy.RequestConnection(localEp, (IPEndPoint)remoteEP, ProtocolType);
|
||||
|
|
@ -331,29 +371,44 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
_connecting = false;
|
||||
|
||||
if (_connectResponse.Info.SourceIpV4 != 0)
|
||||
_connectResponse = obj;
|
||||
|
||||
if (obj.Info.SourceIpV4 != 0)
|
||||
{
|
||||
IPEndPoint remoteEp = GetEndpoint(obj.Info.SourceIpV4, obj.Info.SourcePort);
|
||||
RemoteEndPoint = remoteEp;
|
||||
|
||||
Connected = true;
|
||||
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy socket connected to {RemoteEndPoint} from {LocalEndPoint}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connection failed
|
||||
|
||||
SignalError(WsaError.WSAECONNREFUSED);
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy socket connection refused from {LocalEndPoint}");
|
||||
}
|
||||
|
||||
_connectEvent.Set();
|
||||
}
|
||||
|
||||
public void Disconnect(bool reuseSocket)
|
||||
{
|
||||
if (Connected)
|
||||
{
|
||||
IPEndPoint localEndpoint = LocalEndPoint as IPEndPoint;
|
||||
IPEndPoint remoteEndpoint = RemoteEndPoint as IPEndPoint;
|
||||
|
||||
LogCloseSummary("local disconnect");
|
||||
|
||||
ConnectionEnded();
|
||||
|
||||
// The other side needs to be notified that connection ended.
|
||||
_proxy.EndConnection(LocalEndPoint as IPEndPoint, RemoteEndPoint as IPEndPoint, ProtocolType);
|
||||
if (localEndpoint != null && remoteEndpoint != null)
|
||||
{
|
||||
_proxy.EndConnection(localEndpoint, remoteEndpoint, ProtocolType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -375,6 +430,14 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
if (_socketOptions.TryGetValue(optionName, out int result))
|
||||
{
|
||||
if (optionName == SocketOptionName.Error)
|
||||
{
|
||||
lock (_errors)
|
||||
{
|
||||
result = _errors.Count > 0 ? _errors.Dequeue() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] data = BitConverter.GetBytes(result);
|
||||
Array.Copy(data, 0, optionValue, 0, Math.Min(data.Length, optionValue.Length));
|
||||
}
|
||||
|
|
@ -401,12 +464,22 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
_connectRequests.Enqueue(obj);
|
||||
}
|
||||
|
||||
_connectEvent.Set();
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy socket queued connect request on {LocalEndPoint}");
|
||||
|
||||
_acceptEvent.Set();
|
||||
}
|
||||
|
||||
public void HandleDisconnect(ProxyDisconnectMessage message)
|
||||
{
|
||||
Disconnect(false);
|
||||
_readShutdown = true;
|
||||
|
||||
Logger.Debug?.PrintMsg(LogClass.ServiceLdn, $"LDN proxy socket disconnected by peer on {LocalEndPoint}");
|
||||
LogCloseSummary("peer disconnect");
|
||||
ConnectionEnded();
|
||||
|
||||
_receiveEvent.Set();
|
||||
_acceptEvent.Set();
|
||||
_connectEvent.Set();
|
||||
}
|
||||
|
||||
public int Receive(Span<byte> buffer)
|
||||
|
|
@ -477,7 +550,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new SocketException((int)WsaError.WSAETIMEDOUT);
|
||||
_receiveWouldBlockCount++;
|
||||
throw new SocketException((int)WsaError.WSAEWOULDBLOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -532,7 +606,8 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
}
|
||||
else
|
||||
{
|
||||
socketError = SocketError.TimedOut;
|
||||
_receiveWouldBlockCount++;
|
||||
socketError = SocketError.WouldBlock;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -700,7 +775,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
return _proxy.SendTo(buffer, flags, localEp, (IPEndPoint)remoteEP, ProtocolType);
|
||||
int sent = _proxy.SendTo(buffer, flags, localEp, (IPEndPoint)remoteEP, ProtocolType);
|
||||
_bytesSent += sent;
|
||||
_sentPreview ??= FormatPayloadPreview(buffer);
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
public int SendTo(ReadOnlySpan<byte> buffer, SocketFlags flags, out SocketError socketError, EndPoint remoteEP)
|
||||
|
|
@ -722,7 +801,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
socketError = SocketError.Success;
|
||||
|
||||
return _proxy.SendTo(buffer, flags, localEp, (IPEndPoint)remoteEP, ProtocolType);
|
||||
int sent = _proxy.SendTo(buffer, flags, localEp, (IPEndPoint)remoteEP, ProtocolType);
|
||||
_bytesSent += sent;
|
||||
_sentPreview ??= FormatPayloadPreview(buffer);
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
public bool Poll(int microSeconds, SelectMode mode)
|
||||
|
|
@ -774,9 +857,11 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
case SocketShutdown.Both:
|
||||
_readShutdown = true;
|
||||
// _writeShutdown = true;
|
||||
_receiveEvent.Set();
|
||||
break;
|
||||
case SocketShutdown.Receive:
|
||||
_readShutdown = true;
|
||||
_receiveEvent.Set();
|
||||
break;
|
||||
case SocketShutdown.Send:
|
||||
// _writeShutdown = true;
|
||||
|
|
@ -786,12 +871,41 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||
|
||||
public void ProxyDestroyed()
|
||||
{
|
||||
// Do nothing, for now. Will likely be more useful with TCP.
|
||||
_closed = true;
|
||||
_readShutdown = true;
|
||||
ConnectionEnded();
|
||||
|
||||
_receiveEvent.Set();
|
||||
_acceptEvent.Set();
|
||||
_connectEvent.Set();
|
||||
}
|
||||
|
||||
private void LogCloseSummary(string reason)
|
||||
{
|
||||
if (_closeSummaryLogged || (_bytesReceived == 0 && _bytesSent == 0 && _receiveWouldBlockCount == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_closeSummaryLogged = true;
|
||||
|
||||
Logger.Info?.PrintMsg(
|
||||
LogClass.ServiceLdn,
|
||||
$"LDN proxy socket closed ({reason}): local={LocalEndPoint}, remote={RemoteEndPoint}, sent={_bytesSent} bytes, received={_bytesReceived} bytes, receiveWouldBlock={_receiveWouldBlockCount}, sentPreview={_sentPreview ?? "none"}, receivedPreview={_receivedPreview ?? "none"}");
|
||||
}
|
||||
|
||||
private static string FormatPayloadPreview(ReadOnlySpan<byte> data)
|
||||
{
|
||||
const int PreviewLength = 32;
|
||||
|
||||
ReadOnlySpan<byte> preview = data[..Math.Min(data.Length, PreviewLength)];
|
||||
|
||||
return Convert.ToHexString(preview);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
LogCloseSummary("dispose");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||
using System;
|
||||
|
|
@ -34,7 +35,11 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
|||
{
|
||||
SourceFlag flag = (SourceFlag)context.RequestData.ReadInt32();
|
||||
|
||||
context.ResponseData.Write(GetCount(flag));
|
||||
uint count = GetCount(flag);
|
||||
|
||||
context.ResponseData.Write(count);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceMii, $"GetCount: flag={flag}, count={count}");
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
@ -57,6 +62,8 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
|||
|
||||
WriteSpanToBuffer(context, outputBuffer, elementsSpan);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceMii, $"Get: flag={flag}, count={count}, result={result}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -78,6 +85,8 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
|||
|
||||
WriteSpanToBuffer(context, outputBuffer, elementsSpan);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceMii, $"Get1: flag={flag}, count={count}, result={result}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +150,8 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
|||
|
||||
WriteSpanToBuffer(context, outputBuffer, elementsSpan);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceMii, $"Get2: flag={flag}, count={count}, result={result}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -162,6 +173,8 @@ namespace Ryujinx.HLE.HOS.Services.Mii.StaticService
|
|||
|
||||
WriteSpanToBuffer(context, outputBuffer, elementsSpan);
|
||||
|
||||
Logger.NetLog?.PrintMsg(LogClass.ServiceMii, $"Get3: flag={flag}, count={count}, result={result}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,6 +172,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
|||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket connection failed: {exception.Message}");
|
||||
|
||||
return LinuxError.EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
|
|
@ -449,6 +455,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
|||
|
||||
Socket.SetSocketOption(level, SocketOptionName.Linger, new LingerOption(value != 0, value2));
|
||||
}
|
||||
else if (level == SocketOptionLevel.Socket && (option == BsdSocketOption.SoRcvTimeo || option == BsdSocketOption.SoSndTimeo))
|
||||
{
|
||||
Socket.SetSocketOption(level, optionName, ConvertTimeValToMilliseconds(optionValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
Socket.SetSocketOption(level, optionName, value);
|
||||
|
|
@ -467,6 +477,36 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
|||
}
|
||||
}
|
||||
|
||||
private static int ConvertTimeValToMilliseconds(ReadOnlySpan<byte> optionValue)
|
||||
{
|
||||
long seconds;
|
||||
long microseconds;
|
||||
|
||||
if (optionValue.Length >= 16)
|
||||
{
|
||||
seconds = MemoryMarshal.Read<long>(optionValue);
|
||||
microseconds = MemoryMarshal.Read<long>(optionValue[8..]);
|
||||
}
|
||||
else if (optionValue.Length >= 8)
|
||||
{
|
||||
seconds = MemoryMarshal.Read<int>(optionValue);
|
||||
microseconds = MemoryMarshal.Read<int>(optionValue[4..]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue);
|
||||
}
|
||||
|
||||
if (seconds <= 0 && microseconds <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
long milliseconds = (seconds * 1000) + ((microseconds + 999) / 1000);
|
||||
|
||||
return (int)Math.Clamp(milliseconds, 1, int.MaxValue);
|
||||
}
|
||||
|
||||
public LinuxError Read(out int readSize, Span<byte> buffer)
|
||||
{
|
||||
return Receive(out readSize, buffer, BsdSocketFlags.None);
|
||||
|
|
|
|||
Loading…
Reference in a new issue