diff options
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs')
| -rw-r--r-- | src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/IGeneralService.cs | 203 |
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 |
