IClient.cs 16 KB

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