ManagedSocket.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. LinuxError result;
  152. bool shouldBlockAfterOperation = false;
  153. try
  154. {
  155. if (Blocking && flags.HasFlag(BsdSocketFlags.DontWait))
  156. {
  157. Blocking = false;
  158. shouldBlockAfterOperation = true;
  159. }
  160. receiveSize = Socket.Receive(buffer, ConvertBsdSocketFlags(flags));
  161. result = LinuxError.SUCCESS;
  162. }
  163. catch (SocketException exception)
  164. {
  165. receiveSize = -1;
  166. result = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  167. }
  168. if (shouldBlockAfterOperation)
  169. {
  170. Blocking = true;
  171. }
  172. return result;
  173. }
  174. public LinuxError ReceiveFrom(out int receiveSize, Span<byte> buffer, int size, BsdSocketFlags flags, out IPEndPoint remoteEndPoint)
  175. {
  176. remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
  177. LinuxError result;
  178. bool shouldBlockAfterOperation = false;
  179. try
  180. {
  181. EndPoint temp = new IPEndPoint(IPAddress.Any, 0);
  182. if (Blocking && flags.HasFlag(BsdSocketFlags.DontWait))
  183. {
  184. Blocking = false;
  185. shouldBlockAfterOperation = true;
  186. }
  187. receiveSize = Socket.ReceiveFrom(buffer[..size], ConvertBsdSocketFlags(flags), ref temp);
  188. remoteEndPoint = (IPEndPoint)temp;
  189. result = LinuxError.SUCCESS;
  190. }
  191. catch (SocketException exception)
  192. {
  193. receiveSize = -1;
  194. result = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  195. }
  196. if (shouldBlockAfterOperation)
  197. {
  198. Blocking = true;
  199. }
  200. return result;
  201. }
  202. public LinuxError Send(out int sendSize, ReadOnlySpan<byte> buffer, BsdSocketFlags flags)
  203. {
  204. try
  205. {
  206. sendSize = Socket.Send(buffer, ConvertBsdSocketFlags(flags));
  207. return LinuxError.SUCCESS;
  208. }
  209. catch (SocketException exception)
  210. {
  211. sendSize = -1;
  212. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  213. }
  214. }
  215. public LinuxError SendTo(out int sendSize, ReadOnlySpan<byte> buffer, int size, BsdSocketFlags flags, IPEndPoint remoteEndPoint)
  216. {
  217. try
  218. {
  219. sendSize = Socket.SendTo(buffer[..size], ConvertBsdSocketFlags(flags), remoteEndPoint);
  220. return LinuxError.SUCCESS;
  221. }
  222. catch (SocketException exception)
  223. {
  224. sendSize = -1;
  225. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  226. }
  227. }
  228. public LinuxError GetSocketOption(BsdSocketOption option, SocketOptionLevel level, Span<byte> optionValue)
  229. {
  230. try
  231. {
  232. if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
  233. {
  234. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Option: {option} Level: {level}");
  235. return LinuxError.EOPNOTSUPP;
  236. }
  237. byte[] tempOptionValue = new byte[optionValue.Length];
  238. Socket.GetSocketOption(level, optionName, tempOptionValue);
  239. tempOptionValue.AsSpan().CopyTo(optionValue);
  240. return LinuxError.SUCCESS;
  241. }
  242. catch (SocketException exception)
  243. {
  244. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  245. }
  246. }
  247. public LinuxError SetSocketOption(BsdSocketOption option, SocketOptionLevel level, ReadOnlySpan<byte> optionValue)
  248. {
  249. try
  250. {
  251. if (!WinSockHelper.TryConvertSocketOption(option, level, out SocketOptionName optionName))
  252. {
  253. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Option: {option} Level: {level}");
  254. return LinuxError.EOPNOTSUPP;
  255. }
  256. int value = optionValue.Length >= 4 ? MemoryMarshal.Read<int>(optionValue) : MemoryMarshal.Read<byte>(optionValue);
  257. if (option == BsdSocketOption.SoLinger)
  258. {
  259. int value2 = MemoryMarshal.Read<int>(optionValue[4..]);
  260. Socket.SetSocketOption(level, SocketOptionName.Linger, new LingerOption(value != 0, value2));
  261. }
  262. else
  263. {
  264. Socket.SetSocketOption(level, optionName, value);
  265. }
  266. return LinuxError.SUCCESS;
  267. }
  268. catch (SocketException exception)
  269. {
  270. return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
  271. }
  272. }
  273. public LinuxError Read(out int readSize, Span<byte> buffer)
  274. {
  275. return Receive(out readSize, buffer, BsdSocketFlags.None);
  276. }
  277. public LinuxError Write(out int writeSize, ReadOnlySpan<byte> buffer)
  278. {
  279. return Send(out writeSize, buffer, BsdSocketFlags.None);
  280. }
  281. }
  282. }