IClient.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.HLE.Utilities;
  3. using System;
  4. using System.Buffers.Binary;
  5. using System.Collections.Generic;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using System.Text;
  9. using System.Threading;
  10. namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
  11. {
  12. [Service("bsd:s", true)]
  13. [Service("bsd:u", false)]
  14. class IClient : IpcService
  15. {
  16. private static Dictionary<WsaError, LinuxError> _errorMap = new Dictionary<WsaError, LinuxError>
  17. {
  18. // WSAEINTR
  19. {WsaError.WSAEINTR, LinuxError.EINTR},
  20. // WSAEWOULDBLOCK
  21. {WsaError.WSAEWOULDBLOCK, LinuxError.EWOULDBLOCK},
  22. // WSAEINPROGRESS
  23. {WsaError.WSAEINPROGRESS, LinuxError.EINPROGRESS},
  24. // WSAEALREADY
  25. {WsaError.WSAEALREADY, LinuxError.EALREADY},
  26. // WSAENOTSOCK
  27. {WsaError.WSAENOTSOCK, LinuxError.ENOTSOCK},
  28. // WSAEDESTADDRREQ
  29. {WsaError.WSAEDESTADDRREQ, LinuxError.EDESTADDRREQ},
  30. // WSAEMSGSIZE
  31. {WsaError.WSAEMSGSIZE, LinuxError.EMSGSIZE},
  32. // WSAEPROTOTYPE
  33. {WsaError.WSAEPROTOTYPE, LinuxError.EPROTOTYPE},
  34. // WSAENOPROTOOPT
  35. {WsaError.WSAENOPROTOOPT, LinuxError.ENOPROTOOPT},
  36. // WSAEPROTONOSUPPORT
  37. {WsaError.WSAEPROTONOSUPPORT, LinuxError.EPROTONOSUPPORT},
  38. // WSAESOCKTNOSUPPORT
  39. {WsaError.WSAESOCKTNOSUPPORT, LinuxError.ESOCKTNOSUPPORT},
  40. // WSAEOPNOTSUPP
  41. {WsaError.WSAEOPNOTSUPP, LinuxError.EOPNOTSUPP},
  42. // WSAEPFNOSUPPORT
  43. {WsaError.WSAEPFNOSUPPORT, LinuxError.EPFNOSUPPORT},
  44. // WSAEAFNOSUPPORT
  45. {WsaError.WSAEAFNOSUPPORT, LinuxError.EAFNOSUPPORT},
  46. // WSAEADDRINUSE
  47. {WsaError.WSAEADDRINUSE, LinuxError.EADDRINUSE},
  48. // WSAEADDRNOTAVAIL
  49. {WsaError.WSAEADDRNOTAVAIL, LinuxError.EADDRNOTAVAIL},
  50. // WSAENETDOWN
  51. {WsaError.WSAENETDOWN, LinuxError.ENETDOWN},
  52. // WSAENETUNREACH
  53. {WsaError.WSAENETUNREACH, LinuxError.ENETUNREACH},
  54. // WSAENETRESET
  55. {WsaError.WSAENETRESET, LinuxError.ENETRESET},
  56. // WSAECONNABORTED
  57. {WsaError.WSAECONNABORTED, LinuxError.ECONNABORTED},
  58. // WSAECONNRESET
  59. {WsaError.WSAECONNRESET, LinuxError.ECONNRESET},
  60. // WSAENOBUFS
  61. {WsaError.WSAENOBUFS, LinuxError.ENOBUFS},
  62. // WSAEISCONN
  63. {WsaError.WSAEISCONN, LinuxError.EISCONN},
  64. // WSAENOTCONN
  65. {WsaError.WSAENOTCONN, LinuxError.ENOTCONN},
  66. // WSAESHUTDOWN
  67. {WsaError.WSAESHUTDOWN, LinuxError.ESHUTDOWN},
  68. // WSAETOOMANYREFS
  69. {WsaError.WSAETOOMANYREFS, LinuxError.ETOOMANYREFS},
  70. // WSAETIMEDOUT
  71. {WsaError.WSAETIMEDOUT, LinuxError.ETIMEDOUT},
  72. // WSAECONNREFUSED
  73. {WsaError.WSAECONNREFUSED, LinuxError.ECONNREFUSED},
  74. // WSAELOOP
  75. {WsaError.WSAELOOP, LinuxError.ELOOP},
  76. // WSAENAMETOOLONG
  77. {WsaError.WSAENAMETOOLONG, LinuxError.ENAMETOOLONG},
  78. // WSAEHOSTDOWN
  79. {WsaError.WSAEHOSTDOWN, LinuxError.EHOSTDOWN},
  80. // WSAEHOSTUNREACH
  81. {WsaError.WSAEHOSTUNREACH, LinuxError.EHOSTUNREACH},
  82. // WSAENOTEMPTY
  83. {WsaError.WSAENOTEMPTY, LinuxError.ENOTEMPTY},
  84. // WSAEUSERS
  85. {WsaError.WSAEUSERS, LinuxError.EUSERS},
  86. // WSAEDQUOT
  87. {WsaError.WSAEDQUOT, LinuxError.EDQUOT},
  88. // WSAESTALE
  89. {WsaError.WSAESTALE, LinuxError.ESTALE},
  90. // WSAEREMOTE
  91. {WsaError.WSAEREMOTE, LinuxError.EREMOTE},
  92. // WSAEINVAL
  93. {WsaError.WSAEINVAL, LinuxError.EINVAL},
  94. // WSAEFAULT
  95. {WsaError.WSAEFAULT, LinuxError.EFAULT},
  96. // NOERROR
  97. {0, 0}
  98. };
  99. private bool _isPrivileged;
  100. private List<BsdSocket> _sockets = new List<BsdSocket>();
  101. public IClient(ServiceCtx context, bool isPrivileged) : base(new ServerBase("BsdServer"))
  102. {
  103. _isPrivileged = isPrivileged;
  104. }
  105. private LinuxError ConvertError(WsaError errorCode)
  106. {
  107. if (!_errorMap.TryGetValue(errorCode, out LinuxError errno))
  108. {
  109. errno = (LinuxError)errorCode;
  110. }
  111. return errno;
  112. }
  113. private ResultCode WriteWinSock2Error(ServiceCtx context, WsaError errorCode)
  114. {
  115. return WriteBsdResult(context, -1, ConvertError(errorCode));
  116. }
  117. private ResultCode WriteBsdResult(ServiceCtx context, int result, LinuxError errorCode = 0)
  118. {
  119. if (errorCode != LinuxError.SUCCESS)
  120. {
  121. result = -1;
  122. }
  123. context.ResponseData.Write(result);
  124. context.ResponseData.Write((int)errorCode);
  125. return ResultCode.Success;
  126. }
  127. private BsdSocket RetrieveSocket(int socketFd)
  128. {
  129. if (socketFd >= 0 && _sockets.Count > socketFd)
  130. {
  131. return _sockets[socketFd];
  132. }
  133. return null;
  134. }
  135. private LinuxError SetResultErrno(Socket socket, int result)
  136. {
  137. return result == 0 && !socket.Blocking ? LinuxError.EWOULDBLOCK : LinuxError.SUCCESS;
  138. }
  139. private AddressFamily ConvertFromBsd(int domain)
  140. {
  141. if (domain == 2)
  142. {
  143. return AddressFamily.InterNetwork;
  144. }
  145. // FIXME: AF_ROUTE ignored, is that really needed?
  146. return AddressFamily.Unknown;
  147. }
  148. private ResultCode SocketInternal(ServiceCtx context, bool exempt)
  149. {
  150. AddressFamily domain = (AddressFamily)context.RequestData.ReadInt32();
  151. SocketType type = (SocketType)context.RequestData.ReadInt32();
  152. ProtocolType protocol = (ProtocolType)context.RequestData.ReadInt32();
  153. if (domain == AddressFamily.Unknown)
  154. {
  155. return WriteBsdResult(context, -1, LinuxError.EPROTONOSUPPORT);
  156. }
  157. else if ((type == SocketType.Seqpacket || type == SocketType.Raw) && !_isPrivileged)
  158. {
  159. if (domain != AddressFamily.InterNetwork || type != SocketType.Raw || protocol != ProtocolType.Icmp)
  160. {
  161. return WriteBsdResult(context, -1, LinuxError.ENOENT);
  162. }
  163. }
  164. BsdSocket newBsdSocket = new BsdSocket
  165. {
  166. Family = (int)domain,
  167. Type = (int)type,
  168. Protocol = (int)protocol,
  169. Handle = new Socket(domain, type, protocol)
  170. };
  171. _sockets.Add(newBsdSocket);
  172. if (exempt)
  173. {
  174. newBsdSocket.Handle.Disconnect(true);
  175. }
  176. return WriteBsdResult(context, _sockets.Count - 1);
  177. }
  178. private IPEndPoint ParseSockAddr(ServiceCtx context, long bufferPosition, long bufferSize)
  179. {
  180. int size = context.Memory.Read<byte>((ulong)bufferPosition);
  181. int family = context.Memory.Read<byte>((ulong)bufferPosition + 1);
  182. int port = BinaryPrimitives.ReverseEndianness(context.Memory.Read<ushort>((ulong)bufferPosition + 2));
  183. byte[] rawIp = new byte[4];
  184. context.Memory.Read((ulong)bufferPosition + 4, rawIp);
  185. return new IPEndPoint(new IPAddress(rawIp), port);
  186. }
  187. private void WriteSockAddr(ServiceCtx context, long bufferPosition, IPEndPoint endPoint)
  188. {
  189. context.Memory.Write((ulong)bufferPosition, (byte)0);
  190. context.Memory.Write((ulong)bufferPosition + 1, (byte)endPoint.AddressFamily);
  191. context.Memory.Write((ulong)bufferPosition + 2, BinaryPrimitives.ReverseEndianness((ushort)endPoint.Port));
  192. context.Memory.Write((ulong)bufferPosition + 4, endPoint.Address.GetAddressBytes());
  193. }
  194. private void WriteSockAddr(ServiceCtx context, long bufferPosition, BsdSocket socket, bool isRemote)
  195. {
  196. IPEndPoint endPoint = (isRemote ? socket.Handle.RemoteEndPoint : socket.Handle.LocalEndPoint) as IPEndPoint;
  197. WriteSockAddr(context, bufferPosition, endPoint);
  198. }
  199. [Command(0)]
  200. // Initialize(nn::socket::BsdBufferConfig config, u64 pid, u64 transferMemorySize, KObject<copy, transfer_memory>, pid) -> u32 bsd_errno
  201. public ResultCode RegisterClient(ServiceCtx context)
  202. {
  203. /*
  204. typedef struct {
  205. u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0.
  206. u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed).
  207. u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed).
  208. u32 tcp_tx_buf_max_size; // Maximum size of the TCP transfer (send) buffer. If it is 0, the size of the buffer is fixed to its initial value.
  209. u32 tcp_rx_buf_max_size; // Maximum size of the TCP receive buffer. If it is 0, the size of the buffer is fixed to its initial value.
  210. u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes).
  211. u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes).
  212. u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8).
  213. } BsdBufferConfig;
  214. */
  215. // bsd_error
  216. context.ResponseData.Write(0);
  217. Logger.Stub?.PrintStub(LogClass.ServiceBsd);
  218. return ResultCode.Success;
  219. }
  220. [Command(1)]
  221. // StartMonitoring(u64, pid)
  222. public ResultCode StartMonitoring(ServiceCtx context)
  223. {
  224. ulong unknown0 = context.RequestData.ReadUInt64();
  225. Logger.Stub?.PrintStub(LogClass.ServiceBsd, new { unknown0 });
  226. return ResultCode.Success;
  227. }
  228. [Command(2)]
  229. // Socket(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno)
  230. public ResultCode Socket(ServiceCtx context)
  231. {
  232. return SocketInternal(context, false);
  233. }
  234. [Command(3)]
  235. // SocketExempt(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno)
  236. public ResultCode SocketExempt(ServiceCtx context)
  237. {
  238. return SocketInternal(context, true);
  239. }
  240. [Command(4)]
  241. // Open(u32 flags, array<unknown, 0x21> path) -> (i32 ret, u32 bsd_errno)
  242. public ResultCode Open(ServiceCtx context)
  243. {
  244. (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21();
  245. int flags = context.RequestData.ReadInt32();
  246. byte[] rawPath = new byte[bufferSize];
  247. context.Memory.Read((ulong)bufferPosition, rawPath);
  248. string path = Encoding.ASCII.GetString(rawPath);
  249. WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
  250. Logger.Stub?.PrintStub(LogClass.ServiceBsd, new { path, flags });
  251. return ResultCode.Success;
  252. }
  253. [Command(5)]
  254. // Select(u32 nfds, nn::socket::timeout timeout, buffer<nn::socket::fd_set, 0x21, 0> readfds_in, buffer<nn::socket::fd_set, 0x21, 0> writefds_in, buffer<nn::socket::fd_set, 0x21, 0> errorfds_in) -> (i32 ret, u32 bsd_errno, buffer<nn::socket::fd_set, 0x22, 0> readfds_out, buffer<nn::socket::fd_set, 0x22, 0> writefds_out, buffer<nn::socket::fd_set, 0x22, 0> errorfds_out)
  255. public ResultCode Select(ServiceCtx context)
  256. {
  257. WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
  258. Logger.Stub?.PrintStub(LogClass.ServiceBsd);
  259. return ResultCode.Success;
  260. }
  261. [Command(6)]
  262. // Poll(u32 nfds, u32 timeout, buffer<unknown, 0x21, 0> fds) -> (i32 ret, u32 bsd_errno, buffer<unknown, 0x22, 0>)
  263. public ResultCode Poll(ServiceCtx context)
  264. {
  265. int fdsCount = context.RequestData.ReadInt32();
  266. int timeout = context.RequestData.ReadInt32();
  267. (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21();
  268. if (timeout < -1 || fdsCount < 0 || (fdsCount * 8) > bufferSize)
  269. {
  270. return WriteBsdResult(context, -1, LinuxError.EINVAL);
  271. }
  272. PollEvent[] events = new PollEvent[fdsCount];
  273. for (int i = 0; i < fdsCount; i++)
  274. {
  275. int socketFd = context.Memory.Read<int>((ulong)(bufferPosition + i * 8));
  276. BsdSocket socket = RetrieveSocket(socketFd);
  277. if (socket == null)
  278. {
  279. return WriteBsdResult(context, -1, LinuxError.EBADF);}
  280. PollEvent.EventTypeMask inputEvents = (PollEvent.EventTypeMask)context.Memory.Read<short>((ulong)(bufferPosition + i * 8 + 4));
  281. PollEvent.EventTypeMask outputEvents = (PollEvent.EventTypeMask)context.Memory.Read<short>((ulong)(bufferPosition + i * 8 + 6));
  282. events[i] = new PollEvent(socketFd, socket, inputEvents, outputEvents);
  283. }
  284. List<Socket> readEvents = new List<Socket>();
  285. List<Socket> writeEvents = new List<Socket>();
  286. List<Socket> errorEvents = new List<Socket>();
  287. foreach (PollEvent Event in events)
  288. {
  289. bool isValidEvent = false;
  290. if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0)
  291. {
  292. readEvents.Add(Event.Socket.Handle);
  293. errorEvents.Add(Event.Socket.Handle);
  294. isValidEvent = true;
  295. }
  296. if ((Event.InputEvents & PollEvent.EventTypeMask.UrgentInput) != 0)
  297. {
  298. readEvents.Add(Event.Socket.Handle);
  299. errorEvents.Add(Event.Socket.Handle);
  300. isValidEvent = true;
  301. }
  302. if ((Event.InputEvents & PollEvent.EventTypeMask.Output) != 0)
  303. {
  304. writeEvents.Add(Event.Socket.Handle);
  305. errorEvents.Add(Event.Socket.Handle);
  306. isValidEvent = true;
  307. }
  308. if ((Event.InputEvents & PollEvent.EventTypeMask.Error) != 0)
  309. {
  310. errorEvents.Add(Event.Socket.Handle);
  311. isValidEvent = true;
  312. }
  313. if (!isValidEvent)
  314. {
  315. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Poll input event type: {Event.InputEvents}");
  316. return WriteBsdResult(context, -1, LinuxError.EINVAL);
  317. }
  318. }
  319. if (fdsCount != 0)
  320. {
  321. try
  322. {
  323. System.Net.Sockets.Socket.Select(readEvents, writeEvents, errorEvents, timeout);
  324. }
  325. catch (SocketException exception)
  326. {
  327. return WriteWinSock2Error(context, (WsaError)exception.ErrorCode);
  328. }
  329. }
  330. else if (timeout == -1)
  331. {
  332. // FIXME: If we get a timeout of -1 and there is no fds to wait on, this should kill the KProces. (need to check that with re)
  333. throw new InvalidOperationException();
  334. }
  335. else
  336. {
  337. // FIXME: We should make the KThread sleep but we can't do much about it yet.
  338. Thread.Sleep(timeout);
  339. }
  340. for (int i = 0; i < fdsCount; i++)
  341. {
  342. PollEvent Event = events[i];
  343. context.Memory.Write((ulong)(bufferPosition + i * 8), Event.SocketFd);
  344. context.Memory.Write((ulong)(bufferPosition + i * 8 + 4), (short)Event.InputEvents);
  345. PollEvent.EventTypeMask outputEvents = 0;
  346. Socket socket = Event.Socket.Handle;
  347. if (errorEvents.Contains(socket))
  348. {
  349. outputEvents |= PollEvent.EventTypeMask.Error;
  350. if (!socket.Connected || !socket.IsBound)
  351. {
  352. outputEvents |= PollEvent.EventTypeMask.Disconnected;
  353. }
  354. }
  355. if (readEvents.Contains(socket))
  356. {
  357. if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0)
  358. {
  359. outputEvents |= PollEvent.EventTypeMask.Input;
  360. }
  361. }
  362. if (writeEvents.Contains(socket))
  363. {
  364. outputEvents |= PollEvent.EventTypeMask.Output;
  365. }
  366. context.Memory.Write((ulong)(bufferPosition + i * 8 + 6), (short)outputEvents);
  367. }
  368. return WriteBsdResult(context, readEvents.Count + writeEvents.Count + errorEvents.Count, LinuxError.SUCCESS);
  369. }
  370. [Command(7)]
  371. // Sysctl(buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>) -> (i32 ret, u32 bsd_errno, u32, buffer<unknown, 0x22, 0>)
  372. public ResultCode Sysctl(ServiceCtx context)
  373. {
  374. WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
  375. Logger.Stub?.PrintStub(LogClass.ServiceBsd);
  376. return ResultCode.Success;
  377. }
  378. [Command(8)]
  379. // Recv(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, array<i8, 0x22> message)
  380. public ResultCode Recv(ServiceCtx context)
  381. {
  382. int socketFd = context.RequestData.ReadInt32();
  383. SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
  384. (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22();
  385. LinuxError errno = LinuxError.EBADF;
  386. BsdSocket socket = RetrieveSocket(socketFd);
  387. int result = -1;
  388. if (socket != null)
  389. {
  390. if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0
  391. && (socketFlags & SocketFlags.Peek) == 0)
  392. {
  393. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}");
  394. return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
  395. }
  396. byte[] receivedBuffer = new byte[receiveLength];
  397. try
  398. {
  399. result = socket.Handle.Receive(receivedBuffer, socketFlags);
  400. errno = SetResultErrno(socket.Handle, result);
  401. context.Memory.Write((ulong)receivePosition, receivedBuffer);
  402. }
  403. catch (SocketException exception)
  404. {
  405. errno = ConvertError((WsaError)exception.ErrorCode);
  406. }
  407. }
  408. return WriteBsdResult(context, result, errno);
  409. }
  410. [Command(9)]
  411. // RecvFrom(u32 sock, u32 flags) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<i8, 0x22, 0> message, buffer<nn::socket::sockaddr_in, 0x22, 0x10>)
  412. public ResultCode RecvFrom(ServiceCtx context)
  413. {
  414. int socketFd = context.RequestData.ReadInt32();
  415. SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
  416. (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22();
  417. (long sockAddrOutPosition, long sockAddrOutSize) = context.Request.GetBufferType0x22(1);
  418. LinuxError errno = LinuxError.EBADF;
  419. BsdSocket socket = RetrieveSocket(socketFd);
  420. int result = -1;
  421. if (socket != null)
  422. {
  423. if (socketFlags != SocketFlags.None && (socketFlags & SocketFlags.OutOfBand) == 0
  424. && (socketFlags & SocketFlags.Peek) == 0)
  425. {
  426. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Recv flags: {socketFlags}");
  427. return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
  428. }
  429. byte[] receivedBuffer = new byte[receiveLength];
  430. EndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
  431. try
  432. {
  433. result = socket.Handle.ReceiveFrom(receivedBuffer, receivedBuffer.Length, socketFlags, ref endPoint);
  434. errno = SetResultErrno(socket.Handle, result);
  435. context.Memory.Write((ulong)receivePosition, receivedBuffer);
  436. WriteSockAddr(context, sockAddrOutPosition, (IPEndPoint)endPoint);
  437. }
  438. catch (SocketException exception)
  439. {
  440. errno = ConvertError((WsaError)exception.ErrorCode);
  441. }
  442. }
  443. return WriteBsdResult(context, result, errno);
  444. }
  445. [Command(10)]
  446. // Send(u32 socket, u32 flags, buffer<i8, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
  447. public ResultCode Send(ServiceCtx context)
  448. {
  449. int socketFd = context.RequestData.ReadInt32();
  450. SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
  451. (long sendPosition, long sendSize) = context.Request.GetBufferType0x21();
  452. LinuxError errno = LinuxError.EBADF;
  453. BsdSocket socket = RetrieveSocket(socketFd);
  454. int result = -1;
  455. if (socket != null)
  456. {
  457. if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand
  458. && socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute)
  459. {
  460. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}");
  461. return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
  462. }
  463. byte[] sendBuffer = new byte[sendSize];
  464. context.Memory.Read((ulong)sendPosition, sendBuffer);
  465. try
  466. {
  467. result = socket.Handle.Send(sendBuffer, socketFlags);
  468. errno = SetResultErrno(socket.Handle, result);
  469. }
  470. catch (SocketException exception)
  471. {
  472. errno = ConvertError((WsaError)exception.ErrorCode);
  473. }
  474. }
  475. return WriteBsdResult(context, result, errno);
  476. }
  477. [Command(11)]
  478. // SendTo(u32 socket, u32 flags, buffer<i8, 0x21, 0>, buffer<nn::socket::sockaddr_in, 0x21, 0x10>) -> (i32 ret, u32 bsd_errno)
  479. public ResultCode SendTo(ServiceCtx context)
  480. {
  481. int socketFd = context.RequestData.ReadInt32();
  482. SocketFlags socketFlags = (SocketFlags)context.RequestData.ReadInt32();
  483. (long sendPosition, long sendSize) = context.Request.GetBufferType0x21();
  484. (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(1);
  485. LinuxError errno = LinuxError.EBADF;
  486. BsdSocket socket = RetrieveSocket(socketFd);
  487. int result = -1;
  488. if (socket != null)
  489. {
  490. if (socketFlags != SocketFlags.None && socketFlags != SocketFlags.OutOfBand
  491. && socketFlags != SocketFlags.Peek && socketFlags != SocketFlags.DontRoute)
  492. {
  493. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Send flags: {socketFlags}");
  494. return WriteBsdResult(context, -1, LinuxError.EOPNOTSUPP);
  495. }
  496. byte[] sendBuffer = new byte[sendSize];
  497. context.Memory.Read((ulong)sendPosition, sendBuffer);
  498. EndPoint endPoint = ParseSockAddr(context, bufferPosition, bufferSize);
  499. try
  500. {
  501. result = socket.Handle.SendTo(sendBuffer, sendBuffer.Length, socketFlags, endPoint);
  502. errno = SetResultErrno(socket.Handle, result);
  503. }
  504. catch (SocketException exception)
  505. {
  506. errno = ConvertError((WsaError)exception.ErrorCode);
  507. }
  508. }
  509. return WriteBsdResult(context, result, errno);
  510. }
  511. [Command(12)]
  512. // Accept(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<nn::socket::sockaddr_in, 0x22, 0x10> addr)
  513. public ResultCode Accept(ServiceCtx context)
  514. {
  515. int socketFd = context.RequestData.ReadInt32();
  516. (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22();
  517. LinuxError errno = LinuxError.EBADF;
  518. BsdSocket socket = RetrieveSocket(socketFd);
  519. if (socket != null)
  520. {
  521. errno = LinuxError.SUCCESS;
  522. Socket newSocket = null;
  523. try
  524. {
  525. newSocket = socket.Handle.Accept();
  526. }
  527. catch (SocketException exception)
  528. {
  529. errno = ConvertError((WsaError)exception.ErrorCode);
  530. }
  531. if (newSocket == null && errno == LinuxError.SUCCESS)
  532. {
  533. errno = LinuxError.EWOULDBLOCK;
  534. }
  535. else if (errno == LinuxError.SUCCESS)
  536. {
  537. BsdSocket newBsdSocket = new BsdSocket
  538. {
  539. Family = (int)newSocket.AddressFamily,
  540. Type = (int)newSocket.SocketType,
  541. Protocol = (int)newSocket.ProtocolType,
  542. Handle = newSocket
  543. };
  544. _sockets.Add(newBsdSocket);
  545. WriteSockAddr(context, bufferPos, newBsdSocket, true);
  546. WriteBsdResult(context, _sockets.Count - 1, errno);
  547. context.ResponseData.Write(0x10);
  548. return ResultCode.Success;
  549. }
  550. }
  551. return WriteBsdResult(context, -1, errno);
  552. }
  553. [Command(13)]
  554. // Bind(u32 socket, buffer<nn::socket::sockaddr_in, 0x21, 0x10> addr) -> (i32 ret, u32 bsd_errno)
  555. public ResultCode Bind(ServiceCtx context)
  556. {
  557. int socketFd = context.RequestData.ReadInt32();
  558. (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21();
  559. LinuxError errno = LinuxError.EBADF;
  560. BsdSocket socket = RetrieveSocket(socketFd);
  561. if (socket != null)
  562. {
  563. errno = LinuxError.SUCCESS;
  564. try
  565. {
  566. IPEndPoint endPoint = ParseSockAddr(context, bufferPos, bufferSize);
  567. socket.Handle.Bind(endPoint);
  568. }
  569. catch (SocketException exception)
  570. {
  571. errno = ConvertError((WsaError)exception.ErrorCode);
  572. }
  573. }
  574. return WriteBsdResult(context, 0, errno);
  575. }
  576. [Command(14)]
  577. // Connect(u32 socket, buffer<nn::socket::sockaddr_in, 0x21, 0x10>) -> (i32 ret, u32 bsd_errno)
  578. public ResultCode Connect(ServiceCtx context)
  579. {
  580. int socketFd = context.RequestData.ReadInt32();
  581. (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21();
  582. LinuxError errno = LinuxError.EBADF;
  583. BsdSocket socket = RetrieveSocket(socketFd);
  584. if (socket != null)
  585. {
  586. errno = LinuxError.SUCCESS;
  587. try
  588. {
  589. IPEndPoint endPoint = ParseSockAddr(context, bufferPos, bufferSize);
  590. socket.Handle.Connect(endPoint);
  591. }
  592. catch (SocketException exception)
  593. {
  594. errno = ConvertError((WsaError)exception.ErrorCode);
  595. }
  596. }
  597. return WriteBsdResult(context, 0, errno);
  598. }
  599. [Command(15)]
  600. // GetPeerName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<nn::socket::sockaddr_in, 0x22, 0x10> addr)
  601. public ResultCode GetPeerName(ServiceCtx context)
  602. {
  603. int socketFd = context.RequestData.ReadInt32();
  604. (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22();
  605. LinuxError errno = LinuxError.EBADF;
  606. BsdSocket socket = RetrieveSocket(socketFd);
  607. if (socket != null)
  608. {
  609. errno = LinuxError.SUCCESS;
  610. WriteSockAddr(context, bufferPos, socket, true);
  611. WriteBsdResult(context, 0, errno);
  612. context.ResponseData.Write(0x10);
  613. }
  614. return WriteBsdResult(context, 0, errno);
  615. }
  616. [Command(16)]
  617. // GetSockName(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<nn::socket::sockaddr_in, 0x22, 0x10> addr)
  618. public ResultCode GetSockName(ServiceCtx context)
  619. {
  620. int socketFd = context.RequestData.ReadInt32();
  621. (long bufferPos, long bufferSize) = context.Request.GetBufferType0x22();
  622. LinuxError errno = LinuxError.EBADF;
  623. BsdSocket socket = RetrieveSocket(socketFd);
  624. if (socket != null)
  625. {
  626. errno = LinuxError.SUCCESS;
  627. WriteSockAddr(context, bufferPos, socket, false);
  628. WriteBsdResult(context, 0, errno);
  629. context.ResponseData.Write(0x10);
  630. }
  631. return WriteBsdResult(context, 0, errno);
  632. }
  633. [Command(17)]
  634. // GetSockOpt(u32 socket, u32 level, u32 option_name) -> (i32 ret, u32 bsd_errno, u32, buffer<unknown, 0x22, 0>)
  635. public ResultCode GetSockOpt(ServiceCtx context)
  636. {
  637. int socketFd = context.RequestData.ReadInt32();
  638. int level = context.RequestData.ReadInt32();
  639. int optionName = context.RequestData.ReadInt32();
  640. (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x22();
  641. LinuxError errno = LinuxError.EBADF;
  642. BsdSocket socket = RetrieveSocket(socketFd);
  643. if (socket != null)
  644. {
  645. errno = LinuxError.ENOPROTOOPT;
  646. if (level == 0xFFFF)
  647. {
  648. errno = HandleGetSocketOption(context, socket, (SocketOptionName)optionName, bufferPosition, bufferSize);
  649. }
  650. else
  651. {
  652. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported GetSockOpt Level: {(SocketOptionLevel)level}");
  653. }
  654. }
  655. return WriteBsdResult(context, 0, errno);
  656. }
  657. [Command(18)]
  658. // Listen(u32 socket, u32 backlog) -> (i32 ret, u32 bsd_errno)
  659. public ResultCode Listen(ServiceCtx context)
  660. {
  661. int socketFd = context.RequestData.ReadInt32();
  662. int backlog = context.RequestData.ReadInt32();
  663. LinuxError errno = LinuxError.EBADF;
  664. BsdSocket socket = RetrieveSocket(socketFd);
  665. if (socket != null)
  666. {
  667. errno = LinuxError.SUCCESS;
  668. try
  669. {
  670. socket.Handle.Listen(backlog);
  671. }
  672. catch (SocketException exception)
  673. {
  674. errno = ConvertError((WsaError)exception.ErrorCode);
  675. }
  676. }
  677. return WriteBsdResult(context, 0, errno);
  678. }
  679. [Command(19)]
  680. // Ioctl(u32 fd, u32 request, u32 bufcount, buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>, buffer<unknown, 0x21, 0>) -> (i32 ret, u32 bsd_errno, buffer<unknown, 0x22, 0>, buffer<unknown, 0x22, 0>, buffer<unknown, 0x22, 0>, buffer<unknown, 0x22, 0>)
  681. public ResultCode Ioctl(ServiceCtx context)
  682. {
  683. int socketFd = context.RequestData.ReadInt32();
  684. BsdIoctl cmd = (BsdIoctl)context.RequestData.ReadInt32();
  685. int bufferCount = context.RequestData.ReadInt32();
  686. LinuxError errno = LinuxError.EBADF;
  687. BsdSocket socket = RetrieveSocket(socketFd);
  688. if (socket != null)
  689. {
  690. switch (cmd)
  691. {
  692. case BsdIoctl.AtMark:
  693. errno = LinuxError.SUCCESS;
  694. (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x22();
  695. // FIXME: OOB not implemented.
  696. context.Memory.Write((ulong)bufferPosition, 0);
  697. break;
  698. default:
  699. errno = LinuxError.EOPNOTSUPP;
  700. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Ioctl Cmd: {cmd}");
  701. break;
  702. }
  703. }
  704. return WriteBsdResult(context, 0, errno);
  705. }
  706. [Command(20)]
  707. // Fcntl(u32 socket, u32 cmd, u32 arg) -> (i32 ret, u32 bsd_errno)
  708. public ResultCode Fcntl(ServiceCtx context)
  709. {
  710. int socketFd = context.RequestData.ReadInt32();
  711. int cmd = context.RequestData.ReadInt32();
  712. int arg = context.RequestData.ReadInt32();
  713. int result = 0;
  714. LinuxError errno = LinuxError.EBADF;
  715. BsdSocket socket = RetrieveSocket(socketFd);
  716. if (socket != null)
  717. {
  718. errno = LinuxError.SUCCESS;
  719. if (cmd == 0x3)
  720. {
  721. result = !socket.Handle.Blocking ? 0x800 : 0;
  722. }
  723. else if (cmd == 0x4 && arg == 0x800)
  724. {
  725. socket.Handle.Blocking = false;
  726. result = 0;
  727. }
  728. else
  729. {
  730. errno = LinuxError.EOPNOTSUPP;
  731. }
  732. }
  733. return WriteBsdResult(context, result, errno);
  734. }
  735. private LinuxError HandleGetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, long optionValuePosition, long optionValueSize)
  736. {
  737. try
  738. {
  739. byte[] optionValue = new byte[optionValueSize];
  740. switch (optionName)
  741. {
  742. case SocketOptionName.Broadcast:
  743. case SocketOptionName.DontLinger:
  744. case SocketOptionName.Debug:
  745. case SocketOptionName.Error:
  746. case SocketOptionName.KeepAlive:
  747. case SocketOptionName.OutOfBandInline:
  748. case SocketOptionName.ReceiveBuffer:
  749. case SocketOptionName.ReceiveTimeout:
  750. case SocketOptionName.SendBuffer:
  751. case SocketOptionName.SendTimeout:
  752. case SocketOptionName.Type:
  753. case SocketOptionName.Linger:
  754. socket.Handle.GetSocketOption(SocketOptionLevel.Socket, optionName, optionValue);
  755. context.Memory.Write((ulong)optionValuePosition, optionValue);
  756. return LinuxError.SUCCESS;
  757. case (SocketOptionName)0x200:
  758. socket.Handle.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue);
  759. context.Memory.Write((ulong)optionValuePosition, optionValue);
  760. return LinuxError.SUCCESS;
  761. default:
  762. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}");
  763. return LinuxError.EOPNOTSUPP;
  764. }
  765. }
  766. catch (SocketException exception)
  767. {
  768. return ConvertError((WsaError)exception.ErrorCode);
  769. }
  770. }
  771. private LinuxError HandleSetSocketOption(ServiceCtx context, BsdSocket socket, SocketOptionName optionName, long optionValuePosition, long optionValueSize)
  772. {
  773. try
  774. {
  775. switch (optionName)
  776. {
  777. case SocketOptionName.Broadcast:
  778. case SocketOptionName.DontLinger:
  779. case SocketOptionName.Debug:
  780. case SocketOptionName.Error:
  781. case SocketOptionName.KeepAlive:
  782. case SocketOptionName.OutOfBandInline:
  783. case SocketOptionName.ReceiveBuffer:
  784. case SocketOptionName.ReceiveTimeout:
  785. case SocketOptionName.SendBuffer:
  786. case SocketOptionName.SendTimeout:
  787. case SocketOptionName.Type:
  788. case SocketOptionName.ReuseAddress:
  789. socket.Handle.SetSocketOption(SocketOptionLevel.Socket, optionName, context.Memory.Read<int>((ulong)optionValuePosition));
  790. return LinuxError.SUCCESS;
  791. case (SocketOptionName)0x200:
  792. socket.Handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, context.Memory.Read<int>((ulong)optionValuePosition));
  793. return LinuxError.SUCCESS;
  794. case SocketOptionName.Linger:
  795. socket.Handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger,
  796. new LingerOption(context.Memory.Read<int>((ulong)optionValuePosition) != 0, context.Memory.Read<int>((ulong)optionValuePosition + 4)));
  797. return LinuxError.SUCCESS;
  798. default:
  799. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt OptionName: {optionName}");
  800. return LinuxError.EOPNOTSUPP;
  801. }
  802. }
  803. catch (SocketException exception)
  804. {
  805. return ConvertError((WsaError)exception.ErrorCode);
  806. }
  807. }
  808. [Command(21)]
  809. // SetSockOpt(u32 socket, u32 level, u32 option_name, buffer<unknown, 0x21, 0> option_value) -> (i32 ret, u32 bsd_errno)
  810. public ResultCode SetSockOpt(ServiceCtx context)
  811. {
  812. int socketFd = context.RequestData.ReadInt32();
  813. int level = context.RequestData.ReadInt32();
  814. int optionName = context.RequestData.ReadInt32();
  815. (long bufferPos, long bufferSize) = context.Request.GetBufferType0x21();
  816. LinuxError errno = LinuxError.EBADF;
  817. BsdSocket socket = RetrieveSocket(socketFd);
  818. if (socket != null)
  819. {
  820. errno = LinuxError.ENOPROTOOPT;
  821. if (level == 0xFFFF)
  822. {
  823. errno = HandleSetSocketOption(context, socket, (SocketOptionName)optionName, bufferPos, bufferSize);
  824. }
  825. else
  826. {
  827. Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported SetSockOpt Level: {(SocketOptionLevel)level}");
  828. }
  829. }
  830. return WriteBsdResult(context, 0, errno);
  831. }
  832. [Command(22)]
  833. // Shutdown(u32 socket, u32 how) -> (i32 ret, u32 bsd_errno)
  834. public ResultCode Shutdown(ServiceCtx context)
  835. {
  836. int socketFd = context.RequestData.ReadInt32();
  837. int how = context.RequestData.ReadInt32();
  838. LinuxError errno = LinuxError.EBADF;
  839. BsdSocket socket = RetrieveSocket(socketFd);
  840. if (socket != null)
  841. {
  842. errno = LinuxError.EINVAL;
  843. if (how >= 0 && how <= 2)
  844. {
  845. errno = LinuxError.SUCCESS;
  846. try
  847. {
  848. socket.Handle.Shutdown((SocketShutdown)how);
  849. }
  850. catch (SocketException exception)
  851. {
  852. errno = ConvertError((WsaError)exception.ErrorCode);
  853. }
  854. }
  855. }
  856. return WriteBsdResult(context, 0, errno);
  857. }
  858. [Command(23)]
  859. // ShutdownAllSockets(u32 how) -> (i32 ret, u32 bsd_errno)
  860. public ResultCode ShutdownAllSockets(ServiceCtx context)
  861. {
  862. int how = context.RequestData.ReadInt32();
  863. LinuxError errno = LinuxError.EINVAL;
  864. if (how >= 0 && how <= 2)
  865. {
  866. errno = LinuxError.SUCCESS;
  867. foreach (BsdSocket socket in _sockets)
  868. {
  869. if (socket != null)
  870. {
  871. try
  872. {
  873. socket.Handle.Shutdown((SocketShutdown)how);
  874. }
  875. catch (SocketException exception)
  876. {
  877. errno = ConvertError((WsaError)exception.ErrorCode);
  878. break;
  879. }
  880. }
  881. }
  882. }
  883. return WriteBsdResult(context, 0, errno);
  884. }
  885. [Command(24)]
  886. // Write(u32 socket, buffer<i8, 0x21, 0> message) -> (i32 ret, u32 bsd_errno)
  887. public ResultCode Write(ServiceCtx context)
  888. {
  889. int socketFd = context.RequestData.ReadInt32();
  890. (long sendPosition, long sendSize) = context.Request.GetBufferType0x21();
  891. LinuxError errno = LinuxError.EBADF;
  892. BsdSocket socket = RetrieveSocket(socketFd);
  893. int result = -1;
  894. if (socket != null)
  895. {
  896. byte[] sendBuffer = new byte[sendSize];
  897. context.Memory.Read((ulong)sendPosition, sendBuffer);
  898. try
  899. {
  900. result = socket.Handle.Send(sendBuffer);
  901. errno = SetResultErrno(socket.Handle, result);
  902. }
  903. catch (SocketException exception)
  904. {
  905. errno = ConvertError((WsaError)exception.ErrorCode);
  906. }
  907. }
  908. return WriteBsdResult(context, result, errno);
  909. }
  910. [Command(25)]
  911. // Read(u32 socket) -> (i32 ret, u32 bsd_errno, buffer<i8, 0x22, 0> message)
  912. public ResultCode Read(ServiceCtx context)
  913. {
  914. int socketFd = context.RequestData.ReadInt32();
  915. (long receivePosition, long receiveLength) = context.Request.GetBufferType0x22();
  916. LinuxError errno = LinuxError.EBADF;
  917. BsdSocket socket = RetrieveSocket(socketFd);
  918. int result = -1;
  919. if (socket != null)
  920. {
  921. byte[] receivedBuffer = new byte[receiveLength];
  922. try
  923. {
  924. result = socket.Handle.Receive(receivedBuffer);
  925. errno = SetResultErrno(socket.Handle, result);
  926. context.Memory.Write((ulong)receivePosition, receivedBuffer);
  927. }
  928. catch (SocketException exception)
  929. {
  930. errno = ConvertError((WsaError)exception.ErrorCode);
  931. }
  932. }
  933. return WriteBsdResult(context, result, errno);
  934. }
  935. [Command(26)]
  936. // Close(u32 socket) -> (i32 ret, u32 bsd_errno)
  937. public ResultCode Close(ServiceCtx context)
  938. {
  939. int socketFd = context.RequestData.ReadInt32();
  940. LinuxError errno = LinuxError.EBADF;
  941. BsdSocket socket = RetrieveSocket(socketFd);
  942. if (socket != null)
  943. {
  944. socket.Handle.Close();
  945. _sockets[socketFd] = null;
  946. errno = LinuxError.SUCCESS;
  947. }
  948. return WriteBsdResult(context, 0, errno);
  949. }
  950. [Command(27)]
  951. // DuplicateSocket(u32 socket, u64 reserved) -> (i32 ret, u32 bsd_errno)
  952. public ResultCode DuplicateSocket(ServiceCtx context)
  953. {
  954. int socketFd = context.RequestData.ReadInt32();
  955. ulong reserved = context.RequestData.ReadUInt64();
  956. LinuxError errno = LinuxError.ENOENT;
  957. int newSockFd = -1;
  958. if (_isPrivileged)
  959. {
  960. errno = LinuxError.EBADF;
  961. BsdSocket oldSocket = RetrieveSocket(socketFd);
  962. if (oldSocket != null)
  963. {
  964. _sockets.Add(oldSocket);
  965. newSockFd = _sockets.Count - 1;
  966. }
  967. }
  968. return WriteBsdResult(context, newSockFd, errno);
  969. }
  970. }
  971. }