IGeneralService.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. using Ryujinx.Common;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.HLE.HOS.Services.Nifm.StaticService.GeneralService;
  4. using Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types;
  5. using System;
  6. using System.Diagnostics;
  7. using System.Linq;
  8. using System.Net;
  9. using System.Net.NetworkInformation;
  10. using System.Net.Sockets;
  11. using System.Runtime.CompilerServices;
  12. namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService
  13. {
  14. class IGeneralService : IpcService, IDisposable
  15. {
  16. private GeneralServiceDetail _generalServiceDetail;
  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. GeneralServiceManager.Add(_generalServiceDetail);
  25. }
  26. [Command(1)]
  27. // GetClientId() -> buffer<nn::nifm::ClientId, 0x1a, 4>
  28. public ResultCode GetClientId(ServiceCtx context)
  29. {
  30. long position = context.Request.RecvListBuff[0].Position;
  31. long size = context.Request.RecvListBuff[0].Size;
  32. context.Memory.Write((ulong)position, _generalServiceDetail.ClientId);
  33. return ResultCode.Success;
  34. }
  35. [Command(4)]
  36. // CreateRequest(u32 version) -> object<nn::nifm::detail::IRequest>
  37. public ResultCode CreateRequest(ServiceCtx context)
  38. {
  39. uint version = context.RequestData.ReadUInt32();
  40. MakeObject(context, new IRequest(context.Device.System, version));
  41. // Doesn't occur in our case.
  42. // return ResultCode.ObjectIsNull;
  43. Logger.PrintStub(LogClass.ServiceNifm, new { version });
  44. return ResultCode.Success;
  45. }
  46. [Command(12)]
  47. // GetCurrentIpAddress() -> nn::nifm::IpV4Address
  48. public ResultCode GetCurrentIpAddress(ServiceCtx context)
  49. {
  50. (_, UnicastIPAddressInformation unicastAddress) = GetLocalInterface();
  51. if (unicastAddress == null)
  52. {
  53. return ResultCode.NoInternetConnection;
  54. }
  55. context.ResponseData.WriteStruct(new IpV4Address(unicastAddress.Address));
  56. Logger.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
  57. return ResultCode.Success;
  58. }
  59. [Command(15)]
  60. // GetCurrentIpConfigInfo() -> (nn::nifm::IpAddressSetting, nn::nifm::DnsSetting)
  61. public ResultCode GetCurrentIpConfigInfo(ServiceCtx context)
  62. {
  63. (IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastAddress) = GetLocalInterface();
  64. if (interfaceProperties == null)
  65. {
  66. return ResultCode.NoInternetConnection;
  67. }
  68. Logger.PrintInfo(LogClass.ServiceNifm, $"Console's local IP is \"{unicastAddress.Address}\".");
  69. context.ResponseData.WriteStruct(new IpAddressSetting(interfaceProperties, unicastAddress));
  70. context.ResponseData.WriteStruct(new DnsSetting(interfaceProperties));
  71. return ResultCode.Success;
  72. }
  73. [Command(18)]
  74. // GetInternetConnectionStatus() -> nn::nifm::detail::sf::InternetConnectionStatus
  75. public ResultCode GetInternetConnectionStatus(ServiceCtx context)
  76. {
  77. if (!NetworkInterface.GetIsNetworkAvailable())
  78. {
  79. return ResultCode.NoInternetConnection;
  80. }
  81. InternetConnectionStatus internetConnectionStatus = new InternetConnectionStatus
  82. {
  83. Type = InternetConnectionType.WiFi,
  84. WifiStrength = 3,
  85. State = InternetConnectionState.Connected,
  86. };
  87. context.ResponseData.WriteStruct(internetConnectionStatus);
  88. return ResultCode.Success;
  89. }
  90. [Command(21)]
  91. // IsAnyInternetRequestAccepted(buffer<nn::nifm::ClientId, 0x19, 4>) -> bool
  92. public ResultCode IsAnyInternetRequestAccepted(ServiceCtx context)
  93. {
  94. long position = context.Request.PtrBuff[0].Position;
  95. long size = context.Request.PtrBuff[0].Size;
  96. int clientId = context.Memory.Read<int>((ulong)position);
  97. context.ResponseData.Write(GeneralServiceManager.Get(clientId).IsAnyInternetRequestAccepted);
  98. return ResultCode.Success;
  99. }
  100. private (IPInterfaceProperties, UnicastIPAddressInformation) GetLocalInterface()
  101. {
  102. if (!NetworkInterface.GetIsNetworkAvailable())
  103. {
  104. return (null, null);
  105. }
  106. IPInterfaceProperties targetProperties = null;
  107. UnicastIPAddressInformation targetAddressInfo = null;
  108. NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
  109. foreach (NetworkInterface adapter in interfaces)
  110. {
  111. // Ignore loopback and non IPv4 capable interface.
  112. if (adapter.NetworkInterfaceType != NetworkInterfaceType.Loopback && adapter.Supports(NetworkInterfaceComponent.IPv4))
  113. {
  114. IPInterfaceProperties properties = adapter.GetIPProperties();
  115. if (properties.GatewayAddresses.Count > 0 && properties.DnsAddresses.Count > 1)
  116. {
  117. foreach (UnicastIPAddressInformation info in properties.UnicastAddresses)
  118. {
  119. // Only accept an IPv4 address
  120. if (info.Address.GetAddressBytes().Length == 4)
  121. {
  122. targetProperties = properties;
  123. targetAddressInfo = info;
  124. break;
  125. }
  126. }
  127. }
  128. // Found the target interface, stop here.
  129. if (targetProperties != null)
  130. {
  131. break;
  132. }
  133. }
  134. }
  135. return (targetProperties, targetAddressInfo);
  136. }
  137. public void Dispose()
  138. {
  139. GeneralServiceManager.Remove(_generalServiceDetail.ClientId);
  140. }
  141. }
  142. }