aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs')
-rw-r--r--src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
new file mode 100644
index 00000000..e9712e92
--- /dev/null
+++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs
@@ -0,0 +1,203 @@
+using Ryujinx.Common;
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Utilities;
+using Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService;
+using Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types;
+using System;
+using System.Net.NetworkInformation;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
+{
+ class IGeneralService : DisposableIpcService
+ {
+ private GeneralServiceDetail _generalServiceDetail;
+
+ private IPInterfaceProperties _targetPropertiesCache = null;
+ private UnicastIPAddressInformation _targetAddressInfoCache = null;
+ private string _cacheChosenInterface = null;
+
+ public IGeneralService()
+ {
+ _generalServiceDetail = new GeneralServiceDetail
+ {
+ ClientId = GeneralServiceManager.Count,
+ IsAnyInternetRequestAccepted = true // NOTE: Why not accept any internet request?
+ };
+
+ NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(LocalInterfaceCacheHandler);
+
+ GeneralServiceManager.Add(_generalServiceDetail);
+ }
+
+ [CommandCmif(1)]
+ // GetClientId() -> buffer<nn::nifm::ClientId, 0x1a, 4>
+ public ResultCode GetClientId(ServiceCtx context)
+ {
+ ulong position = context.Request.RecvListBuff[0].Position;
+
+ context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(sizeof(int));
+
+ context.Memory.Write(position, _generalServiceDetail.ClientId);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(4)]
+ // CreateRequest(u32 version) -> object<nn::nifm::detail::IRequest>
+ public ResultCode CreateRequest(ServiceCtx context)
+ {
+ uint version = context.RequestData.ReadUInt32();
+
+ MakeObject(context, new IRequest(context.Device.System, version));
+
+ // Doesn't occur in our case.
+ // return ResultCode.ObjectIsNull;
+
+ Logger.Stub?.PrintStub(LogClass.ServiceNifm, new { version });
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(5)]
+ // GetCurrentNetworkProfile() -> buffer<nn::nifm::detail::sf::NetworkProfileData, 0x1a, 0x17c>
+ public ResultCode GetCurrentNetworkProfile(ServiceCtx context)
+ {
+ ulong networkProfileDataPosition = context.Request.RecvListBuff[0].Position;
+
+ (IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastAddress) = GetLocalInterface(context);
+
+ if (interfaceProperties == null || unicastAddress == null)
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
+
+ context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Unsafe.SizeOf<NetworkProfileData>());
+
+ NetworkProfileData networkProfile = new NetworkProfileData
+ {
+ Uuid = UInt128Utils.CreateRandom()
+ };
+
+ networkProfile.IpSettingData.IpAddressSetting = new IpAddressSetting(interfaceProperties, unicastAddress);
+ networkProfile.IpSettingData.DnsSetting = new DnsSetting(interfaceProperties);
+
+ "RyujinxNetwork"u8.CopyTo(networkProfile.Name.AsSpan());
+
+ context.Memory.Write(networkProfileDataPosition, networkProfile);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(12)]
+ // GetCurrentIpAddress() -> nn::nifm::IpV4Address
+ public ResultCode GetCurrentIpAddress(ServiceCtx context)
+ {
+ (_, UnicastIPAddressInformation unicastAddress) = GetLocalInterface(context);
+
+ if (unicastAddress == null)
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ context.ResponseData.WriteStruct(new IpV4Address(unicastAddress.Address));
+
+ Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(15)]
+ // GetCurrentIpConfigInfo() -> (nn::nifm::IpAddressSetting, nn::nifm::DnsSetting)
+ public ResultCode GetCurrentIpConfigInfo(ServiceCtx context)
+ {
+ (IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastAddress) = GetLocalInterface(context);
+
+ if (interfaceProperties == null || unicastAddress == null)
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
+
+ context.ResponseData.WriteStruct(new IpAddressSetting(interfaceProperties, unicastAddress));
+ context.ResponseData.WriteStruct(new DnsSetting(interfaceProperties));
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(18)]
+ // GetInternetConnectionStatus() -> nn::nifm::detail::sf::InternetConnectionStatus
+ public ResultCode GetInternetConnectionStatus(ServiceCtx context)
+ {
+ if (!NetworkInterface.GetIsNetworkAvailable())
+ {
+ return ResultCode.NoInternetConnection;
+ }
+
+ InternetConnectionStatus internetConnectionStatus = new InternetConnectionStatus
+ {
+ Type = InternetConnectionType.WiFi,
+ WifiStrength = 3,
+ State = InternetConnectionState.Connected,
+ };
+
+ context.ResponseData.WriteStruct(internetConnectionStatus);
+
+ return ResultCode.Success;
+ }
+
+ [CommandCmif(21)]
+ // IsAnyInternetRequestAccepted(buffer<nn::nifm::ClientId, 0x19, 4>) -> bool
+ public ResultCode IsAnyInternetRequestAccepted(ServiceCtx context)
+ {
+ ulong position = context.Request.PtrBuff[0].Position;
+ ulong size = context.Request.PtrBuff[0].Size;
+
+ int clientId = context.Memory.Read<int>(position);
+
+ context.ResponseData.Write(GeneralServiceManager.Get(clientId).IsAnyInternetRequestAccepted);
+
+ return ResultCode.Success;
+ }
+
+ private (IPInterfaceProperties, UnicastIPAddressInformation) GetLocalInterface(ServiceCtx context)
+ {
+ if (!NetworkInterface.GetIsNetworkAvailable())
+ {
+ return (null, null);
+ }
+
+ string chosenInterface = context.Device.Configuration.MultiplayerLanInterfaceId;
+
+ if (_targetPropertiesCache == null || _targetAddressInfoCache == null || _cacheChosenInterface != chosenInterface)
+ {
+ _cacheChosenInterface = chosenInterface;
+
+ (_targetPropertiesCache, _targetAddressInfoCache) = NetworkHelpers.GetLocalInterface(chosenInterface);
+ }
+
+ return (_targetPropertiesCache, _targetAddressInfoCache);
+ }
+
+ private void LocalInterfaceCacheHandler(object sender, EventArgs e)
+ {
+ Logger.Info?.Print(LogClass.ServiceNifm, $"NetworkAddress changed, invalidating cached data.");
+
+ _targetPropertiesCache = null;
+ _targetAddressInfoCache = null;
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ if (isDisposing)
+ {
+ NetworkChange.NetworkAddressChanged -= LocalInterfaceCacheHandler;
+
+ GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
+ }
+ }
+ }
+} \ No newline at end of file