aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.HLE/HOS/Services/Sockets/Nsd
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Services/Sockets/Nsd')
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs402
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs97
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs19
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/ApplicationServerEnvironmentType.cs11
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs9
5 files changed, 538 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs
new file mode 100644
index 00000000..0b7adff4
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs
@@ -0,0 +1,402 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Cpu;
+using Ryujinx.HLE.Exceptions;
+using Ryujinx.HLE.HOS.Services.Settings;
+using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager;
+using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Types;
+using System;
+using System.Text;
+
+namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
+{
+ [Service("nsd:a")] // Max sessions: 5
+ [Service("nsd:u")] // Max sessions: 20
+ class IManager : IpcService
+ {
+ public static readonly NsdSettings NsdSettings;
+ private readonly FqdnResolver _fqdnResolver;
+
+ private bool _isInitialized = false;
+
+ public IManager(ServiceCtx context)
+ {
+ _fqdnResolver = new FqdnResolver();
+
+ _isInitialized = true;
+ }
+
+ static IManager()
+ {
+ // TODO: Load nsd settings through the savedata 0x80000000000000B0 (nsdsave:/).
+
+ if (!NxSettings.Settings.TryGetValue("nsd!test_mode", out object testMode))
+ {
+ // return ResultCode.InvalidSettingsValue;
+ }
+
+ if (!NxSettings.Settings.TryGetValue("nsd!environment_identifier", out object environmentIdentifier))
+ {
+ // return ResultCode.InvalidSettingsValue;
+ }
+
+ NsdSettings = new NsdSettings
+ {
+ Initialized = true,
+ TestMode = (bool)testMode,
+ Environment = (string)environmentIdentifier
+ };
+ }
+
+ [CommandCmif(5)] // 11.0.0+
+ // GetSettingUrl() -> buffer<unknown<0x100>, 0x16>
+ public ResultCode GetSettingUrl(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(10)]
+ // GetSettingName() -> buffer<unknown<0x100>, 0x16>
+ public ResultCode GetSettingName(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(11)]
+ // GetEnvironmentIdentifier() -> buffer<bytes<8> environment_identifier, 0x16>
+ public ResultCode GetEnvironmentIdentifier(ServiceCtx context)
+ {
+ (ulong outputPosition, ulong outputSize) = context.Request.GetBufferType0x22();
+
+ MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
+
+ ResultCode result = _fqdnResolver.GetEnvironmentIdentifier(out string identifier);
+
+ if (result == ResultCode.Success)
+ {
+ byte[] identifierBuffer = Encoding.UTF8.GetBytes(identifier);
+
+ context.Memory.Write(outputPosition, identifierBuffer);
+ }
+
+ return result;
+ }
+
+ [CommandCmif(12)]
+ // GetDeviceId() -> bytes<0x10, 1>
+ public ResultCode GetDeviceId(ServiceCtx context)
+ {
+ // NOTE: Stubbed in system module.
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(13)]
+ // DeleteSettings(u32)
+ public ResultCode DeleteSettings(ServiceCtx context)
+ {
+ uint unknown = context.RequestData.ReadUInt32();
+
+ if (!_isInitialized)
+ {
+ return ResultCode.ServiceNotInitialized;
+ }
+
+ if (unknown > 1)
+ {
+ return ResultCode.InvalidArgument;
+ }
+
+ if (unknown == 1)
+ {
+ NxSettings.Settings.TryGetValue("nsd!environment_identifier", out object environmentIdentifier);
+
+ if ((string)environmentIdentifier == NsdSettings.Environment)
+ {
+ // TODO: Call nn::fs::DeleteSystemFile() to delete the savedata file and return ResultCode.
+ }
+ else
+ {
+ // TODO: Mount the savedata file and return ResultCode.
+ }
+ }
+ else
+ {
+ // TODO: Call nn::fs::DeleteSystemFile() to delete the savedata file and return ResultCode.
+ }
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(14)]
+ // ImportSettings(u32, buffer<unknown, 5>) -> buffer<unknown, 6>
+ public ResultCode ImportSettings(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(15)] // 4.0.0+
+ // SetChangeEnvironmentIdentifierDisabled(bytes<1>)
+ public ResultCode SetChangeEnvironmentIdentifierDisabled(ServiceCtx context)
+ {
+ byte disabled = context.RequestData.ReadByte();
+
+ // TODO: When sys:set service calls will be implemented
+ /*
+ if (((nn::settings::detail::GetServiceDiscoveryControlSettings() ^ disabled) & 1) != 0 )
+ {
+ nn::settings::detail::SetServiceDiscoveryControlSettings(disabled & 1);
+ }
+ */
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNsd, new { disabled });
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(20)]
+ // Resolve(buffer<unknown<0x100>, 0x15>) -> buffer<unknown<0x100>, 0x16>
+ public ResultCode Resolve(ServiceCtx context)
+ {
+ ulong outputPosition = context.Request.ReceiveBuff[0].Position;
+ ulong outputSize = context.Request.ReceiveBuff[0].Size;
+
+ ResultCode result = _fqdnResolver.ResolveEx(context, out _, out string resolvedAddress);
+
+ if ((ulong)resolvedAddress.Length > outputSize)
+ {
+ return ResultCode.InvalidArgument;
+ }
+
+ byte[] resolvedAddressBuffer = Encoding.UTF8.GetBytes(resolvedAddress);
+
+ MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
+
+ context.Memory.Write(outputPosition, resolvedAddressBuffer);
+
+ return result;
+ }
+
+ [CommandCmif(21)]
+ // ResolveEx(buffer<unknown<0x100>, 0x15>) -> (u32, buffer<unknown<0x100>, 0x16>)
+ public ResultCode ResolveEx(ServiceCtx context)
+ {
+ ulong outputPosition = context.Request.ReceiveBuff[0].Position;
+ ulong outputSize = context.Request.ReceiveBuff[0].Size;
+
+ ResultCode result = _fqdnResolver.ResolveEx(context, out ResultCode errorCode, out string resolvedAddress);
+
+ if ((ulong)resolvedAddress.Length > outputSize)
+ {
+ return ResultCode.InvalidArgument;
+ }
+
+ byte[] resolvedAddressBuffer = Encoding.UTF8.GetBytes(resolvedAddress);
+
+ MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
+
+ context.Memory.Write(outputPosition, resolvedAddressBuffer);
+
+ context.ResponseData.Write((int)errorCode);
+
+ return result;
+ }
+
+ [CommandCmif(30)]
+ // GetNasServiceSetting(buffer<unknown<0x10>, 0x15>) -> buffer<unknown<0x108>, 0x16>
+ public ResultCode GetNasServiceSetting(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(31)]
+ // GetNasServiceSettingEx(buffer<unknown<0x10>, 0x15>) -> (u32, buffer<unknown<0x108>, 0x16>)
+ public ResultCode GetNasServiceSettingEx(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(40)]
+ // GetNasRequestFqdn() -> buffer<unknown<0x100>, 0x16>
+ public ResultCode GetNasRequestFqdn(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(41)]
+ // GetNasRequestFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
+ public ResultCode GetNasRequestFqdnEx(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(42)]
+ // GetNasApiFqdn() -> buffer<unknown<0x100>, 0x16>
+ public ResultCode GetNasApiFqdn(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(43)]
+ // GetNasApiFqdnEx() -> (u32, buffer<unknown<0x100>, 0x16>)
+ public ResultCode GetNasApiFqdnEx(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(50)]
+ // GetCurrentSetting() -> buffer<unknown<0x12bf0>, 0x16>
+ public ResultCode GetCurrentSetting(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(51)] // 9.0.0+
+ // WriteTestParameter(buffer<?>)
+ public ResultCode WriteTestParameter(ServiceCtx context)
+ {
+ // TODO: Write test parameter through the savedata 0x80000000000000B0 (nsdsave:/test_parameter).
+
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(52)] // 9.0.0+
+ // ReadTestParameter() -> buffer<?>
+ public ResultCode ReadTestParameter(ServiceCtx context)
+ {
+ // TODO: Read test parameter through the savedata 0x80000000000000B0 (nsdsave:/test_parameter).
+
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(60)]
+ // ReadSaveDataFromFsForTest() -> buffer<unknown<0x12bf0>, 0x16>
+ public ResultCode ReadSaveDataFromFsForTest(ServiceCtx context)
+ {
+ if (!_isInitialized)
+ {
+ return ResultCode.ServiceNotInitialized;
+ }
+
+ // TODO: Read the savedata 0x80000000000000B0 (nsdsave:/file) and write it inside the buffer.
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNsd);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(61)]
+ // WriteSaveDataToFsForTest(buffer<unknown<0x12bf0>, 0x15>)
+ public ResultCode WriteSaveDataToFsForTest(ServiceCtx context)
+ {
+ if (!_isInitialized)
+ {
+ return ResultCode.ServiceNotInitialized;
+ }
+
+ // TODO: When sys:set service calls will be implemented
+ /*
+ if (nn::settings::detail::GetSettingsItemValueSize("nsd", "test_mode") != 1)
+ {
+ return ResultCode.InvalidSettingsValue;
+ }
+ */
+
+ if (!NsdSettings.TestMode)
+ {
+ return ResultCode.InvalidSettingsValue;
+ }
+
+ // TODO: Write the buffer inside the savedata 0x80000000000000B0 (nsdsave:/file).
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNsd);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(62)]
+ // DeleteSaveDataOfFsForTest()
+ public ResultCode DeleteSaveDataOfFsForTest(ServiceCtx context)
+ {
+ if (!_isInitialized)
+ {
+ return ResultCode.ServiceNotInitialized;
+ }
+
+ // TODO: When sys:set service calls will be implemented
+ /*
+ if (nn::settings::detail::GetSettingsItemValueSize("nsd", "test_mode") != 1)
+ {
+ return ResultCode.InvalidSettingsValue;
+ }
+ */
+
+ if (!NsdSettings.TestMode)
+ {
+ return ResultCode.InvalidSettingsValue;
+ }
+
+ // TODO: Delete the savedata 0x80000000000000B0.
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNsd);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(63)] // 4.0.0+
+ // IsChangeEnvironmentIdentifierDisabled() -> bytes<1>
+ public ResultCode IsChangeEnvironmentIdentifierDisabled(ServiceCtx context)
+ {
+ // TODO: When sys:set service calls will be implemented use nn::settings::detail::GetServiceDiscoveryControlSettings()
+
+ bool disabled = false;
+
+ context.ResponseData.Write(disabled);
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNsd, new { disabled });
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(100)] // 10.0.0+
+ // GetApplicationServerEnvironmentType() -> bytes<1>
+ public ResultCode GetApplicationServerEnvironmentType(ServiceCtx context)
+ {
+ // TODO: Mount the savedata 0x80000000000000B0 (nsdsave:/test_parameter) and returns the environment type stored inside if the mount succeed.
+ // Returns ResultCode.NullOutputObject if failed.
+
+ ResultCode result = _fqdnResolver.GetEnvironmentIdentifier(out string identifier);
+
+ if (result != ResultCode.Success)
+ {
+ return result;
+ }
+
+ byte environmentType = identifier.AsSpan(0, 2) switch
+ {
+ "lp" => (byte)ApplicationServerEnvironmentType.Lp,
+ "sd" => (byte)ApplicationServerEnvironmentType.Sd,
+ "sp" => (byte)ApplicationServerEnvironmentType.Sp,
+ "dp" => (byte)ApplicationServerEnvironmentType.Dp,
+ _ => (byte)ApplicationServerEnvironmentType.None
+ };
+
+ context.ResponseData.Write(environmentType);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(101)] // 10.0.0+
+ // SetApplicationServerEnvironmentType(bytes<1>)
+ public ResultCode SetApplicationServerEnvironmentType(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+
+ [CommandCmif(102)] // 10.0.0+
+ // DeleteApplicationServerEnvironmentType()
+ public ResultCode DeleteApplicationServerEnvironmentType(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(this, context);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs
new file mode 100644
index 00000000..4096e431
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Manager/FqdnResolver.cs
@@ -0,0 +1,97 @@
+using System.Text;
+
+namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager
+{
+ class FqdnResolver
+ {
+ private const string _dummyAddress = "unknown.dummy.nintendo.net";
+
+ public ResultCode GetEnvironmentIdentifier(out string identifier)
+ {
+ if (IManager.NsdSettings.TestMode)
+ {
+ identifier = "err";
+
+ return ResultCode.InvalidSettingsValue;
+ }
+ else
+ {
+ identifier = IManager.NsdSettings.Environment;
+ }
+
+ return ResultCode.Success;
+ }
+
+ public static ResultCode Resolve(string address, out string resolvedAddress)
+ {
+ if (address == "api.sect.srv.nintendo.net" ||
+ address == "ctest.cdn.nintendo.net" ||
+ address == "ctest.cdn.n.nintendoswitch.cn" ||
+ address == "unknown.dummy.nintendo.net")
+ {
+ resolvedAddress = address;
+ }
+ else
+ {
+ // TODO: Load Environment from the savedata.
+ address = address.Replace("%", IManager.NsdSettings.Environment);
+
+ resolvedAddress = "";
+
+ if (IManager.NsdSettings == null)
+ {
+ return ResultCode.SettingsNotInitialized;
+ }
+
+ if (!IManager.NsdSettings.Initialized)
+ {
+ return ResultCode.SettingsNotLoaded;
+ }
+
+ resolvedAddress = address switch
+ {
+ "e97b8a9d672e4ce4845ec6947cd66ef6-sb-api.accounts.nintendo.com" => "e97b8a9d672e4ce4845ec6947cd66ef6-sb.baas.nintendo.com", // dp1 environment
+ "api.accounts.nintendo.com" => "e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com", // dp1 environment
+ "e97b8a9d672e4ce4845ec6947cd66ef6-sb.accounts.nintendo.com" => "e97b8a9d672e4ce4845ec6947cd66ef6-sb.baas.nintendo.com", // lp1 environment
+ "accounts.nintendo.com" => "e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com", // lp1 environment
+ /*
+ // TODO: Determine fields of the struct.
+ this + 0xEB8 => this + 0xEB8 + 0x300
+ this + 0x2BE8 => this + 0x2BE8 + 0x300
+ */
+ _ => address,
+ };
+ }
+
+ return ResultCode.Success;
+ }
+
+ public ResultCode ResolveEx(ServiceCtx context, out ResultCode resultCode, out string resolvedAddress)
+ {
+ ulong inputPosition = context.Request.SendBuff[0].Position;
+ ulong inputSize = context.Request.SendBuff[0].Size;
+
+ byte[] addressBuffer = new byte[inputSize];
+
+ context.Memory.Read(inputPosition, addressBuffer);
+
+ string address = Encoding.UTF8.GetString(addressBuffer).TrimEnd('\0');
+
+ resultCode = Resolve(address, out resolvedAddress);
+
+ if (resultCode != ResultCode.Success)
+ {
+ resolvedAddress = _dummyAddress;
+ }
+
+ if (IManager.NsdSettings.TestMode)
+ {
+ return ResultCode.Success;
+ }
+ else
+ {
+ return resultCode;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs
new file mode 100644
index 00000000..993fbe8a
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/ResultCode.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
+{
+ enum ResultCode
+ {
+ ModuleId = 141,
+ ErrorCodeShift = 9,
+
+ Success = 0,
+
+ InvalidSettingsValue = ( 1 << ErrorCodeShift) | ModuleId,
+ InvalidObject1 = ( 3 << ErrorCodeShift) | ModuleId,
+ InvalidObject2 = ( 4 << ErrorCodeShift) | ModuleId,
+ NullOutputObject = ( 5 << ErrorCodeShift) | ModuleId,
+ SettingsNotLoaded = ( 6 << ErrorCodeShift) | ModuleId,
+ InvalidArgument = ( 8 << ErrorCodeShift) | ModuleId,
+ SettingsNotInitialized = ( 10 << ErrorCodeShift) | ModuleId,
+ ServiceNotInitialized = (400 << ErrorCodeShift) | ModuleId,
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/ApplicationServerEnvironmentType.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/ApplicationServerEnvironmentType.cs
new file mode 100644
index 00000000..150bdab4
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/ApplicationServerEnvironmentType.cs
@@ -0,0 +1,11 @@
+namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd.Types
+{
+ enum ApplicationServerEnvironmentType : byte
+ {
+ None,
+ Lp,
+ Sd,
+ Sp,
+ Dp
+ }
+} \ No newline at end of file
diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs
new file mode 100644
index 00000000..0a72fa87
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Nsd/Types/NsdSettings.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd
+{
+ class NsdSettings
+ {
+ public bool Initialized;
+ public bool TestMode;
+ public string Environment;
+ }
+} \ No newline at end of file