Improve SocketOption handling (#2946)
This commit is contained in:
parent
322c14ee31
commit
8544b1445b
3 changed files with 221 additions and 80 deletions
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
[Service("bsd:u", false)]
|
||||
class IClient : IpcService
|
||||
{
|
||||
private static Dictionary<WsaError, LinuxError> _errorMap = new Dictionary<WsaError, LinuxError>
|
||||
private static readonly Dictionary<WsaError, LinuxError> _errorMap = new()
|
||||
{
|
||||
// WSAEINTR
|
||||
{WsaError.WSAEINTR, LinuxError.EINTR},
|
||||
|
@ -97,6 +97,50 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
{0, 0}
|
||||
};
|
||||
|
||||
private static readonly Dictionary<BsdSocketOption, SocketOptionName> _soSocketOptionMap = new()
|
||||
{
|
||||
{ BsdSocketOption.SoDebug, SocketOptionName.Debug },
|
||||
{ BsdSocketOption.SoReuseAddr, SocketOptionName.ReuseAddress },
|
||||
{ BsdSocketOption.SoKeepAlive, SocketOptionName.KeepAlive },
|
||||
{ BsdSocketOption.SoDontRoute, SocketOptionName.DontRoute },
|
||||
{ BsdSocketOption.SoBroadcast, SocketOptionName.Broadcast },
|
||||
{ BsdSocketOption.SoUseLoopBack, SocketOptionName.UseLoopback },
|
||||
{ BsdSocketOption.SoLinger, SocketOptionName.Linger },
|
||||
{ BsdSocketOption.SoOobInline, SocketOptionName.OutOfBandInline },
|
||||
{ BsdSocketOption.SoReusePort, SocketOptionName.ReuseAddress },
|
||||
{ BsdSocketOption.SoSndBuf, SocketOptionName.SendBuffer },
|
||||
{ BsdSocketOption.SoRcvBuf, SocketOptionName.ReceiveBuffer },
|
||||
{ BsdSocketOption.SoSndLoWat, SocketOptionName.SendLowWater },
|
||||
{ BsdSocketOption.SoRcvLoWat, SocketOptionName.ReceiveLowWater },
|
||||
{ BsdSocketOption.SoSndTimeo, SocketOptionName.SendTimeout },
|
||||
{ BsdSocketOption.SoRcvTimeo, SocketOptionName.ReceiveTimeout },
|
||||
{ BsdSocketOption.SoError, SocketOptionName.Error },
|
||||
{ BsdSocketOption.SoType, SocketOptionName.Type }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<BsdSocketOption, SocketOptionName> _ipSocketOptionMap = new()
|
||||
{
|
||||
{ BsdSocketOption.IpOptions, SocketOptionName.IPOptions },
|
||||
{ BsdSocketOption.IpHdrIncl, SocketOptionName.HeaderIncluded },
|
||||
{ BsdSocketOption.IpTtl, SocketOptionName.IpTimeToLive },
|
||||
{ BsdSocketOption.IpMulticastIf, SocketOptionName.MulticastInterface },
|
||||
{ BsdSocketOption.IpMulticastTtl, SocketOptionName.MulticastTimeToLive },
|
||||
{ BsdSocketOption.IpMulticastLoop, SocketOptionName.MulticastLoopback },
|
||||
{ BsdSocketOption.IpAddMembership, SocketOptionName.AddMembership },
|
||||
{ BsdSocketOption.IpDropMembership, SocketOptionName.DropMembership },
|
||||
{ BsdSocketOption.IpDontFrag, SocketOptionName.DontFragment },
|
||||
{ BsdSocketOption.IpAddSourceMembership, SocketOptionName.AddSourceMembership },
|
||||
{ BsdSocketOption.IpDropSourceMembership, SocketOptionName.DropSourceMembership }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<BsdSocketOption, SocketOptionName> _tcpSocketOptionMap = new()
|
||||
{
|
||||
{ BsdSocketOption.TcpNoDelay, SocketOptionName.NoDelay },
|
||||
{ BsdSocketOption.TcpKeepIdle, SocketOptionName.TcpKeepAliveTime },
|
||||
{ BsdSocketOption.TcpKeepIntvl, SocketOptionName.TcpKeepAliveInterval },
|
||||
{ BsdSocketOption.TcpKeepCnt, SocketOptionName.TcpKeepAliveRetryCount }
|
||||
};
|
||||
|
||||
private bool _isPrivileged;
|
||||
|
||||
private List<BsdSocket> _sockets = new List<BsdSocket>();
|
||||
|
@ -118,13 +162,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
|
||||
private static SocketFlags ConvertBsdSocketFlags(BsdSocketFlags bsdSocketFlags)
|
||||
{
|
||||
BsdSocketFlags SupportedFlags =
|
||||
BsdSocketFlags.Oob |
|
||||
BsdSocketFlags.Peek |
|
||||
BsdSocketFlags.DontRoute |
|
||||
BsdSocketFlags.Trunc |
|
||||
BsdSocketFlags.CTrunc;
|
||||
|
||||
SocketFlags socketFlags = SocketFlags.None;
|
||||
|
||||
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Oob))
|
||||
|
@ -166,6 +203,25 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
return socketFlags;
|
||||
}
|
||||
|
||||
private static bool TryConvertSocketOption(BsdSocketOption option, SocketOptionLevel level, out SocketOptionName name)
|
||||
{
|
||||
var table = level switch
|
||||
{
|
||||
SocketOptionLevel.Socket => _soSocketOptionMap,
|
||||
SocketOptionLevel.IP => _ipSocketOptionMap,
|
||||
SocketOptionLevel.Tcp => _tcpSocketOptionMap,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (table == null)
|
||||
{
|
||||
name = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
return table.TryGetValue(option, out name);
|
||||
}
|
||||
|
||||
private ResultCode WriteWinSock2Error(ServiceCtx context, WsaError errorCode)
|
||||
{
|
||||
return WriteBsdResult(context, -1, ConvertError(errorCode));
|
||||
|
@ -820,9 +876,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
// GetSockOpt(u32 socket, u32 level, u32 option_name) -> (i32 ret, u32 bsd_errno, u32, buffer<unknown, 0x22, 0>)
|
||||
public ResultCode GetSockOpt(ServiceCtx context)
|
||||
{
|
||||
int socketFd = context.RequestData.ReadInt32();
|
||||
SocketOptionLevel level = (SocketOptionLevel)context.RequestData.ReadInt32();
|
||||
SocketOptionName optionName = (SocketOptionName)context.RequestData.ReadInt32();
|
||||
int socketFd = context.RequestData.ReadInt32();
|
||||
SocketOptionLevel level = (SocketOptionLevel)context.RequestData.ReadInt32();
|
||||
BsdSocketOption option = (BsdSocketOption)context.RequestData.ReadInt32();
|
||||
|
||||
(ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x22();
|
||||
|
||||
|
@ -831,7 +887,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
|
||||
if (socket != null)
|
||||
{
|
||||
errno = HandleGetSocketOption(context, socket, optionName, level, bufferPosition, bufferSize);
|
||||
errno = HandleGetSocketOption(context, socket, option, level, bufferPosition, bufferSize);
|
||||
}
|
||||
|
||||
return WriteBsdResult(context, 0, errno);
|
||||
|
@ -936,45 +992,26 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
private static LinuxError HandleGetSocketOption(
|
||||
ServiceCtx context,
|
||||
BsdSocket socket,
|
||||
SocketOptionName optionName,
|
||||
BsdSocketOption option,
|
||||
SocketOptionLevel level,
|
||||
ulong optionValuePosition,
|
||||
ulong optionValueSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!TryConvertSocketOption(option, level, out SocketOptionName optionName))
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}");
|
||||
|
||||
return LinuxError.EOPNOTSUPP;
|
||||
}
|
||||
|
||||
byte[] optionValue = new byte[optionValueSize];
|
||||
|
||||
switch (optionName)
|
||||
{
|
||||
case SocketOptionName.Broadcast:
|
||||
case SocketOptionName.DontLinger:
|
||||
case SocketOptionName.Debug:
|
||||
case SocketOptionName.Error:
|
||||
case SocketOptionName.KeepAlive:
|
||||
case SocketOptionName.OutOfBandInline:
|
||||
case SocketOptionName.ReceiveBuffer:
|
||||
case SocketOptionName.ReceiveTimeout:
|
||||
case SocketOptionName.SendBuffer:
|
||||
case SocketOptionName.SendTimeout:
|
||||
case SocketOptionName.Type:
|
||||
case SocketOptionName.Linger:
|
||||
socket.Handle.GetSocketOption(level, optionName, optionValue);
|
||||
context.Memory.Write(optionValuePosition, optionValue);
|
||||
socket.Handle.GetSocketOption(level, optionName, optionValue);
|
||||
context.Memory.Write(optionValuePosition, optionValue);
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
|
||||
case (SocketOptionName)0x200:
|
||||
socket.Handle.GetSocketOption(level, SocketOptionName.ReuseAddress, optionValue);
|
||||
context.Memory.Write(optionValuePosition, optionValue);
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
|
||||
default:
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt OptionName: {optionName}");
|
||||
|
||||
return LinuxError.EOPNOTSUPP;
|
||||
}
|
||||
return LinuxError.SUCCESS;
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
|
@ -985,47 +1022,34 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
private static LinuxError HandleSetSocketOption(
|
||||
ServiceCtx context,
|
||||
BsdSocket socket,
|
||||
SocketOptionName optionName,
|
||||
BsdSocketOption option,
|
||||
SocketOptionLevel level,
|
||||
ulong optionValuePosition,
|
||||
ulong optionValueSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (optionName)
|
||||
if (!TryConvertSocketOption(option, level, out SocketOptionName optionName))
|
||||
{
|
||||
case SocketOptionName.Broadcast:
|
||||
case SocketOptionName.DontLinger:
|
||||
case SocketOptionName.Debug:
|
||||
case SocketOptionName.Error:
|
||||
case SocketOptionName.KeepAlive:
|
||||
case SocketOptionName.OutOfBandInline:
|
||||
case SocketOptionName.ReceiveBuffer:
|
||||
case SocketOptionName.ReceiveTimeout:
|
||||
case SocketOptionName.SendBuffer:
|
||||
case SocketOptionName.SendTimeout:
|
||||
case SocketOptionName.Type:
|
||||
case SocketOptionName.ReuseAddress:
|
||||
socket.Handle.SetSocketOption(level, optionName, context.Memory.Read<int>((ulong)optionValuePosition));
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}");
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
|
||||
case (SocketOptionName)0x200:
|
||||
socket.Handle.SetSocketOption(level, SocketOptionName.ReuseAddress, context.Memory.Read<int>((ulong)optionValuePosition));
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
|
||||
case SocketOptionName.Linger:
|
||||
socket.Handle.SetSocketOption(level, SocketOptionName.Linger,
|
||||
new LingerOption(context.Memory.Read<int>((ulong)optionValuePosition) != 0, context.Memory.Read<int>((ulong)optionValuePosition + 4)));
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
|
||||
default:
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}");
|
||||
|
||||
return LinuxError.EOPNOTSUPP;
|
||||
return LinuxError.EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int value = context.Memory.Read<int>((ulong)optionValuePosition);
|
||||
|
||||
if (option == BsdSocketOption.SoLinger)
|
||||
{
|
||||
int value2 = context.Memory.Read<int>((ulong)optionValuePosition + 4);
|
||||
|
||||
socket.Handle.SetSocketOption(level, SocketOptionName.Linger, new LingerOption(value != 0, value2));
|
||||
}
|
||||
else
|
||||
{
|
||||
socket.Handle.SetSocketOption(level, optionName, value);
|
||||
}
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
|
@ -1037,9 +1061,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
// SetSockOpt(u32 socket, u32 level, u32 option_name, buffer<unknown, 0x21, 0> option_value) -> (i32 ret, u32 bsd_errno)
|
||||
public ResultCode SetSockOpt(ServiceCtx context)
|
||||
{
|
||||
int socketFd = context.RequestData.ReadInt32();
|
||||
SocketOptionLevel level = (SocketOptionLevel)context.RequestData.ReadInt32();
|
||||
SocketOptionName optionName = (SocketOptionName)context.RequestData.ReadInt32();
|
||||
int socketFd = context.RequestData.ReadInt32();
|
||||
SocketOptionLevel level = (SocketOptionLevel)context.RequestData.ReadInt32();
|
||||
BsdSocketOption option = (BsdSocketOption)context.RequestData.ReadInt32();
|
||||
|
||||
(ulong bufferPos, ulong bufferSize) = context.Request.GetBufferType0x21();
|
||||
|
||||
|
@ -1048,7 +1072,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
|||
|
||||
if (socket != null)
|
||||
{
|
||||
errno = HandleSetSocketOption(context, socket, optionName, level, bufferPos, bufferSize);
|
||||
errno = HandleSetSocketOption(context, socket, option, level, bufferPos, bufferSize);
|
||||
}
|
||||
|
||||
return WriteBsdResult(context, 0, errno);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
using System.Net.Sockets;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
{
|
||||
enum BsdSocketFlags
|
||||
|
|
119
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketOption.cs
Normal file
119
Ryujinx.HLE/HOS/Services/Sockets/Bsd/Types/BsdSocketOption.cs
Normal file
|
@ -0,0 +1,119 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
{
|
||||
enum BsdSocketOption
|
||||
{
|
||||
SoDebug = 0x1,
|
||||
SoAcceptConn = 0x2,
|
||||
SoReuseAddr = 0x4,
|
||||
SoKeepAlive = 0x8,
|
||||
SoDontRoute = 0x10,
|
||||
SoBroadcast = 0x20,
|
||||
SoUseLoopBack = 0x40,
|
||||
SoLinger = 0x80,
|
||||
SoOobInline = 0x100,
|
||||
SoReusePort = 0x200,
|
||||
SoTimestamp = 0x400,
|
||||
SoNoSigpipe = 0x800,
|
||||
SoAcceptFilter = 0x1000,
|
||||
SoBinTime = 0x2000,
|
||||
SoNoOffload = 0x4000,
|
||||
SoNoDdp = 0x8000,
|
||||
SoReusePortLb = 0x10000,
|
||||
SoRError = 0x20000,
|
||||
|
||||
SoSndBuf = 0x1001,
|
||||
SoRcvBuf = 0x1002,
|
||||
SoSndLoWat = 0x1003,
|
||||
SoRcvLoWat = 0x1004,
|
||||
SoSndTimeo = 0x1005,
|
||||
SoRcvTimeo = 0x1006,
|
||||
SoError = 0x1007,
|
||||
SoType = 0x1008,
|
||||
SoLabel = 0x1009,
|
||||
SoPeerLabel = 0x1010,
|
||||
SoListenQLimit = 0x1011,
|
||||
SoListenQLen = 0x1012,
|
||||
SoListenIncQLen = 0x1013,
|
||||
SoSetFib = 0x1014,
|
||||
SoUserCookie = 0x1015,
|
||||
SoProtocol = 0x1016,
|
||||
SoTsClock = 0x1017,
|
||||
SoMaxPacingRate = 0x1018,
|
||||
SoDomain = 0x1019,
|
||||
|
||||
IpOptions = 1,
|
||||
IpHdrIncl = 2,
|
||||
IpTos = 3,
|
||||
IpTtl = 4,
|
||||
IpRecvOpts = 5,
|
||||
IpRecvRetOpts = 6,
|
||||
IpRecvDstAddr = 7,
|
||||
IpRetOpts = 8,
|
||||
IpMulticastIf = 9,
|
||||
IpMulticastTtl = 10,
|
||||
IpMulticastLoop = 11,
|
||||
IpAddMembership = 12,
|
||||
IpDropMembership = 13,
|
||||
IpMulticastVif = 14,
|
||||
IpRsvpOn = 15,
|
||||
IpRsvpOff = 16,
|
||||
IpRsvpVifOn = 17,
|
||||
IpRsvpVifOff = 18,
|
||||
IpPortRange = 19,
|
||||
IpRecvIf = 20,
|
||||
IpIpsecPolicy = 21,
|
||||
IpOnesBcast = 23,
|
||||
IpBindany = 24,
|
||||
IpBindMulti = 25,
|
||||
IpRssListenBucket = 26,
|
||||
IpOrigDstAddr = 27,
|
||||
|
||||
IpFwTableAdd = 40,
|
||||
IpFwTableDel = 41,
|
||||
IpFwTableFlush = 42,
|
||||
IpFwTableGetSize = 43,
|
||||
IpFwTableList = 44,
|
||||
|
||||
IpFw3 = 48,
|
||||
IpDummyNet3 = 49,
|
||||
|
||||
IpFwAdd = 50,
|
||||
IpFwDel = 51,
|
||||
IpFwFlush = 52,
|
||||
IpFwZero = 53,
|
||||
IpFwGet = 54,
|
||||
IpFwResetLog = 55,
|
||||
|
||||
IpFwNatCfg = 56,
|
||||
IpFwNatDel = 57,
|
||||
IpFwNatGetConfig = 58,
|
||||
IpFwNatGetLog = 59,
|
||||
|
||||
IpDummyNetConfigure = 60,
|
||||
IpDummyNetDel = 61,
|
||||
IpDummyNetFlush = 62,
|
||||
IpDummyNetGet = 64,
|
||||
|
||||
IpRecvTtl = 65,
|
||||
IpMinTtl = 66,
|
||||
IpDontFrag = 67,
|
||||
IpRecvTos = 68,
|
||||
|
||||
IpAddSourceMembership = 70,
|
||||
IpDropSourceMembership = 71,
|
||||
IpBlockSource = 72,
|
||||
IpUnblockSource = 73,
|
||||
|
||||
TcpNoDelay = 1,
|
||||
TcpMaxSeg = 2,
|
||||
TcpNoPush = 4,
|
||||
TcpNoOpt = 8,
|
||||
TcpMd5Sig = 16,
|
||||
TcpInfo = 32,
|
||||
TcpCongestion = 64,
|
||||
TcpKeepInit = 128,
|
||||
TcpKeepIdle = 256,
|
||||
TcpKeepIntvl = 512,
|
||||
TcpKeepCnt = 1024
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue