ServiceBsd.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. using ChocolArm64.Memory;
  2. using Ryujinx.Core.OsHle.Ipc;
  3. using Ryujinx.Core.OsHle.Utilities;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using System.Threading.Tasks;
  10. namespace Ryujinx.Core.OsHle.Services.Bsd
  11. {
  12. //bsd_errno == (SocketException.ErrorCode - 10000)
  13. //https://github.com/freebsd/freebsd/blob/master/sys/sys/errno.h
  14. public enum BsdError
  15. {
  16. ENOTSOCK = 38, /* Socket operation on non-socket */
  17. EDESTADDRREQ = 39, /* Destination address required */
  18. EMSGSIZE = 40, /* Message too long */
  19. EPROTOTYPE = 41, /* Protocol wrong type for socket */
  20. ENOPROTOOPT = 42, /* Protocol not available */
  21. EPROTONOSUPPORT = 43, /* Protocol not supported */
  22. ESOCKTNOSUPPORT = 44, /* Socket type not supported */
  23. EOPNOTSUPP = 45, /* Operation not supported */
  24. EPFNOSUPPORT = 46, /* Protocol family not supported */
  25. EAFNOSUPPORT = 47, /* Address family not supported by protocol family */
  26. EADDRINUSE = 48, /* Address already in use */
  27. EADDRNOTAVAIL = 49, /* Can't assign requested address */
  28. ENETDOWN = 50, /* Network is down */
  29. ENETUNREACH = 51, /* Network is unreachable */
  30. ENETRESET = 52, /* Network dropped connection on reset */
  31. ECONNABORTED = 53, /* Software caused connection abort */
  32. ECONNRESET = 54, /* Connection reset by peer */
  33. ENOBUFS = 55, /* No buffer space available */
  34. EISCONN = 56, /* Socket is already connected */
  35. ENOTCONN = 57, /* Socket is not connected */
  36. ESHUTDOWN = 58, /* Can't send after socket shutdown */
  37. ETOOMANYREFS = 59, /* Too many references: can't splice */
  38. ETIMEDOUT = 60, /* Operation timed out */
  39. ECONNREFUSED = 61 /* Connection refused */
  40. }
  41. class SocketBsd
  42. {
  43. public int Family;
  44. public int Type;
  45. public int Protocol;
  46. public IPAddress IpAddress;
  47. public IPEndPoint RemoteEP;
  48. public Socket Handle;
  49. }
  50. class ServiceBsd : IpcService
  51. {
  52. private Dictionary<int, ServiceProcessRequest> m_Commands;
  53. public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
  54. private List<SocketBsd> Sockets = new List<SocketBsd>();
  55. public ServiceBsd()
  56. {
  57. m_Commands = new Dictionary<int, ServiceProcessRequest>()
  58. {
  59. { 0, Initialize },
  60. { 1, StartMonitoring },
  61. { 2, Socket },
  62. { 6, Poll },
  63. { 8, Recv },
  64. { 10, Send },
  65. { 11, SendTo },
  66. { 12, Accept },
  67. { 13, Bind },
  68. { 14, Connect },
  69. { 18, Listen },
  70. { 21, SetSockOpt },
  71. { 26, Close }
  72. };
  73. }
  74. //(u32, u32, u32, u32, u32, u32, u32, u32, u64 pid, u64 transferMemorySize, pid, KObject) -> u32 bsd_errno
  75. public long Initialize(ServiceCtx Context)
  76. {
  77. /*
  78. typedef struct {
  79. u32 version; // Observed 1 on 2.0 LibAppletWeb, 2 on 3.0.
  80. u32 tcp_tx_buf_size; // Size of the TCP transfer (send) buffer (initial or fixed).
  81. u32 tcp_rx_buf_size; // Size of the TCP recieve buffer (initial or fixed).
  82. 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.
  83. 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.
  84. u32 udp_tx_buf_size; // Size of the UDP transfer (send) buffer (typically 0x2400 bytes).
  85. u32 udp_rx_buf_size; // Size of the UDP receive buffer (typically 0xA500 bytes).
  86. u32 sb_efficiency; // Number of buffers for each socket (standard values range from 1 to 8).
  87. } BsdBufferConfig;
  88. */
  89. long Pid = Context.RequestData.ReadInt64();
  90. long TransferMemorySize = Context.RequestData.ReadInt64();
  91. // Two other args are unknown!
  92. Context.ResponseData.Write(0);
  93. //Todo: Stub
  94. return 0;
  95. }
  96. //(u64, pid)
  97. public long StartMonitoring(ServiceCtx Context)
  98. {
  99. //Todo: Stub
  100. return 0;
  101. }
  102. //(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno)
  103. public long Socket(ServiceCtx Context)
  104. {
  105. SocketBsd NewBSDSocket = new SocketBsd
  106. {
  107. Family = Context.RequestData.ReadInt32(),
  108. Type = Context.RequestData.ReadInt32(),
  109. Protocol = Context.RequestData.ReadInt32()
  110. };
  111. Sockets.Add(NewBSDSocket);
  112. Sockets[Sockets.Count - 1].Handle = new Socket((AddressFamily)Sockets[Sockets.Count - 1].Family,
  113. (SocketType)Sockets[Sockets.Count - 1].Type,
  114. (ProtocolType)Sockets[Sockets.Count - 1].Protocol);
  115. Context.ResponseData.Write(Sockets.Count - 1);
  116. Context.ResponseData.Write(0);
  117. return 0;
  118. }
  119. //(u32, u32, buffer<unknown, 0x21, 0>) -> (i32 ret, u32 bsd_errno, buffer<unknown, 0x22, 0>)
  120. public long Poll(ServiceCtx Context)
  121. {
  122. int PollCount = Context.RequestData.ReadInt32();
  123. int TimeOut = Context.RequestData.ReadInt32();
  124. //https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/poll.h
  125. //https://msdn.microsoft.com/fr-fr/library/system.net.sockets.socket.poll(v=vs.110).aspx
  126. //https://github.com/switchbrew/libnx/blob/e0457c4534b3c37426d83e1a620f82cb28c3b528/nx/source/services/bsd.c#L343
  127. //https://github.com/TuxSH/ftpd/blob/switch_pr/source/ftp.c#L1634
  128. //https://linux.die.net/man/2/poll
  129. byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
  130. Context.Request.SendBuff[0].Position,
  131. Context.Request.SendBuff[0].Size);
  132. int SocketId = Get32(SentBuffer, 0);
  133. short RequestedEvents = (short)Get16(SentBuffer, 4);
  134. short ReturnedEvents = (short)Get16(SentBuffer, 6);
  135. //Todo: Stub - Need to implemented the Type-22 buffer.
  136. Context.ResponseData.Write(1);
  137. Context.ResponseData.Write(0);
  138. return 0;
  139. }
  140. //(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, buffer<i8, 0x22, 0> message)
  141. public long Recv(ServiceCtx Context)
  142. {
  143. try
  144. {
  145. int SocketId = Context.RequestData.ReadInt32();
  146. int SocketFlags = Context.RequestData.ReadInt32();
  147. byte[] ReceivedBuffer = new byte[Context.Request.ReceiveBuff[0].Size];
  148. int ReadedBytes = Sockets[SocketId].Handle.Receive(ReceivedBuffer);
  149. //Logging.Debug("Received Buffer:" + Environment.NewLine + Logging.HexDump(ReceivedBuffer));
  150. AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, ReceivedBuffer);
  151. Context.ResponseData.Write(ReadedBytes);
  152. Context.ResponseData.Write(0);
  153. }
  154. catch (SocketException Ex)
  155. {
  156. Context.ResponseData.Write(-1);
  157. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  158. }
  159. return 0;
  160. }
  161. //(u32 socket, u32 flags, buffer<i8, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
  162. public long Send(ServiceCtx Context)
  163. {
  164. int SocketId = Context.RequestData.ReadInt32();
  165. int SocketFlags = Context.RequestData.ReadInt32();
  166. byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
  167. Context.Request.SendBuff[0].Position,
  168. Context.Request.SendBuff[0].Size);
  169. try
  170. {
  171. //Logging.Debug("Sended Buffer:" + Environment.NewLine + Logging.HexDump(SendedBuffer));
  172. int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
  173. Context.ResponseData.Write(BytesSent);
  174. Context.ResponseData.Write(0);
  175. }
  176. catch (SocketException Ex)
  177. {
  178. Context.ResponseData.Write(-1);
  179. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  180. }
  181. return 0;
  182. }
  183. //(u32 socket, u32 flags, buffer<i8, 0x21, 0>, buffer<sockaddr, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
  184. public long SendTo(ServiceCtx Context)
  185. {
  186. int SocketId = Context.RequestData.ReadInt32();
  187. int SocketFlags = Context.RequestData.ReadInt32();
  188. byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
  189. Context.Request.SendBuff[0].Position,
  190. Context.Request.SendBuff[0].Size);
  191. byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
  192. Context.Request.SendBuff[1].Position,
  193. Context.Request.SendBuff[1].Size);
  194. if (!Sockets[SocketId].Handle.Connected)
  195. {
  196. try
  197. {
  198. ParseAddrBuffer(SocketId, AddressBuffer);
  199. Sockets[SocketId].Handle.Connect(Sockets[SocketId].RemoteEP);
  200. }
  201. catch (SocketException Ex)
  202. {
  203. Context.ResponseData.Write(-1);
  204. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  205. }
  206. }
  207. try
  208. {
  209. //Logging.Debug("Sended Buffer:" + Environment.NewLine + Logging.HexDump(SendedBuffer));
  210. int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
  211. Context.ResponseData.Write(BytesSent);
  212. Context.ResponseData.Write(0);
  213. }
  214. catch (SocketException Ex)
  215. {
  216. Context.ResponseData.Write(-1);
  217. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  218. }
  219. return 0;
  220. }
  221. //(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<sockaddr, 0x22, 0> addr)
  222. public long Accept(ServiceCtx Context)
  223. {
  224. int SocketId = Context.RequestData.ReadInt32();
  225. long AddrBufferPtr = Context.Request.ReceiveBuff[0].Position;
  226. Socket HandleAccept = null;
  227. var TimeOut = Task.Factory.StartNew(() =>
  228. {
  229. try
  230. {
  231. HandleAccept = Sockets[SocketId].Handle.Accept();
  232. }
  233. catch (SocketException Ex)
  234. {
  235. Context.ResponseData.Write(-1);
  236. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  237. }
  238. });
  239. TimeOut.Wait(10000);
  240. if (HandleAccept != null)
  241. {
  242. SocketBsd NewBSDSocket = new SocketBsd
  243. {
  244. IpAddress = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint).Address,
  245. RemoteEP = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint),
  246. Handle = HandleAccept
  247. };
  248. Sockets.Add(NewBSDSocket);
  249. using (MemoryStream MS = new MemoryStream())
  250. {
  251. BinaryWriter Writer = new BinaryWriter(MS);
  252. Writer.Write((byte)0);
  253. Writer.Write((byte)Sockets[Sockets.Count - 1].Handle.AddressFamily);
  254. Writer.Write((Int16)((IPEndPoint)Sockets[Sockets.Count - 1].Handle.LocalEndPoint).Port);
  255. string[] IpAdress = Sockets[Sockets.Count - 1].IpAddress.ToString().Split('.');
  256. Writer.Write(byte.Parse(IpAdress[0]));
  257. Writer.Write(byte.Parse(IpAdress[1]));
  258. Writer.Write(byte.Parse(IpAdress[2]));
  259. Writer.Write(byte.Parse(IpAdress[3]));
  260. AMemoryHelper.WriteBytes(Context.Memory, AddrBufferPtr, MS.ToArray());
  261. Context.ResponseData.Write(Sockets.Count - 1);
  262. Context.ResponseData.Write(0);
  263. Context.ResponseData.Write(MS.Length);
  264. }
  265. }
  266. else
  267. {
  268. Context.ResponseData.Write(-1);
  269. Context.ResponseData.Write((int)BsdError.ETIMEDOUT);
  270. }
  271. return 0;
  272. }
  273. //(u32 socket, buffer<sockaddr, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
  274. public long Bind(ServiceCtx Context)
  275. {
  276. int SocketId = Context.RequestData.ReadInt32();
  277. byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
  278. Context.Request.SendBuff[0].Position,
  279. Context.Request.SendBuff[0].Size);
  280. try
  281. {
  282. ParseAddrBuffer(SocketId, AddressBuffer);
  283. Context.ResponseData.Write(0);
  284. Context.ResponseData.Write(0);
  285. }
  286. catch (SocketException Ex)
  287. {
  288. Context.ResponseData.Write(-1);
  289. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  290. }
  291. return 0;
  292. }
  293. //(u32 socket, buffer<sockaddr, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
  294. public long Connect(ServiceCtx Context)
  295. {
  296. int SocketId = Context.RequestData.ReadInt32();
  297. byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
  298. Context.Request.SendBuff[0].Position,
  299. Context.Request.SendBuff[0].Size);
  300. try
  301. {
  302. ParseAddrBuffer(SocketId, AddressBuffer);
  303. Sockets[SocketId].Handle.Connect(Sockets[SocketId].RemoteEP);
  304. Context.ResponseData.Write(0);
  305. Context.ResponseData.Write(0);
  306. }
  307. catch (SocketException Ex)
  308. {
  309. Context.ResponseData.Write(-1);
  310. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  311. }
  312. return 0;
  313. }
  314. //(u32 socket, u32 backlog) -> (i32 ret, u32 bsd_errno)
  315. public long Listen(ServiceCtx Context)
  316. {
  317. int SocketId = Context.RequestData.ReadInt32();
  318. int BackLog = Context.RequestData.ReadInt32();
  319. try
  320. {
  321. Sockets[SocketId].Handle.Bind(Sockets[SocketId].RemoteEP);
  322. Sockets[SocketId].Handle.Listen(BackLog);
  323. Context.ResponseData.Write(0);
  324. Context.ResponseData.Write(0);
  325. }
  326. catch (SocketException Ex)
  327. {
  328. Context.ResponseData.Write(-1);
  329. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  330. }
  331. return 0;
  332. }
  333. //(u32 socket, u32 level, u32 option_name, buffer<unknown, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
  334. public long SetSockOpt(ServiceCtx Context)
  335. {
  336. int SocketId = Context.RequestData.ReadInt32();
  337. int SocketLevel = Context.RequestData.ReadInt32();
  338. int SocketOptionName = Context.RequestData.ReadInt32();
  339. byte[] SocketOptionValue = AMemoryHelper.ReadBytes(Context.Memory,
  340. Context.Request.PtrBuff[0].Position,
  341. Context.Request.PtrBuff[0].Size);
  342. try
  343. {
  344. Sockets[SocketId].Handle.SetSocketOption((SocketOptionLevel)SocketLevel,
  345. (SocketOptionName)SocketOptionName,
  346. Get32(SocketOptionValue, 0));
  347. Context.ResponseData.Write(0);
  348. Context.ResponseData.Write(0);
  349. }
  350. catch (SocketException Ex)
  351. {
  352. Context.ResponseData.Write(-1);
  353. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  354. }
  355. return 0;
  356. }
  357. //(u32 socket) -> (i32 ret, u32 bsd_errno)
  358. public long Close(ServiceCtx Context)
  359. {
  360. int SocketId = Context.RequestData.ReadInt32();
  361. try
  362. {
  363. Sockets[SocketId].Handle.Close();
  364. Sockets[SocketId] = null;
  365. Context.ResponseData.Write(0);
  366. Context.ResponseData.Write(0);
  367. }
  368. catch (SocketException Ex)
  369. {
  370. Context.ResponseData.Write(-1);
  371. Context.ResponseData.Write(Ex.ErrorCode - 10000);
  372. }
  373. return 0;
  374. }
  375. public void ParseAddrBuffer(int SocketId, byte[] AddrBuffer)
  376. {
  377. using (MemoryStream MS = new MemoryStream(AddrBuffer))
  378. {
  379. BinaryReader Reader = new BinaryReader(MS);
  380. int Size = Reader.ReadByte();
  381. int Family = Reader.ReadByte();
  382. int Port = EndianSwap.Swap16(Reader.ReadInt16());
  383. string IpAddress = Reader.ReadByte().ToString() +
  384. "." + Reader.ReadByte().ToString() +
  385. "." + Reader.ReadByte().ToString() +
  386. "." + Reader.ReadByte().ToString();
  387. Logging.Debug($"Try to connect to {IpAddress}:{Port}");
  388. Sockets[SocketId].IpAddress = IPAddress.Parse(IpAddress);
  389. Sockets[SocketId].RemoteEP = new IPEndPoint(Sockets[SocketId].IpAddress, Port);
  390. }
  391. }
  392. private int Get16(byte[] Data, int Address)
  393. {
  394. return
  395. Data[Address + 0] << 0 |
  396. Data[Address + 1] << 8;
  397. }
  398. private int Get32(byte[] Data, int Address)
  399. {
  400. return
  401. Data[Address + 0] << 0 |
  402. Data[Address + 1] << 8 |
  403. Data[Address + 2] << 16 |
  404. Data[Address + 3] << 24;
  405. }
  406. }
  407. }