IGeneralService.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Common.Utilities;
  4. using Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService;
  5. using Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types;
  6. using System;
  7. using System.Net.NetworkInformation;
  8. using System.Runtime.CompilerServices;
  9. using System.Text;
  10. namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
  11. {
  12. class IGeneralService : DisposableIpcService
  13. {
  14. private GeneralServiceDetail _generalServiceDetail;
  15. private IPInterfaceProperties _targetPropertiesCache = null;
  16. private UnicastIPAddressInformation _targetAddressInfoCache = null;
  17. public IGeneralService()
  18. {
  19. _generalServiceDetail = new GeneralServiceDetail
  20. {
  21. ClientId = GeneralServiceManager.Count,
  22. IsAnyInternetRequestAccepted = true // NOTE: Why not accept any internet request?
  23. };
  24. NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(LocalInterfaceCacheHandler);
  25. GeneralServiceManager.Add(_generalServiceDetail);
  26. }
  27. [CommandHipc(1)]
  28. // GetClientId() -> buffer<nn::nifm::ClientId, 0x1a, 4>
  29. public ResultCode GetClientId(ServiceCtx context)
  30. {
  31. ulong position = context.Request.RecvListBuff[0].Position;
  32. context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(sizeof(int));
  33. context.Memory.Write(position, _generalServiceDetail.ClientId);
  34. return ResultCode.Success;
  35. }
  36. [CommandHipc(4)]
  37. // CreateRequest(u32 version) -> object<nn::nifm::detail::IRequest>
  38. public ResultCode CreateRequest(ServiceCtx context)
  39. {
  40. uint version = context.RequestData.ReadUInt32();
  41. MakeObject(context, new IRequest(context.Device.System, version));
  42. // Doesn't occur in our case.
  43. // return ResultCode.ObjectIsNull;
  44. Logger.Stub?.PrintStub(LogClass.ServiceNifm, new { version });
  45. return ResultCode.Success;
  46. }
  47. [CommandHipc(5)]
  48. // GetCurrentNetworkProfile() -> buffer<nn::nifm::detail::sf::NetworkProfileData, 0x1a, 0x17c>
  49. public ResultCode GetCurrentNetworkProfile(ServiceCtx context)
  50. {
  51. ulong networkProfileDataPosition = context.Request.RecvListBuff[0].Position;
  52. (IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastAddress) = GetLocalInterface();
  53. if (interfaceProperties == null || unicastAddress == null)
  54. {
  55. return ResultCode.NoInternetConnection;
  56. }
  57. Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
  58. context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Unsafe.SizeOf<NetworkProfileData>());
  59. NetworkProfileData networkProfile = new NetworkProfileData
  60. {
  61. Uuid = UInt128Utils.CreateRandom()
  62. };
  63. networkProfile.IpSettingData.IpAddressSetting = new IpAddressSetting(interfaceProperties, unicastAddress);
  64. networkProfile.IpSettingData.DnsSetting = new DnsSetting(interfaceProperties);
  65. Encoding.ASCII.GetBytes("RyujinxNetwork").CopyTo(networkProfile.Name.AsSpan());
  66. context.Memory.Write(networkProfileDataPosition, networkProfile);
  67. return ResultCode.Success;
  68. }
  69. [CommandHipc(12)]
  70. // GetCurrentIpAddress() -> nn::nifm::IpV4Address
  71. public ResultCode GetCurrentIpAddress(ServiceCtx context)
  72. {
  73. (_, UnicastIPAddressInformation unicastAddress) = GetLocalInterface();
  74. if (unicastAddress == null)
  75. {
  76. return ResultCode.NoInternetConnection;
  77. }
  78. context.ResponseData.WriteStruct(new IpV4Address(unicastAddress.Address));
  79. Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
  80. return ResultCode.Success;
  81. }
  82. [CommandHipc(15)]
  83. // GetCurrentIpConfigInfo() -> (nn::nifm::IpAddressSetting, nn::nifm::DnsSetting)
  84. public ResultCode GetCurrentIpConfigInfo(ServiceCtx context)
  85. {
  86. (IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastAddress) = GetLocalInterface();
  87. if (interfaceProperties == null || unicastAddress == null)
  88. {
  89. return ResultCode.NoInternetConnection;
  90. }
  91. Logger.Info?.Print(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
  92. context.ResponseData.WriteStruct(new IpAddressSetting(interfaceProperties, unicastAddress));
  93. context.ResponseData.WriteStruct(new DnsSetting(interfaceProperties));
  94. return ResultCode.Success;
  95. }
  96. [CommandHipc(18)]
  97. // GetInternetConnectionStatus() -> nn::nifm::detail::sf::InternetConnectionStatus
  98. public ResultCode GetInternetConnectionStatus(ServiceCtx context)
  99. {
  100. if (!NetworkInterface.GetIsNetworkAvailable())
  101. {
  102. return ResultCode.NoInternetConnection;
  103. }
  104. InternetConnectionStatus internetConnectionStatus = new InternetConnectionStatus
  105. {
  106. Type = InternetConnectionType.WiFi,
  107. WifiStrength = 3,
  108. State = InternetConnectionState.Connected,
  109. };
  110. context.ResponseData.WriteStruct(internetConnectionStatus);
  111. return ResultCode.Success;
  112. }
  113. [CommandHipc(21)]
  114. // IsAnyInternetRequestAccepted(buffer<nn::nifm::ClientId, 0x19, 4>) -> bool
  115. public ResultCode IsAnyInternetRequestAccepted(ServiceCtx context)
  116. {
  117. ulong position = context.Request.PtrBuff[0].Position;
  118. ulong size = context.Request.PtrBuff[0].Size;
  119. int clientId = context.Memory.Read<int>(position);
  120. context.ResponseData.Write(GeneralServiceManager.Get(clientId).IsAnyInternetRequestAccepted);
  121. return ResultCode.Success;
  122. }
  123. private (IPInterfaceProperties, UnicastIPAddressInformation) GetLocalInterface()
  124. {
  125. if (!NetworkInterface.GetIsNetworkAvailable())
  126. {
  127. return (null, null);
  128. }
  129. if (_targetPropertiesCache != null && _targetAddressInfoCache != null)
  130. {
  131. return (_targetPropertiesCache, _targetAddressInfoCache);
  132. }
  133. IPInterfaceProperties targetProperties = null;
  134. UnicastIPAddressInformation targetAddressInfo = null;
  135. NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
  136. foreach (NetworkInterface adapter in interfaces)
  137. {
  138. // Ignore loopback and non IPv4 capable interface.
  139. if (targetProperties == null && adapter.NetworkInterfaceType != NetworkInterfaceType.Loopback && adapter.Supports(NetworkInterfaceComponent.IPv4))
  140. {
  141. IPInterfaceProperties properties = adapter.GetIPProperties();
  142. if (properties.GatewayAddresses.Count > 0 && properties.DnsAddresses.Count > 0)
  143. {
  144. foreach (UnicastIPAddressInformation info in properties.UnicastAddresses)
  145. {
  146. // Only accept an IPv4 address
  147. if (info.Address.GetAddressBytes().Length == 4)
  148. {
  149. targetProperties = properties;
  150. targetAddressInfo = info;
  151. break;
  152. }
  153. }
  154. }
  155. }
  156. }
  157. _targetPropertiesCache = targetProperties;
  158. _targetAddressInfoCache = targetAddressInfo;
  159. return (targetProperties, targetAddressInfo);
  160. }
  161. private void LocalInterfaceCacheHandler(object sender, EventArgs e)
  162. {
  163. Logger.Info?.Print(LogClass.ServiceNifm, $"NetworkAddress changed, invalidating cached data.");
  164. _targetPropertiesCache = null;
  165. _targetAddressInfoCache = null;
  166. }
  167. protected override void Dispose(bool isDisposing)
  168. {
  169. if (isDisposing)
  170. {
  171. NetworkChange.NetworkAddressChanged -= LocalInterfaceCacheHandler;
  172. GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
  173. }
  174. }
  175. }
  176. }