ManagedSocket.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. using Ryujinx.Common.Logging;
  2. using System;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using System.Runtime.InteropServices;
  6. namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
  7. {
  8. class ManagedSocket : ISocket
  9. {
  10. public int Refcount { get; set; }
  11. public AddressFamily AddressFamily => Socket.AddressFamily;
  12. public SocketType SocketType => Socket.SocketType;
  13. public ProtocolType ProtocolType => Socket.ProtocolType;
  14. public bool Blocking { get => Socket.Blocking; set => Socket.Blocking = value; }
  15. public IntPtr Handle => Socket.Handle;
  16. public IPEndPoint RemoteEndPoint => Socket.RemoteEndPoint as IPEndPoint;
  17. public IPEndPoint LocalEndPoint => Socket.LocalEndPoint as IPEndPoint;
  18. public Socket Socket { get; }
  19. public ManagedSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
  20. {
  21. Socket = new Socket(addressFamily, socketType, protocolType);
  22. Refcount = 1;
  23. }
  24. private ManagedSocket(Socket socket)
  25. {
  26. Socket = socket;
  27. Refcount = 1;
  28. }
  29. private static SocketFlags ConvertBsdSocketFlags(BsdSocketFlags bsdSocketFlags)
  30. {
  31. SocketFlags socketFlags = SocketFlags.None;
  32. if (bsdSocketFlags.HasFlag(BsdSocketFlags.Oob))
  33. {
  34. socketFlags |= SocketFlags.OutOfBand;
  35. }
  36. if (bsdSocketFlags.HasFlag(BsdSocketFlags.Peek))
  37. {
  38. socketFlags |= SocketFlags.Peek;
  39. }
  40. if (bsdSocketFlags.HasFlag(BsdSocketFlags.DontRoute))
  41. {
  42. socketFlags |= SocketFlags.DontRoute;
  43. }
  44. if (bsdSocketFlags.HasFlag(BsdSocketFlags.Trunc))
  45. {
  46. socketFlags |= SocketFlags.Truncated;
  47. }
  48. if (bsdSocketFlags.HasFlag(BsdSocketFlags.CTrunc))
  49. {
  50. socketFlags |= SocketFlags.ControlDataTruncated;
  51. }
  52. bsdSocketFlags &= ~(BsdSocketFlags.Oob |
  53. BsdSocketFlags.Peek |
  54. BsdSocketFlags.DontRoute |
  55. BsdSocketFlags.DontWait |
  56. BsdSocketFlags.Trunc |
  57. BsdSocketFlags.CTrunc);
  58. if (bsdSocketFlags != BsdSocketFlags.None)
  59. {
  60. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported socket flags: {bsdSocketFlags}");
  61. }
  62. return socketFlags;
  63. }
  64. public LinuxError Accept(out ISocket newSocket)
  65. {
  66. try
  67. {
  68. newSocket = new ManagedSocket(Socket.Accept());
  69. return LinuxError.SUCCESS;
  70. }
  71. catch (SocketException exception)
  72. {
  73. newSocket = null;
  74. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  75. }
  76. }
  77. public LinuxError Bind(IPEndPoint localEndPoint)
  78. {
  79. try
  80. {
  81. Socket.Bind(localEndPoint);
  82. return LinuxError.SUCCESS;
  83. }
  84. catch (SocketException exception)
  85. {
  86. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  87. }
  88. }
  89. public void Close()
  90. {
  91. Socket.Close();
  92. }
  93. public LinuxError Connect(IPEndPoint remoteEndPoint)
  94. {
  95. try
  96. {
  97. Socket.Connect(remoteEndPoint);
  98. return LinuxError.SUCCESS;
  99. }
  100. catch (SocketException exception)
  101. {
  102. if (!Blocking && exception.ErrorCode == (int)WsaError.WSAEWOULDBLOCK)
  103. {
  104. return LinuxError.EINPROGRESS;
  105. }
  106. else
  107. {
  108. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  109. }
  110. }
  111. }
  112. public void Disconnect()
  113. {
  114. Socket.Disconnect(true);
  115. }
  116. public void Dispose()
  117. {
  118. Socket.Close();
  119. Socket.Dispose();
  120. }
  121. public LinuxError Listen(int backlog)
  122. {
  123. try
  124. {
  125. Socket.Listen(backlog);
  126. return LinuxError.SUCCESS;
  127. }
  128. catch (SocketException exception)
  129. {
  130. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  131. }
  132. }
  133. public bool Poll(int microSeconds, SelectMode mode)
  134. {
  135. return Socket.Poll(microSeconds, mode);
  136. }
  137. public LinuxError Shutdown(BsdSocketShutdownFlags how)
  138. {
  139. try
  140. {
  141. Socket.Shutdown((SocketShutdown)how);
  142. return LinuxError.SUCCESS;
  143. }
  144. catch (SocketException exception)
  145. {
  146. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  147. }
  148. }
  149. public LinuxError Receive(out int receiveSize, Span<byte> buffer, BsdSocketFlags flags)
  150. {
  151. try
  152. {
  153. receiveSize = Socket.Receive(buffer, ConvertBsdSocketFlags(flags));
  154. return LinuxError.SUCCESS;
  155. }
  156. catch (SocketException exception)
  157. {
  158. receiveSize = -1;
  159. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  160. }
  161. }
  162. public LinuxError ReceiveFrom(out int receiveSize, Span<byte> buffer, int size, BsdSocketFlags flags, out IPEndPoint remoteEndPoint)
  163. {
  164. remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
  165. LinuxError result;
  166. bool shouldBlockAfterOperation = false;
  167. try
  168. {
  169. EndPoint temp = new IPEndPoint(IPAddress.Any, 0);
  170. if (Blocking && flags.HasFlag(BsdSocketFlags.DontWait))
  171. {
  172. Blocking = false;
  173. shouldBlockAfterOperation = true;
  174. }
  175. receiveSize = Socket.ReceiveFrom(buffer[..size], ConvertBsdSocketFlags(flags), ref temp);
  176. remoteEndPoint = (IPEndPoint)temp;
  177. result = LinuxError.SUCCESS;
  178. }
  179. catch (SocketException exception)
  180. {
  181. receiveSize = -1;
  182. result = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  183. }
  184. if (shouldBlockAfterOperation)
  185. {
  186. Blocking = true;
  187. }
  188. return result;
  189. }
  190. public LinuxError Send(out int sendSize, ReadOnlySpan<byte> buffer, BsdSocketFlags flags)
  191. {
  192. try
  193. {
  194. sendSize = Socket.Send(buffer, ConvertBsdSocketFlags(flags));
  195. return LinuxError.SUCCESS;
  196. }
  197. catch (SocketException exception)
  198. {
  199. sendSize = -1;
  200. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  201. }
  202. }
  203. public LinuxError SendTo(out int sendSize, ReadOnlySpan<byte> buffer, int size, BsdSocketFlags flags, IPEndPoint remoteEndPoint)
  204. {
  205. try
  206. {
  207. sendSize = Socket.SendTo(buffer[..size], ConvertBsdSocketFlags(flags), remoteEndPoint);
  208. return LinuxError.SUCCESS;
  209. }
  210. catch (SocketException exception)
  211. {
  212. sendSize = -1;
  213. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  214. }
  215. }
  216. public LinuxError GetSocketOption(BsdSocketOption option, SocketOptionLevel level, Span<byte> optionValue)
  217. {
  218. try
  219. {
  220. if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
  221. {
  222. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}");
  223. return LinuxError.EOPNOTSUPP;
  224. }
  225. byte[] tempOptionValue = new byte[optionValue.Length];
  226. Socket.GetSocketOption(level, optionName, tempOptionValue);
  227. tempOptionValue.AsSpan().CopyTo(optionValue);
  228. return LinuxError.SUCCESS;
  229. }
  230. catch (SocketException exception)
  231. {
  232. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  233. }
  234. }
  235. public LinuxError SetSocketOption(BsdSocketOption option, SocketOptionLevel level, ReadOnlySpan<byte> optionValue)
  236. {
  237. try
  238. {
  239. if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
  240. {
  241. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}");
  242. return LinuxError.EOPNOTSUPP;
  243. }
  244. int value = MemoryMarshal.Read<int>(optionValue);
  245. if (option == BsdSocketOption.SoLinger)
  246. {
  247. int value2 = MemoryMarshal.Read<int>(optionValue[4..]);
  248. Socket.SetSocketOption(level, SocketOptionName.Linger, new LingerOption(value != 0, value2));
  249. }
  250. else
  251. {
  252. Socket.SetSocketOption(level, optionName, value);
  253. }
  254. return LinuxError.SUCCESS;
  255. }
  256. catch (SocketException exception)
  257. {
  258. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  259. }
  260. }
  261. public LinuxError Read(out int readSize, Span<byte> buffer)
  262. {
  263. return Receive(out readSize, buffer, BsdSocketFlags.None);
  264. }
  265. public LinuxError Write(out int writeSize, ReadOnlySpan<byte> buffer)
  266. {
  267. return Send(out writeSize, buffer, BsdSocketFlags.None);
  268. }
  269. }
  270. }