TESTERS WANTED: RyuLDN implementation (#65)
These changes allow players to matchmake for local wireless using a LDN server. The network implementation originates from Berry's public TCP RyuLDN fork. Logo and unrelated changes have been removed. Additionally displays LDN game status in the game selection window when RyuLDN is enabled. Functionality is only enabled while network mode is set to "RyuLDN" in the settings.
This commit is contained in:
@@ -95,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
}
|
||||
}
|
||||
|
||||
ISocket newBsdSocket = new ManagedSocket(netDomain, (SocketType)type, protocol)
|
||||
ISocket newBsdSocket = new ManagedSocket(netDomain, (SocketType)type, protocol, context.Device.Configuration.MultiplayerLanInterfaceId)
|
||||
{
|
||||
Blocking = !creationFlags.HasFlag(BsdSocketCreationFlags.NonBlocking),
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy;
|
||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -21,21 +22,21 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
public bool Blocking { get => Socket.Blocking; set => Socket.Blocking = value; }
|
||||
|
||||
public nint Handle => Socket.Handle;
|
||||
public nint Handle => IntPtr.Zero;
|
||||
|
||||
public IPEndPoint RemoteEndPoint => Socket.RemoteEndPoint as IPEndPoint;
|
||||
|
||||
public IPEndPoint LocalEndPoint => Socket.LocalEndPoint as IPEndPoint;
|
||||
|
||||
public Socket Socket { get; }
|
||||
public ISocketImpl Socket { get; }
|
||||
|
||||
public ManagedSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
|
||||
public ManagedSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, string lanInterfaceId)
|
||||
{
|
||||
Socket = new Socket(addressFamily, socketType, protocolType);
|
||||
Socket = SocketHelpers.CreateSocket(addressFamily, socketType, protocolType, lanInterfaceId);
|
||||
Refcount = 1;
|
||||
}
|
||||
|
||||
private ManagedSocket(Socket socket)
|
||||
private ManagedSocket(ISocketImpl socket)
|
||||
{
|
||||
Socket = socket;
|
||||
Refcount = 1;
|
||||
@@ -185,6 +186,8 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
}
|
||||
|
||||
bool hasEmittedBlockingWarning = false;
|
||||
|
||||
public LinuxError Receive(out int receiveSize, Span<byte> buffer, BsdSocketFlags flags)
|
||||
{
|
||||
LinuxError result;
|
||||
@@ -199,6 +202,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
shouldBlockAfterOperation = true;
|
||||
}
|
||||
|
||||
if (Blocking && !hasEmittedBlockingWarning)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceBsd, "Blocking socket operations are not yet working properly. Expect network errors.");
|
||||
hasEmittedBlockingWarning = true;
|
||||
}
|
||||
|
||||
receiveSize = Socket.Receive(buffer, ConvertBsdSocketFlags(flags));
|
||||
|
||||
result = LinuxError.SUCCESS;
|
||||
@@ -236,6 +245,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
shouldBlockAfterOperation = true;
|
||||
}
|
||||
|
||||
if (Blocking && !hasEmittedBlockingWarning)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceBsd, "Blocking socket operations are not yet working properly. Expect network errors.");
|
||||
hasEmittedBlockingWarning = true;
|
||||
}
|
||||
|
||||
if (!Socket.IsBound)
|
||||
{
|
||||
receiveSize = -1;
|
||||
@@ -313,7 +328,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}");
|
||||
optionValue.Clear();
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
return LinuxError.EOPNOTSUPP;
|
||||
}
|
||||
|
||||
byte[] tempOptionValue = new byte[optionValue.Length];
|
||||
@@ -347,7 +362,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}");
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
return LinuxError.EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int value = optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue);
|
||||
@@ -493,7 +508,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
try
|
||||
{
|
||||
int receiveSize = Socket.Receive(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError);
|
||||
int receiveSize = (Socket as DefaultSocket).BaseSocket.Receive(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError);
|
||||
|
||||
if (receiveSize > 0)
|
||||
{
|
||||
@@ -531,7 +546,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
try
|
||||
{
|
||||
int sendSize = Socket.Send(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError);
|
||||
int sendSize = (Socket as DefaultSocket).BaseSocket.Send(ConvertMessagesToBuffer(message), ConvertBsdSocketFlags(flags), out SocketError socketError);
|
||||
|
||||
if (sendSize > 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy;
|
||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
@@ -26,45 +27,46 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
public LinuxError Poll(List<PollEvent> events, int timeoutMilliseconds, out int updatedCount)
|
||||
{
|
||||
List<Socket> readEvents = new();
|
||||
List<Socket> writeEvents = new();
|
||||
List<Socket> errorEvents = new();
|
||||
List<ISocketImpl> readEvents = new();
|
||||
List<ISocketImpl> writeEvents = new();
|
||||
List<ISocketImpl> errorEvents = new();
|
||||
|
||||
updatedCount = 0;
|
||||
|
||||
foreach (PollEvent evnt in events)
|
||||
{
|
||||
ManagedSocket socket = (ManagedSocket)evnt.FileDescriptor;
|
||||
|
||||
bool isValidEvent = evnt.Data.InputEvents == 0;
|
||||
|
||||
errorEvents.Add(socket.Socket);
|
||||
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
|
||||
if (evnt.FileDescriptor is ManagedSocket ms)
|
||||
{
|
||||
readEvents.Add(socket.Socket);
|
||||
bool isValidEvent = evnt.Data.InputEvents == 0;
|
||||
|
||||
isValidEvent = true;
|
||||
}
|
||||
errorEvents.Add(ms.Socket);
|
||||
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.UrgentInput) != 0)
|
||||
{
|
||||
readEvents.Add(socket.Socket);
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
|
||||
{
|
||||
readEvents.Add(ms.Socket);
|
||||
|
||||
isValidEvent = true;
|
||||
}
|
||||
isValidEvent = true;
|
||||
}
|
||||
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Output) != 0)
|
||||
{
|
||||
writeEvents.Add(socket.Socket);
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.UrgentInput) != 0)
|
||||
{
|
||||
readEvents.Add(ms.Socket);
|
||||
|
||||
isValidEvent = true;
|
||||
}
|
||||
isValidEvent = true;
|
||||
}
|
||||
|
||||
if (!isValidEvent)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Poll input event type: {evnt.Data.InputEvents}");
|
||||
return LinuxError.EINVAL;
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Output) != 0)
|
||||
{
|
||||
writeEvents.Add(ms.Socket);
|
||||
|
||||
isValidEvent = true;
|
||||
}
|
||||
|
||||
if (!isValidEvent)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Poll input event type: {evnt.Data.InputEvents}");
|
||||
return LinuxError.EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
{
|
||||
int actualTimeoutMicroseconds = timeoutMilliseconds == -1 ? -1 : timeoutMilliseconds * 1000;
|
||||
|
||||
Socket.Select(readEvents, writeEvents, errorEvents, actualTimeoutMicroseconds);
|
||||
SocketHelpers.Select(readEvents, writeEvents, errorEvents, actualTimeoutMicroseconds);
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
@@ -81,34 +83,37 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
foreach (PollEvent evnt in events)
|
||||
{
|
||||
Socket socket = ((ManagedSocket)evnt.FileDescriptor).Socket;
|
||||
|
||||
PollEventTypeMask outputEvents = evnt.Data.OutputEvents & ~evnt.Data.InputEvents;
|
||||
|
||||
if (errorEvents.Contains(socket))
|
||||
if (evnt.FileDescriptor is ManagedSocket ms)
|
||||
{
|
||||
outputEvents |= PollEventTypeMask.Error;
|
||||
ISocketImpl socket = ms.Socket;
|
||||
|
||||
if (!socket.Connected || !socket.IsBound)
|
||||
PollEventTypeMask outputEvents = evnt.Data.OutputEvents & ~evnt.Data.InputEvents;
|
||||
|
||||
if (errorEvents.Contains(ms.Socket))
|
||||
{
|
||||
outputEvents |= PollEventTypeMask.Disconnected;
|
||||
}
|
||||
}
|
||||
outputEvents |= PollEventTypeMask.Error;
|
||||
|
||||
if (readEvents.Contains(socket))
|
||||
{
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
|
||||
if (!socket.Connected || !socket.IsBound)
|
||||
{
|
||||
outputEvents |= PollEventTypeMask.Disconnected;
|
||||
}
|
||||
}
|
||||
|
||||
if (readEvents.Contains(ms.Socket))
|
||||
{
|
||||
outputEvents |= PollEventTypeMask.Input;
|
||||
if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0)
|
||||
{
|
||||
outputEvents |= PollEventTypeMask.Input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writeEvents.Contains(socket))
|
||||
{
|
||||
outputEvents |= PollEventTypeMask.Output;
|
||||
}
|
||||
if (writeEvents.Contains(ms.Socket))
|
||||
{
|
||||
outputEvents |= PollEventTypeMask.Output;
|
||||
}
|
||||
|
||||
evnt.Data.OutputEvents = outputEvents;
|
||||
evnt.Data.OutputEvents = outputEvents;
|
||||
}
|
||||
}
|
||||
|
||||
updatedCount = readEvents.Count + writeEvents.Count + errorEvents.Count;
|
||||
@@ -118,53 +123,55 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount)
|
||||
{
|
||||
List<Socket> readEvents = new();
|
||||
List<Socket> writeEvents = new();
|
||||
List<Socket> errorEvents = new();
|
||||
List<ISocketImpl> readEvents = new();
|
||||
List<ISocketImpl> writeEvents = new();
|
||||
List<ISocketImpl> errorEvents = new();
|
||||
|
||||
updatedCount = 0;
|
||||
|
||||
foreach (PollEvent pollEvent in events)
|
||||
{
|
||||
ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor;
|
||||
|
||||
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
|
||||
if (pollEvent.FileDescriptor is ManagedSocket ms)
|
||||
{
|
||||
readEvents.Add(socket.Socket);
|
||||
}
|
||||
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Input))
|
||||
{
|
||||
readEvents.Add(ms.Socket);
|
||||
}
|
||||
|
||||
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
|
||||
{
|
||||
writeEvents.Add(socket.Socket);
|
||||
}
|
||||
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Output))
|
||||
{
|
||||
writeEvents.Add(ms.Socket);
|
||||
}
|
||||
|
||||
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Error))
|
||||
{
|
||||
errorEvents.Add(socket.Socket);
|
||||
if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Error))
|
||||
{
|
||||
errorEvents.Add(ms.Socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Socket.Select(readEvents, writeEvents, errorEvents, timeout);
|
||||
SocketHelpers.Select(readEvents, writeEvents, errorEvents, timeout);
|
||||
|
||||
updatedCount = readEvents.Count + writeEvents.Count + errorEvents.Count;
|
||||
|
||||
foreach (PollEvent pollEvent in events)
|
||||
{
|
||||
ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor;
|
||||
|
||||
if (readEvents.Contains(socket.Socket))
|
||||
if (pollEvent.FileDescriptor is ManagedSocket ms)
|
||||
{
|
||||
pollEvent.Data.OutputEvents |= PollEventTypeMask.Input;
|
||||
}
|
||||
if (readEvents.Contains(ms.Socket))
|
||||
{
|
||||
pollEvent.Data.OutputEvents |= PollEventTypeMask.Input;
|
||||
}
|
||||
|
||||
if (writeEvents.Contains(socket.Socket))
|
||||
{
|
||||
pollEvent.Data.OutputEvents |= PollEventTypeMask.Output;
|
||||
}
|
||||
if (writeEvents.Contains(ms.Socket))
|
||||
{
|
||||
pollEvent.Data.OutputEvents |= PollEventTypeMask.Output;
|
||||
}
|
||||
|
||||
if (errorEvents.Contains(socket.Socket))
|
||||
{
|
||||
pollEvent.Data.OutputEvents |= PollEventTypeMask.Error;
|
||||
if (errorEvents.Contains(ms.Socket))
|
||||
{
|
||||
pollEvent.Data.OutputEvents |= PollEventTypeMask.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
178
src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Proxy/DefaultSocket.cs
Normal file
178
src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Proxy/DefaultSocket.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy
|
||||
{
|
||||
class DefaultSocket : ISocketImpl
|
||||
{
|
||||
public Socket BaseSocket { get; }
|
||||
|
||||
public EndPoint RemoteEndPoint => BaseSocket.RemoteEndPoint;
|
||||
|
||||
public EndPoint LocalEndPoint => BaseSocket.LocalEndPoint;
|
||||
|
||||
public bool Connected => BaseSocket.Connected;
|
||||
|
||||
public bool IsBound => BaseSocket.IsBound;
|
||||
|
||||
public AddressFamily AddressFamily => BaseSocket.AddressFamily;
|
||||
|
||||
public SocketType SocketType => BaseSocket.SocketType;
|
||||
|
||||
public ProtocolType ProtocolType => BaseSocket.ProtocolType;
|
||||
|
||||
public bool Blocking { get => BaseSocket.Blocking; set => BaseSocket.Blocking = value; }
|
||||
|
||||
public int Available => BaseSocket.Available;
|
||||
|
||||
private readonly string _lanInterfaceId;
|
||||
|
||||
public DefaultSocket(Socket baseSocket, string lanInterfaceId)
|
||||
{
|
||||
_lanInterfaceId = lanInterfaceId;
|
||||
|
||||
BaseSocket = baseSocket;
|
||||
}
|
||||
|
||||
public DefaultSocket(AddressFamily domain, SocketType type, ProtocolType protocol, string lanInterfaceId)
|
||||
{
|
||||
_lanInterfaceId = lanInterfaceId;
|
||||
|
||||
BaseSocket = new Socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
private void EnsureNetworkInterfaceBound()
|
||||
{
|
||||
if (_lanInterfaceId != "0" && !BaseSocket.IsBound)
|
||||
{
|
||||
(_, UnicastIPAddressInformation ipInfo) = NetworkHelpers.GetLocalInterface(_lanInterfaceId);
|
||||
|
||||
BaseSocket.Bind(new IPEndPoint(ipInfo.Address, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public ISocketImpl Accept()
|
||||
{
|
||||
return new DefaultSocket(BaseSocket.Accept(), _lanInterfaceId);
|
||||
}
|
||||
|
||||
public void Bind(EndPoint localEP)
|
||||
{
|
||||
// NOTE: The guest is able to receive on 0.0.0.0 without it being limited to the chosen network interface.
|
||||
// This is because it must get loopback traffic as well. This could allow other network traffic to leak in.
|
||||
|
||||
BaseSocket.Bind(localEP);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
BaseSocket.Close();
|
||||
}
|
||||
|
||||
public void Connect(EndPoint remoteEP)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
BaseSocket.Connect(remoteEP);
|
||||
}
|
||||
|
||||
public void Disconnect(bool reuseSocket)
|
||||
{
|
||||
BaseSocket.Disconnect(reuseSocket);
|
||||
}
|
||||
|
||||
public void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue)
|
||||
{
|
||||
BaseSocket.GetSocketOption(optionLevel, optionName, optionValue);
|
||||
}
|
||||
|
||||
public void Listen(int backlog)
|
||||
{
|
||||
BaseSocket.Listen(backlog);
|
||||
}
|
||||
|
||||
public int Receive(Span<byte> buffer)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.Receive(buffer);
|
||||
}
|
||||
|
||||
public int Receive(Span<byte> buffer, SocketFlags flags)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.Receive(buffer, flags);
|
||||
}
|
||||
|
||||
public int Receive(Span<byte> buffer, SocketFlags flags, out SocketError socketError)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.Receive(buffer, flags, out socketError);
|
||||
}
|
||||
|
||||
public int ReceiveFrom(Span<byte> buffer, SocketFlags flags, ref EndPoint remoteEP)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.ReceiveFrom(buffer, flags, ref remoteEP);
|
||||
}
|
||||
|
||||
public int Send(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.Send(buffer);
|
||||
}
|
||||
|
||||
public int Send(ReadOnlySpan<byte> buffer, SocketFlags flags)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.Send(buffer, flags);
|
||||
}
|
||||
|
||||
public int Send(ReadOnlySpan<byte> buffer, SocketFlags flags, out SocketError socketError)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.Send(buffer, flags, out socketError);
|
||||
}
|
||||
|
||||
public int SendTo(ReadOnlySpan<byte> buffer, SocketFlags flags, EndPoint remoteEP)
|
||||
{
|
||||
EnsureNetworkInterfaceBound();
|
||||
|
||||
return BaseSocket.SendTo(buffer, flags, remoteEP);
|
||||
}
|
||||
|
||||
public bool Poll(int microSeconds, SelectMode mode)
|
||||
{
|
||||
return BaseSocket.Poll(microSeconds, mode);
|
||||
}
|
||||
|
||||
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
|
||||
{
|
||||
BaseSocket.SetSocketOption(optionLevel, optionName, optionValue);
|
||||
}
|
||||
|
||||
public void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
|
||||
{
|
||||
BaseSocket.SetSocketOption(optionLevel, optionName, optionValue);
|
||||
}
|
||||
|
||||
public void Shutdown(SocketShutdown how)
|
||||
{
|
||||
BaseSocket.Shutdown(how);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BaseSocket.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Proxy/ISocket.cs
Normal file
47
src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Proxy/ISocket.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy
|
||||
{
|
||||
interface ISocketImpl : IDisposable
|
||||
{
|
||||
EndPoint RemoteEndPoint { get; }
|
||||
EndPoint LocalEndPoint { get; }
|
||||
bool Connected { get; }
|
||||
bool IsBound { get; }
|
||||
|
||||
AddressFamily AddressFamily { get; }
|
||||
SocketType SocketType { get; }
|
||||
ProtocolType ProtocolType { get; }
|
||||
|
||||
bool Blocking { get; set; }
|
||||
int Available { get; }
|
||||
|
||||
int Receive(Span<byte> buffer);
|
||||
int Receive(Span<byte> buffer, SocketFlags flags);
|
||||
int Receive(Span<byte> buffer, SocketFlags flags, out SocketError socketError);
|
||||
int ReceiveFrom(Span<byte> buffer, SocketFlags flags, ref EndPoint remoteEP);
|
||||
|
||||
int Send(ReadOnlySpan<byte> buffer);
|
||||
int Send(ReadOnlySpan<byte> buffer, SocketFlags flags);
|
||||
int Send(ReadOnlySpan<byte> buffer, SocketFlags flags, out SocketError socketError);
|
||||
int SendTo(ReadOnlySpan<byte> buffer, SocketFlags flags, EndPoint remoteEP);
|
||||
|
||||
bool Poll(int microSeconds, SelectMode mode);
|
||||
|
||||
ISocketImpl Accept();
|
||||
|
||||
void Bind(EndPoint localEP);
|
||||
void Connect(EndPoint remoteEP);
|
||||
void Listen(int backlog);
|
||||
|
||||
void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue);
|
||||
void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue);
|
||||
void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue);
|
||||
|
||||
void Shutdown(SocketShutdown how);
|
||||
void Disconnect(bool reuseSocket);
|
||||
void Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy
|
||||
{
|
||||
static class SocketHelpers
|
||||
{
|
||||
private static LdnProxy _proxy;
|
||||
|
||||
public static void Select(List<ISocketImpl> readEvents, List<ISocketImpl> writeEvents, List<ISocketImpl> errorEvents, int timeout)
|
||||
{
|
||||
var readDefault = readEvents.Select(x => (x as DefaultSocket)?.BaseSocket).Where(x => x != null).ToList();
|
||||
var writeDefault = writeEvents.Select(x => (x as DefaultSocket)?.BaseSocket).Where(x => x != null).ToList();
|
||||
var errorDefault = errorEvents.Select(x => (x as DefaultSocket)?.BaseSocket).Where(x => x != null).ToList();
|
||||
|
||||
if (readDefault.Count != 0 || writeDefault.Count != 0 || errorDefault.Count != 0)
|
||||
{
|
||||
Socket.Select(readDefault, writeDefault, errorDefault, timeout);
|
||||
}
|
||||
|
||||
void FilterSockets(List<ISocketImpl> removeFrom, List<Socket> selectedSockets, Func<LdnProxySocket, bool> ldnCheck)
|
||||
{
|
||||
removeFrom.RemoveAll(socket =>
|
||||
{
|
||||
switch (socket)
|
||||
{
|
||||
case DefaultSocket dsocket:
|
||||
return !selectedSockets.Contains(dsocket.BaseSocket);
|
||||
case LdnProxySocket psocket:
|
||||
return !ldnCheck(psocket);
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
FilterSockets(readEvents, readDefault, (socket) => socket.Readable);
|
||||
FilterSockets(writeEvents, writeDefault, (socket) => socket.Writable);
|
||||
FilterSockets(errorEvents, errorDefault, (socket) => socket.Error);
|
||||
}
|
||||
|
||||
public static void RegisterProxy(LdnProxy proxy)
|
||||
{
|
||||
if (_proxy != null)
|
||||
{
|
||||
UnregisterProxy();
|
||||
}
|
||||
|
||||
_proxy = proxy;
|
||||
}
|
||||
|
||||
public static void UnregisterProxy()
|
||||
{
|
||||
_proxy?.Dispose();
|
||||
_proxy = null;
|
||||
}
|
||||
|
||||
public static ISocketImpl CreateSocket(AddressFamily domain, SocketType type, ProtocolType protocol, string lanInterfaceId)
|
||||
{
|
||||
if (_proxy != null)
|
||||
{
|
||||
if (_proxy.Supported(domain, type, protocol))
|
||||
{
|
||||
return new LdnProxySocket(domain, type, protocol, _proxy);
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultSocket(domain, type, protocol, lanInterfaceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +292,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
|
||||
{
|
||||
string host = MemoryHelper.ReadAsciiString(context.Memory, inputBufferPosition, (int)inputBufferSize);
|
||||
|
||||
if (!context.Device.Configuration.EnableInternetAccess)
|
||||
if (host != "localhost" && !context.Device.Configuration.EnableInternetAccess)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.ServiceSfdnsres, $"Guest network access disabled, DNS Blocked: {host}");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user