aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres
diff options
context:
space:
mode:
authorAc_K <Acoustik666@gmail.com>2019-09-19 02:45:11 +0200
committerjduncanator <1518948+jduncanator@users.noreply.github.com>2019-09-19 10:45:11 +1000
commita0720b5681852f3d786d77bd3793b0359dea321c (patch)
tree9d8f61e540d1d1d827999902dad95e5c0c1e076e /Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres
parent4af3101b22e6957d6aa48a2768566d658699f4ed (diff)
Refactoring HOS folder structure (#771)
* Refactoring HOS folder structure Refactoring HOS folder structure: - Added some subfolders when needed (Following structure decided in private). - Added some `Types` folders when needed. - Little cleanup here and there. - Add services placeholders for every HOS services (close #766 and #753). * Remove Types namespaces
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres')
-rw-r--r--Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs387
-rw-r--r--Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs22
-rw-r--r--Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs13
3 files changed, 422 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs
new file mode 100644
index 00000000..1cf2aa1c
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/IResolver.cs
@@ -0,0 +1,387 @@
+using Ryujinx.Common.Logging;
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
+{
+ [Service("sfdnsres")]
+ class IResolver : IpcService
+ {
+ public IResolver(ServiceCtx context) { }
+
+ private long SerializeHostEnt(ServiceCtx context, IPHostEntry hostEntry, List<IPAddress> addresses = null)
+ {
+ long originalBufferPosition = context.Request.ReceiveBuff[0].Position;
+ long bufferPosition = originalBufferPosition;
+ long bufferSize = context.Request.ReceiveBuff[0].Size;
+
+ string hostName = hostEntry.HostName + '\0';
+
+ // h_name
+ context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(hostName));
+ bufferPosition += hostName.Length;
+
+ // h_aliases list size
+ context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(hostEntry.Aliases.Length));
+ bufferPosition += 4;
+
+ // Actual aliases
+ foreach (string alias in hostEntry.Aliases)
+ {
+ context.Memory.WriteBytes(bufferPosition, Encoding.ASCII.GetBytes(alias + '\0'));
+ bufferPosition += alias.Length + 1;
+ }
+
+ // h_addrtype but it's a short (also only support IPv4)
+ context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)2));
+ bufferPosition += 2;
+
+ // h_length but it's a short
+ context.Memory.WriteInt16(bufferPosition, IPAddress.HostToNetworkOrder((short)4));
+ bufferPosition += 2;
+
+ // Ip address count, we can only support ipv4 (blame Nintendo)
+ context.Memory.WriteInt32(bufferPosition, addresses != null ? IPAddress.HostToNetworkOrder(addresses.Count) : 0);
+ bufferPosition += 4;
+
+ if (addresses != null)
+ {
+ foreach (IPAddress ip in addresses)
+ {
+ context.Memory.WriteInt32(bufferPosition, IPAddress.HostToNetworkOrder(BitConverter.ToInt32(ip.GetAddressBytes(), 0)));
+ bufferPosition += 4;
+ }
+ }
+
+ return bufferPosition - originalBufferPosition;
+ }
+
+ private string GetGaiStringErrorFromErrorCode(GaiError errorCode)
+ {
+ if (errorCode > GaiError.Max)
+ {
+ errorCode = GaiError.Max;
+ }
+
+ switch (errorCode)
+ {
+ case GaiError.AddressFamily:
+ return "Address family for hostname not supported";
+ case GaiError.Again:
+ return "Temporary failure in name resolution";
+ case GaiError.BadFlags:
+ return "Invalid value for ai_flags";
+ case GaiError.Fail:
+ return "Non-recoverable failure in name resolution";
+ case GaiError.Family:
+ return "ai_family not supported";
+ case GaiError.Memory:
+ return "Memory allocation failure";
+ case GaiError.NoData:
+ return "No address associated with hostname";
+ case GaiError.NoName:
+ return "hostname nor servname provided, or not known";
+ case GaiError.Service:
+ return "servname not supported for ai_socktype";
+ case GaiError.SocketType:
+ return "ai_socktype not supported";
+ case GaiError.System:
+ return "System error returned in errno";
+ case GaiError.BadHints:
+ return "Invalid value for hints";
+ case GaiError.Protocol:
+ return "Resolved protocol is unknown";
+ case GaiError.Overflow:
+ return "Argument buffer overflow";
+ case GaiError.Max:
+ return "Unknown error";
+ default:
+ return "Success";
+ }
+ }
+
+ private string GetHostStringErrorFromErrorCode(NetDbError errorCode)
+ {
+ if (errorCode <= NetDbError.Internal)
+ {
+ return "Resolver internal error";
+ }
+
+ switch (errorCode)
+ {
+ case NetDbError.Success:
+ return "Resolver Error 0 (no error)";
+ case NetDbError.HostNotFound:
+ return "Unknown host";
+ case NetDbError.TryAgain:
+ return "Host name lookup failure";
+ case NetDbError.NoRecovery:
+ return "Unknown server error";
+ case NetDbError.NoData:
+ return "No address associated with name";
+ default:
+ return "Unknown resolver error";
+ }
+ }
+
+ private List<IPAddress> GetIpv4Addresses(IPHostEntry hostEntry)
+ {
+ List<IPAddress> result = new List<IPAddress>();
+ foreach (IPAddress ip in hostEntry.AddressList)
+ {
+ if (ip.AddressFamily == AddressFamily.InterNetwork)
+ result.Add(ip);
+ }
+ return result;
+ }
+
+ [Command(0)]
+ // SetDnsAddressesPrivate(u32, buffer<unknown, 5, 0>)
+ public ResultCode SetDnsAddressesPrivate(ServiceCtx context)
+ {
+ uint unknown0 = context.RequestData.ReadUInt32();
+ long bufferPosition = context.Request.SendBuff[0].Position;
+ long bufferSize = context.Request.SendBuff[0].Size;
+
+ // TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness.
+ Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 });
+
+ return ResultCode.NotAllocated;
+ }
+
+ [Command(1)]
+ // GetDnsAddressPrivate(u32) -> buffer<unknown, 6, 0>
+ public ResultCode GetDnsAddressesPrivate(ServiceCtx context)
+ {
+ uint unknown0 = context.RequestData.ReadUInt32();
+
+ // TODO: This is stubbed in 2.0.0+, reverse 1.0.0 version for the sake completeness.
+ Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 });
+
+ return ResultCode.NotAllocated;
+ }
+
+ [Command(2)]
+ // GetHostByName(u8, u32, u64, pid, buffer<unknown, 5, 0>) -> (u32, u32, u32, buffer<unknown, 6, 0>)
+ public ResultCode GetHostByName(ServiceCtx context)
+ {
+ byte[] rawName = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size);
+ string name = Encoding.ASCII.GetString(rawName).TrimEnd('\0');
+
+ // TODO: use params
+ bool enableNsdResolve = context.RequestData.ReadInt32() == 1;
+ int timeOut = context.RequestData.ReadInt32();
+ ulong pidPlaceholder = context.RequestData.ReadUInt64();
+
+ IPHostEntry hostEntry = null;
+
+ NetDbError netDbErrorCode = NetDbError.Success;
+ GaiError errno = GaiError.Overflow;
+ long serializedSize = 0;
+
+ if (name.Length <= 255)
+ {
+ try
+ {
+ hostEntry = Dns.GetHostEntry(name);
+ }
+ catch (SocketException exception)
+ {
+ netDbErrorCode = NetDbError.Internal;
+
+ if (exception.ErrorCode == 11001)
+ {
+ netDbErrorCode = NetDbError.HostNotFound;
+ errno = GaiError.NoData;
+ }
+ else if (exception.ErrorCode == 11002)
+ {
+ netDbErrorCode = NetDbError.TryAgain;
+ }
+ else if (exception.ErrorCode == 11003)
+ {
+ netDbErrorCode = NetDbError.NoRecovery;
+ }
+ else if (exception.ErrorCode == 11004)
+ {
+ netDbErrorCode = NetDbError.NoData;
+ }
+ else if (exception.ErrorCode == 10060)
+ {
+ errno = GaiError.Again;
+ }
+ }
+ }
+ else
+ {
+ netDbErrorCode = NetDbError.HostNotFound;
+ }
+
+ if (hostEntry != null)
+ {
+ errno = GaiError.Success;
+
+ List<IPAddress> addresses = GetIpv4Addresses(hostEntry);
+
+ if (addresses.Count == 0)
+ {
+ errno = GaiError.NoData;
+ netDbErrorCode = NetDbError.NoAddress;
+ }
+ else
+ {
+ serializedSize = SerializeHostEnt(context, hostEntry, addresses);
+ }
+ }
+
+ context.ResponseData.Write((int)netDbErrorCode);
+ context.ResponseData.Write((int)errno);
+ context.ResponseData.Write(serializedSize);
+
+ return ResultCode.Success;
+ }
+
+ [Command(3)]
+ // GetHostByAddr(u32, u32, u32, u64, pid, buffer<unknown, 5, 0>) -> (u32, u32, u32, buffer<unknown, 6, 0>)
+ public ResultCode GetHostByAddress(ServiceCtx context)
+ {
+ byte[] rawIp = context.Memory.ReadBytes(context.Request.SendBuff[0].Position, context.Request.SendBuff[0].Size);
+
+ // TODO: use params
+ uint socketLength = context.RequestData.ReadUInt32();
+ uint type = context.RequestData.ReadUInt32();
+ int timeOut = context.RequestData.ReadInt32();
+ ulong pidPlaceholder = context.RequestData.ReadUInt64();
+
+ IPHostEntry hostEntry = null;
+
+ NetDbError netDbErrorCode = NetDbError.Success;
+ GaiError errno = GaiError.AddressFamily;
+ long serializedSize = 0;
+
+ if (rawIp.Length == 4)
+ {
+ try
+ {
+ IPAddress address = new IPAddress(rawIp);
+
+ hostEntry = Dns.GetHostEntry(address);
+ }
+ catch (SocketException exception)
+ {
+ netDbErrorCode = NetDbError.Internal;
+ if (exception.ErrorCode == 11001)
+ {
+ netDbErrorCode = NetDbError.HostNotFound;
+ errno = GaiError.NoData;
+ }
+ else if (exception.ErrorCode == 11002)
+ {
+ netDbErrorCode = NetDbError.TryAgain;
+ }
+ else if (exception.ErrorCode == 11003)
+ {
+ netDbErrorCode = NetDbError.NoRecovery;
+ }
+ else if (exception.ErrorCode == 11004)
+ {
+ netDbErrorCode = NetDbError.NoData;
+ }
+ else if (exception.ErrorCode == 10060)
+ {
+ errno = GaiError.Again;
+ }
+ }
+ }
+ else
+ {
+ netDbErrorCode = NetDbError.NoAddress;
+ }
+
+ if (hostEntry != null)
+ {
+ errno = GaiError.Success;
+ serializedSize = SerializeHostEnt(context, hostEntry, GetIpv4Addresses(hostEntry));
+ }
+
+ context.ResponseData.Write((int)netDbErrorCode);
+ context.ResponseData.Write((int)errno);
+ context.ResponseData.Write(serializedSize);
+
+ return ResultCode.Success;
+ }
+
+ [Command(4)]
+ // GetHostStringError(u32) -> buffer<unknown, 6, 0>
+ public ResultCode GetHostStringError(ServiceCtx context)
+ {
+ ResultCode resultCode = ResultCode.NotAllocated;
+ NetDbError errorCode = (NetDbError)context.RequestData.ReadInt32();
+ string errorString = GetHostStringErrorFromErrorCode(errorCode);
+
+ if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size)
+ {
+ resultCode = 0;
+ context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0'));
+ }
+
+ return resultCode;
+ }
+
+ [Command(5)]
+ // GetGaiStringError(u32) -> buffer<unknown, 6, 0>
+ public ResultCode GetGaiStringError(ServiceCtx context)
+ {
+ ResultCode resultCode = ResultCode.NotAllocated;
+ GaiError errorCode = (GaiError)context.RequestData.ReadInt32();
+ string errorString = GetGaiStringErrorFromErrorCode(errorCode);
+
+ if (errorString.Length + 1 <= context.Request.ReceiveBuff[0].Size)
+ {
+ resultCode = 0;
+ context.Memory.WriteBytes(context.Request.ReceiveBuff[0].Position, Encoding.ASCII.GetBytes(errorString + '\0'));
+ }
+
+ return resultCode;
+ }
+
+ [Command(8)]
+ // RequestCancelHandle(u64, pid) -> u32
+ public ResultCode RequestCancelHandle(ServiceCtx context)
+ {
+ ulong unknown0 = context.RequestData.ReadUInt64();
+
+ context.ResponseData.Write(0);
+
+ Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 });
+
+ return ResultCode.Success;
+ }
+
+ [Command(9)]
+ // CancelSocketCall(u32, u64, pid)
+ public ResultCode CancelSocketCall(ServiceCtx context)
+ {
+ uint unknown0 = context.RequestData.ReadUInt32();
+ ulong unknown1 = context.RequestData.ReadUInt64();
+
+ Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0, unknown1 });
+
+ return ResultCode.Success;
+ }
+
+ [Command(11)]
+ // ClearDnsAddresses(u32)
+ public ResultCode ClearDnsAddresses(ServiceCtx context)
+ {
+ uint unknown0 = context.RequestData.ReadUInt32();
+
+ Logger.PrintStub(LogClass.ServiceSfdnsres, new { unknown0 });
+
+ return ResultCode.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs
new file mode 100644
index 00000000..f9f28b44
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/GaiError.cs
@@ -0,0 +1,22 @@
+namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
+{
+ enum GaiError
+ {
+ Success,
+ AddressFamily,
+ Again,
+ BadFlags,
+ Fail,
+ Family,
+ Memory,
+ NoData,
+ NoName,
+ Service,
+ SocketType,
+ System,
+ BadHints,
+ Protocol,
+ Overflow,
+ Max
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs
new file mode 100644
index 00000000..3c04c049
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Sockets/Sfdnsres/Types/NetDBError.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.HLE.HOS.Services.Sockets.Sfdnsres
+{
+ enum NetDbError
+ {
+ Internal = -1,
+ Success,
+ HostNotFound,
+ TryAgain,
+ NoRecovery,
+ NoData,
+ NoAddress = NoData
+ }
+} \ No newline at end of file