Fix GetAddrInfoWithOptions and some sockets issues (#2936)

* Fix GetAddrInfoWithOptions and some sockets issues

* Was not supposed to remove this log
This commit is contained in:
gdkchan 2021-12-26 11:17:13 -03:00 committed by GitHub
parent c0056546e7
commit 0b1185284c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 237 additions and 108 deletions

View file

@ -8,6 +8,13 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
{
class IRequest : IpcService
{
private enum RequestState
{
Error = 1,
OnHold = 2,
Available = 3
}
private KEvent _event0;
private KEvent _event1;
@ -28,7 +35,11 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
// GetRequestState() -> u32
public ResultCode GetRequestState(ServiceCtx context)
{
context.ResponseData.Write(1);
RequestState requestState = context.Device.Configuration.EnableInternetAccess
? RequestState.Available
: RequestState.Error;
context.ResponseData.Write((int)requestState);
Logger.Stub?.PrintStub(LogClass.ServiceNifm);

View file

@ -106,7 +106,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
_isPrivileged = isPrivileged;
}
private LinuxError ConvertError(WsaError errorCode)
private static LinuxError ConvertError(WsaError errorCode)
{
if (!_errorMap.TryGetValue(errorCode, out LinuxError errno))
{
@ -116,6 +116,56 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return errno;
}
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))
{
socketFlags |= SocketFlags.OutOfBand;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Peek))
{
socketFlags |= SocketFlags.Peek;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.DontRoute))
{
socketFlags |= SocketFlags.DontRoute;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.Trunc))
{
socketFlags |= SocketFlags.Truncated;
}
if (bsdSocketFlags.HasFlag(BsdSocketFlags.CTrunc))
{
socketFlags |= SocketFlags.ControlDataTruncated;
}
bsdSocketFlags &= ~(BsdSocketFlags.Oob |
BsdSocketFlags.Peek |
BsdSocketFlags.DontRoute |
BsdSocketFlags.Trunc |
BsdSocketFlags.CTrunc);
if (bsdSocketFlags != BsdSocketFlags.None)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported socket flags: {bsdSocketFlags}");
}
return socketFlags;
}
private ResultCode WriteWinSock2Error(ServiceCtx context, WsaError errorCode)
{
return WriteBsdResult(context, -1, ConvertError(errorCode));
@ -463,8 +513,8 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
// Recv(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, array<i8, 0x22> message)
public ResultCode Recv(ServiceCtx context)
{
int socketFd = context.RequestData.ReadInt32();
SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
int socketFd = context.RequestData.ReadInt32();
BsdSocketFlags socketFlags = (BsdSocketFlags)context.RequestData.ReadInt32();
(ulong receivePosition, ulong receiveLength) = context.Request.GetBufferType0x22();
@ -474,18 +524,11 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
if (socket != null)
{
if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0
&& (socketFlags & SocketFlags.Peek) == 0)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}");
return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
}
byte[] receivedBuffer = new byte[receiveLength];
try
{
result = socket.Handle.Receive(receivedBuffer, socketFlags);
result = socket.Handle.Receive(receivedBuffer, ConvertBsdSocketFlags(socketFlags));
errno = SetResultErrno(socket.Handle, result);
context.Memory.Write(receivePosition, receivedBuffer);
@ -503,8 +546,8 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
// RecvFrom(u32 sock, u32 flags) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<i8, 0x22, 0> message, buffer<nn::socket::sockaddr_in, 0x22, 0x10>)
public ResultCode RecvFrom(ServiceCtx context)
{
int socketFd = context.RequestData.ReadInt32();
SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
int socketFd = context.RequestData.ReadInt32();
BsdSocketFlags socketFlags = (BsdSocketFlags)context.RequestData.ReadInt32();
(ulong receivePosition, ulong receiveLength) = context.Request.GetBufferType0x22();
(ulong sockAddrOutPosition, ulong sockAddrOutSize) = context.Request.GetBufferType0x22(1);
@ -515,20 +558,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
if (socket != null)
{
if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0
&& (socketFlags & SocketFlags.Peek) == 0)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}");
return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
}
byte[] receivedBuffer = new byte[receiveLength];
EndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
try
{
result = socket.Handle.ReceiveFrom(receivedBuffer, receivedBuffer.Length, socketFlags, ref endPoint);
result = socket.Handle.ReceiveFrom(receivedBuffer, receivedBuffer.Length, ConvertBsdSocketFlags(socketFlags), ref endPoint);
errno = SetResultErrno(socket.Handle, result);
context.Memory.Write(receivePosition, receivedBuffer);
@ -547,8 +582,8 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
// Send(u32 socket, u32 flags, buffer<i8, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
public ResultCode Send(ServiceCtx context)
{
int socketFd = context.RequestData.ReadInt32();
SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
int socketFd = context.RequestData.ReadInt32();
BsdSocketFlags socketFlags = (BsdSocketFlags)context.RequestData.ReadInt32();
(ulong sendPosition, ulong sendSize) = context.Request.GetBufferType0x21();
@ -558,21 +593,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
if (socket != null)
{
if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand
&& socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}");
return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
}
byte[] sendBuffer = new byte[sendSize];
context.Memory.Read(sendPosition, sendBuffer);
try
{
result = socket.Handle.Send(sendBuffer, socketFlags);
result = socket.Handle.Send(sendBuffer, ConvertBsdSocketFlags(socketFlags));
errno = SetResultErrno(socket.Handle, result);
}
catch (SocketException exception)
@ -589,8 +616,8 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
// SendTo(u32 socket, u32 flags, buffer<i8, 0x21, 0>, buffer<nn::socket::sockaddr_in, 0x21, 0x10>) -> (i32 ret, u32 bsd_errno)
public ResultCode SendTo(ServiceCtx context)
{
int socketFd = context.RequestData.ReadInt32();
SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
int socketFd = context.RequestData.ReadInt32();
BsdSocketFlags socketFlags = (BsdSocketFlags)context.RequestData.ReadInt32();
(ulong sendPosition, ulong sendSize) = context.Request.GetBufferType0x21();
(ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x21(1);
@ -601,14 +628,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
if (socket != null)
{
if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand
&& socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute)
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}");
return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
}
byte[] sendBuffer = new byte[sendSize];
context.Memory.Read(sendPosition, sendBuffer);
@ -617,7 +636,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
try
{
result = socket.Handle.SendTo(sendBuffer, sendBuffer.Length, socketFlags, endPoint);
result = socket.Handle.SendTo(sendBuffer, sendBuffer.Length, ConvertBsdSocketFlags(socketFlags), endPoint);
errno = SetResultErrno(socket.Handle, result);
}
catch (SocketException exception)
@ -737,7 +756,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
}
catch (SocketException exception)
{
errno = ConvertError((WsaError)exception.ErrorCode);
if (!socket.Handle.Blocking && exception.ErrorCode == (int)WsaError.WSAEWOULDBLOCK)
{
errno = LinuxError.EINPROGRESS;
}
else
{
errno = ConvertError((WsaError)exception.ErrorCode);
}
}
}
@ -794,9 +820,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();
int level = context.RequestData.ReadInt32();
int optionName = context.RequestData.ReadInt32();
int socketFd = context.RequestData.ReadInt32();
SocketOptionLevel level = (SocketOptionLevel)context.RequestData.ReadInt32();
SocketOptionName optionName = (SocketOptionName)context.RequestData.ReadInt32();
(ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x22();
@ -805,16 +831,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
if (socket != null)
{
errno = LinuxError.ENOPROTOOPT;
if (level == 0xFFFF)
{
errno = HandleGetSocketOption(context, socket, (SocketOptionName)optionName, bufferPosition, bufferSize);
}
else
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Level: {(SocketOptionLevel)level}");
}
errno = HandleGetSocketOption(context, socket, optionName, level, bufferPosition, bufferSize);
}
return WriteBsdResult(context, 0, errno);
@ -916,7 +933,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
return WriteBsdResult(context, result, errno);
}
private LinuxError HandleGetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, ulong optionValuePosition, ulong optionValueSize)
private static LinuxError HandleGetSocketOption(
ServiceCtx context,
BsdSocket socket,
SocketOptionName optionName,
SocketOptionLevel level,
ulong optionValuePosition,
ulong optionValueSize)
{
try
{
@ -936,19 +959,19 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
case SocketOptionName.SendTimeout:
case SocketOptionName.Type:
case SocketOptionName.Linger:
socket.Handle.GetSocketOption(SocketOptionLevel.Socket, optionName, optionValue);
socket.Handle.GetSocketOption(level, optionName, optionValue);
context.Memory.Write(optionValuePosition, optionValue);
return LinuxError.SUCCESS;
case (SocketOptionName)0x200:
socket.Handle.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue);
socket.Handle.GetSocketOption(level, SocketOptionName.ReuseAddress, optionValue);
context.Memory.Write(optionValuePosition, optionValue);
return LinuxError.SUCCESS;
default:
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}");
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt OptionName: {optionName}");
return LinuxError.EOPNOTSUPP;
}
@ -959,7 +982,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
}
}
private LinuxError HandleSetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, ulong optionValuePosition, ulong optionValueSize)
private static LinuxError HandleSetSocketOption(
ServiceCtx context,
BsdSocket socket,
SocketOptionName optionName,
SocketOptionLevel level,
ulong optionValuePosition,
ulong optionValueSize)
{
try
{
@ -977,17 +1006,17 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
case SocketOptionName.SendTimeout:
case SocketOptionName.Type:
case SocketOptionName.ReuseAddress:
socket.Handle.SetSocketOption(SocketOptionLevel.Socket, optionName, context.Memory.Read<int>((ulong)optionValuePosition));
socket.Handle.SetSocketOption(level, optionName, context.Memory.Read<int>((ulong)optionValuePosition));
return LinuxError.SUCCESS;
case (SocketOptionName)0x200:
socket.Handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, context.Memory.Read<int>((ulong)optionValuePosition));
socket.Handle.SetSocketOption(level, SocketOptionName.ReuseAddress, context.Memory.Read<int>((ulong)optionValuePosition));
return LinuxError.SUCCESS;
case SocketOptionName.Linger:
socket.Handle.SetSocketOption(SocketOptionLevel.Socket, 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;
@ -1008,9 +1037,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();
int level = context.RequestData.ReadInt32();
int optionName = context.RequestData.ReadInt32();
int socketFd = context.RequestData.ReadInt32();
SocketOptionLevel level = (SocketOptionLevel)context.RequestData.ReadInt32();
SocketOptionName optionName = (SocketOptionName)context.RequestData.ReadInt32();
(ulong bufferPos, ulong bufferSize) = context.Request.GetBufferType0x21();
@ -1019,16 +1048,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
if (socket != null)
{
errno = LinuxError.ENOPROTOOPT;
if (level == 0xFFFF)
{
errno = HandleSetSocketOption(context, socket, (SocketOptionName)optionName, bufferPos, bufferSize);
}
else
{
Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Level: {(SocketOptionLevel)level}");
}
errno = HandleSetSocketOption(context, socket, optionName, level, bufferPos, bufferSize);
}
return WriteBsdResult(context, 0, errno);

View file

@ -0,0 +1,24 @@
using System.Net.Sockets;
namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
{
enum BsdSocketFlags
{
None = 0,
Oob = 0x1,
Peek = 0x2,
DontRoute = 0x4,
Eor = 0x8,
Trunc = 0x10,
CTrunc = 0x20,
WaitAll = 0x40,
DontWait = 0x80,
Eof = 0x100,
Notification = 0x2000,
Nbio = 0x4000,
Compat = 0x8000,
SoCallbck = 0x10000,
NoSignal = 0x20000,
CMsgCloExec = 0x40000
}
}

View file

@ -155,7 +155,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
ulong responseBufferPosition = context.Request.ReceiveBuff[0].Position;
ulong responseBufferSize = context.Request.ReceiveBuff[0].Size;
return GetAddrInfoRequestImpl(context, responseBufferPosition, responseBufferSize, 0, 0);
return GetAddrInfoRequestImpl(context, responseBufferPosition, responseBufferSize, false, 0, 0);
}
[CommandHipc(8)]
@ -213,7 +213,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
(ulong responseBufferPosition, ulong responseBufferSize) = context.Request.GetBufferType0x22();
(ulong optionsBufferPosition, ulong optionsBufferSize) = context.Request.GetBufferType0x21();
return GetAddrInfoRequestImpl(context, responseBufferPosition, responseBufferSize, optionsBufferPosition, optionsBufferSize);
return GetAddrInfoRequestImpl(context, responseBufferPosition, responseBufferSize, true, optionsBufferPosition, optionsBufferSize);
}
private ResultCode GetHostByNameRequestImpl(ServiceCtx context, ulong inputBufferPosition, ulong inputBufferSize, ulong outputBufferPosition, ulong outputBufferSize, ulong optionsBufferPosition, ulong optionsBufferSize)
@ -391,7 +391,13 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
return bufferPosition - originalBufferPosition;
}
private ResultCode GetAddrInfoRequestImpl(ServiceCtx context, ulong responseBufferPosition, ulong responseBufferSize, ulong optionsBufferPosition, ulong optionsBufferSize)
private ResultCode GetAddrInfoRequestImpl(
ServiceCtx context,
ulong responseBufferPosition,
ulong responseBufferSize,
bool withOptions,
ulong optionsBufferPosition,
ulong optionsBufferSize)
{
bool enableNsdResolve = (context.RequestData.ReadInt32() & 1) != 0;
uint cancelHandle = context.RequestData.ReadUInt32();
@ -402,7 +408,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
// NOTE: We ignore hints for now.
DeserializeAddrInfos(context.Memory, (ulong)context.Request.SendBuff[2].Position, (ulong)context.Request.SendBuff[2].Size);
if (optionsBufferSize > 0)
if (withOptions)
{
// TODO: Find unknown, Parse and use options.
uint unknown = context.RequestData.ReadUInt32();
@ -457,9 +463,19 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
serializedSize = SerializeAddrInfos(context, responseBufferPosition, responseBufferSize, hostEntry, port);
}
context.ResponseData.Write((int)netDbErrorCode);
context.ResponseData.Write((int)errno);
context.ResponseData.Write(serializedSize);
if (withOptions)
{
context.ResponseData.Write(serializedSize);
context.ResponseData.Write((int)errno);
context.ResponseData.Write((int)netDbErrorCode);
context.ResponseData.Write(0);
}
else
{
context.ResponseData.Write((int)netDbErrorCode);
context.ResponseData.Write((int)errno);
context.ResponseData.Write(serializedSize);
}
return ResultCode.Success;
}

View file

@ -21,9 +21,9 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres.Types
Port = port;
Address = default;
address.GetAddressBytes().AsSpan().CopyTo(Address.ToSpan());
Address.ToSpan().Reverse();
Span<byte> outAddress = Address.ToSpan();
address.TryWriteBytes(outAddress, out _);
outAddress.Reverse();
}
}
}