sys-socket.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /*
  2. * <sys/socket.h> wrapper functions.
  3. *
  4. * Authors:
  5. * Steffen Kiess ([email protected])
  6. *
  7. * Copyright (C) 2015 Steffen Kiess
  8. */
  9. #include <sys/socket.h>
  10. #include <sys/time.h>
  11. #include <netinet/in.h>
  12. #include <sys/un.h>
  13. #include <unistd.h>
  14. #include <stddef.h>
  15. #include "map.h"
  16. #include "mph.h"
  17. #include "sys-uio.h"
  18. G_BEGIN_DECLS
  19. int
  20. Mono_Posix_SockaddrStorage_get_size (void)
  21. {
  22. return sizeof (struct sockaddr_storage);
  23. }
  24. int
  25. Mono_Posix_SockaddrUn_get_sizeof_sun_path (void)
  26. {
  27. struct sockaddr_un sun;
  28. return sizeof (sun.sun_path);
  29. }
  30. int
  31. Mono_Posix_Cmsghdr_getsize (void)
  32. {
  33. return sizeof (struct cmsghdr);
  34. }
  35. int
  36. Mono_Posix_FromInAddr (struct Mono_Posix_InAddr* source, void* destination)
  37. {
  38. memcpy (&((struct in_addr*)destination)->s_addr, &source->s_addr, 4);
  39. return 0;
  40. }
  41. int
  42. Mono_Posix_ToInAddr (void* source, struct Mono_Posix_InAddr* destination)
  43. {
  44. memcpy (&destination->s_addr, &((struct in_addr*)source)->s_addr, 4);
  45. return 0;
  46. }
  47. int
  48. Mono_Posix_FromIn6Addr (struct Mono_Posix_In6Addr* source, void* destination)
  49. {
  50. memcpy (&((struct in6_addr*)destination)->s6_addr, &source->addr0, 16);
  51. return 0;
  52. }
  53. int
  54. Mono_Posix_ToIn6Addr (void* source, struct Mono_Posix_In6Addr* destination)
  55. {
  56. memcpy (&destination->addr0, &((struct in6_addr*)source)->s6_addr, 16);
  57. return 0;
  58. }
  59. int
  60. Mono_Posix_Syscall_socketpair (int domain, int type, int protocol, int* socket1, int* socket2)
  61. {
  62. int filedes[2] = {-1, -1};
  63. int r;
  64. r = socketpair (domain, type, protocol, filedes);
  65. *socket1 = filedes[0];
  66. *socket2 = filedes[1];
  67. return r;
  68. }
  69. int
  70. Mono_Posix_Syscall_getsockopt (int socket, int level, int option_name, void* option_value, gint64* option_len)
  71. {
  72. socklen_t len;
  73. int r;
  74. mph_return_if_socklen_t_overflow (*option_len);
  75. len = *option_len;
  76. r = getsockopt (socket, level, option_name, option_value, &len);
  77. *option_len = len;
  78. return r;
  79. }
  80. int
  81. Mono_Posix_Syscall_getsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
  82. {
  83. struct timeval tv;
  84. int r;
  85. socklen_t size;
  86. size = sizeof (struct timeval);
  87. r = getsockopt (socket, level, option_name, &tv, &size);
  88. if (r != -1 && size == sizeof (struct timeval)) {
  89. if (Mono_Posix_ToTimeval (&tv, option_value) != 0)
  90. return -1;
  91. } else {
  92. memset (option_value, 0, sizeof (struct Mono_Posix_Timeval));
  93. if (r != -1)
  94. errno = EINVAL;
  95. }
  96. return r;
  97. }
  98. int
  99. Mono_Posix_Syscall_getsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
  100. {
  101. struct linger ling;
  102. int r;
  103. socklen_t size;
  104. size = sizeof (struct linger);
  105. r = getsockopt (socket, level, option_name, &ling, &size);
  106. if (r != -1 && size == sizeof (struct linger)) {
  107. if (Mono_Posix_ToLinger (&ling, option_value) != 0)
  108. return -1;
  109. } else {
  110. memset (option_value, 0, sizeof (struct Mono_Posix_Linger));
  111. if (r != -1)
  112. errno = EINVAL;
  113. }
  114. return r;
  115. }
  116. int
  117. Mono_Posix_Syscall_setsockopt (int socket, int level, int option_name, void* option_value, gint64 option_len)
  118. {
  119. mph_return_if_socklen_t_overflow (option_len);
  120. return setsockopt (socket, level, option_name, option_value, option_len);
  121. }
  122. int
  123. Mono_Posix_Syscall_setsockopt_timeval (int socket, int level, int option_name, struct Mono_Posix_Timeval* option_value)
  124. {
  125. struct timeval tv;
  126. if (Mono_Posix_FromTimeval (option_value, &tv) != 0)
  127. return -1;
  128. return setsockopt (socket, level, option_name, &tv, sizeof (struct timeval));
  129. }
  130. int
  131. Mono_Posix_Syscall_setsockopt_linger (int socket, int level, int option_name, struct Mono_Posix_Linger* option_value)
  132. {
  133. struct linger ling;
  134. if (Mono_Posix_FromLinger (option_value, &ling) != 0)
  135. return -1;
  136. return setsockopt (socket, level, option_name, &ling, sizeof (struct linger));
  137. }
  138. static int
  139. get_addrlen (struct Mono_Posix__SockaddrHeader* address, socklen_t* addrlen)
  140. {
  141. if (!address) {
  142. *addrlen = 0;
  143. return 0;
  144. }
  145. switch (address->type) {
  146. case Mono_Posix_SockaddrType_SockaddrStorage:
  147. mph_return_if_socklen_t_overflow (((struct Mono_Posix__SockaddrDynamic*) address)->len);
  148. *addrlen = ((struct Mono_Posix__SockaddrDynamic*) address)->len;
  149. return 0;
  150. case Mono_Posix_SockaddrType_SockaddrUn:
  151. mph_return_if_socklen_t_overflow (offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len);
  152. *addrlen = offsetof (struct sockaddr_un, sun_path) + ((struct Mono_Posix__SockaddrDynamic*) address)->len;
  153. return 0;
  154. case Mono_Posix_SockaddrType_Sockaddr: *addrlen = sizeof (struct sockaddr); return 0;
  155. case Mono_Posix_SockaddrType_SockaddrIn: *addrlen = sizeof (struct sockaddr_in); return 0;
  156. case Mono_Posix_SockaddrType_SockaddrIn6: *addrlen = sizeof (struct sockaddr_in6); return 0;
  157. default:
  158. *addrlen = 0;
  159. errno = EINVAL;
  160. return -1;
  161. }
  162. }
  163. int
  164. Mono_Posix_Sockaddr_GetNativeSize (struct Mono_Posix__SockaddrHeader* address, gint64* size)
  165. {
  166. socklen_t value;
  167. int r;
  168. r = get_addrlen (address, &value);
  169. *size = value;
  170. return r;
  171. }
  172. int
  173. Mono_Posix_FromSockaddr (struct Mono_Posix__SockaddrHeader* source, void* destination)
  174. {
  175. if (!source)
  176. return 0;
  177. switch (source->type) {
  178. case Mono_Posix_SockaddrType_SockaddrStorage:
  179. // Do nothing, don't copy source->sa_family into addr->sa_family
  180. return 0;
  181. case Mono_Posix_SockaddrType_SockaddrUn:
  182. memcpy (((struct sockaddr_un*) destination)->sun_path, ((struct Mono_Posix__SockaddrDynamic*) source)->data, ((struct Mono_Posix__SockaddrDynamic*) source)->len);
  183. break;
  184. case Mono_Posix_SockaddrType_Sockaddr:
  185. break;
  186. case Mono_Posix_SockaddrType_SockaddrIn:
  187. if (Mono_Posix_FromSockaddrIn ((struct Mono_Posix_SockaddrIn*) source, (struct sockaddr_in*) destination) != 0)
  188. return -1;
  189. break;
  190. case Mono_Posix_SockaddrType_SockaddrIn6:
  191. if (Mono_Posix_FromSockaddrIn6 ((struct Mono_Posix_SockaddrIn6*) source, (struct sockaddr_in6*) destination) != 0)
  192. return -1;
  193. break;
  194. default:
  195. errno = EINVAL;
  196. return -1;
  197. }
  198. int family;
  199. if (Mono_Posix_FromUnixAddressFamily (source->sa_family, &family) != 0)
  200. return -1;
  201. ((struct sockaddr*) destination)->sa_family = family;
  202. return 0;
  203. }
  204. int
  205. Mono_Posix_ToSockaddr (void* source, gint64 size, struct Mono_Posix__SockaddrHeader* destination)
  206. {
  207. struct Mono_Posix__SockaddrDynamic* destination_dyn;
  208. if (!destination)
  209. return 0;
  210. switch (destination->type) {
  211. case Mono_Posix_SockaddrType_Sockaddr:
  212. if (size < offsetof (struct sockaddr, sa_family) + sizeof (sa_family_t)) {
  213. errno = ENOBUFS;
  214. return -1;
  215. }
  216. break;
  217. case Mono_Posix_SockaddrType_SockaddrStorage:
  218. destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
  219. if (size > destination_dyn->len) {
  220. errno = ENOBUFS;
  221. return -1;
  222. }
  223. destination_dyn->len = size;
  224. break;
  225. case Mono_Posix_SockaddrType_SockaddrUn:
  226. destination_dyn = ((struct Mono_Posix__SockaddrDynamic*) destination);
  227. if (size - offsetof (struct sockaddr_un, sun_path) > destination_dyn->len) {
  228. errno = ENOBUFS;
  229. return -1;
  230. }
  231. destination_dyn->len = size - offsetof (struct sockaddr_un, sun_path);
  232. memcpy (destination_dyn->data, ((struct sockaddr_un*) source)->sun_path, size);
  233. break;
  234. case Mono_Posix_SockaddrType_SockaddrIn:
  235. if (size != sizeof (struct sockaddr_in)) {
  236. errno = ENOBUFS;
  237. return -1;
  238. }
  239. if (Mono_Posix_ToSockaddrIn ((struct sockaddr_in*) source, (struct Mono_Posix_SockaddrIn*) destination) != 0)
  240. return -1;
  241. break;
  242. case Mono_Posix_SockaddrType_SockaddrIn6:
  243. if (size != sizeof (struct sockaddr_in6)) {
  244. errno = ENOBUFS;
  245. return -1;
  246. }
  247. if (Mono_Posix_ToSockaddrIn6 ((struct sockaddr_in6*) source, (struct Mono_Posix_SockaddrIn6*) destination) != 0)
  248. return -1;
  249. break;
  250. default:
  251. errno = EINVAL;
  252. return -1;
  253. }
  254. if (Mono_Posix_ToUnixAddressFamily (((struct sockaddr*) source)->sa_family, &destination->sa_family) != 0)
  255. destination->sa_family = Mono_Posix_UnixAddressFamily_Unknown;
  256. return 0;
  257. }
  258. // Macro for allocating space for the native sockaddr_* structure
  259. // Must be a macro because it is using alloca()
  260. #define ALLOC_SOCKADDR \
  261. socklen_t addrlen; \
  262. struct sockaddr* addr; \
  263. gboolean need_free = 0; \
  264. \
  265. if (get_addrlen (address, &addrlen) != 0) \
  266. return -1; \
  267. if (address == NULL) { \
  268. addr = NULL; \
  269. } else if (address->type == Mono_Posix_SockaddrType_SockaddrStorage) { \
  270. addr = (struct sockaddr*) ((struct Mono_Posix__SockaddrDynamic*) address)->data; \
  271. } else if (address->type == Mono_Posix_SockaddrType_SockaddrUn) { \
  272. /* Use alloca() for up to 2048 bytes, use malloc() otherwise */ \
  273. need_free = addrlen > 2048; \
  274. addr = need_free ? malloc (addrlen) : alloca (addrlen); \
  275. if (!addr) \
  276. return -1; \
  277. } else { \
  278. addr = alloca (addrlen); \
  279. }
  280. int
  281. Mono_Posix_Syscall_bind (int socket, struct Mono_Posix__SockaddrHeader* address)
  282. {
  283. int r;
  284. ALLOC_SOCKADDR
  285. if (Mono_Posix_FromSockaddr (address, addr) != 0) {
  286. if (need_free)
  287. free (addr);
  288. return -1;
  289. }
  290. r = bind (socket, addr, addrlen);
  291. if (need_free)
  292. free (addr);
  293. return r;
  294. }
  295. int
  296. Mono_Posix_Syscall_connect (int socket, struct Mono_Posix__SockaddrHeader* address)
  297. {
  298. int r;
  299. ALLOC_SOCKADDR
  300. if (Mono_Posix_FromSockaddr (address, addr) != 0) {
  301. if (need_free)
  302. free (addr);
  303. return -1;
  304. }
  305. r = connect (socket, addr, addrlen);
  306. if (need_free)
  307. free (addr);
  308. return r;
  309. }
  310. int
  311. Mono_Posix_Syscall_accept (int socket, struct Mono_Posix__SockaddrHeader* address)
  312. {
  313. int r;
  314. ALLOC_SOCKADDR
  315. r = accept (socket, addr, &addrlen);
  316. if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
  317. close (r);
  318. r = -1;
  319. }
  320. if (need_free)
  321. free (addr);
  322. return r;
  323. }
  324. #ifdef HAVE_ACCEPT4
  325. int
  326. Mono_Posix_Syscall_accept4 (int socket, struct Mono_Posix__SockaddrHeader* address, int flags)
  327. {
  328. int r;
  329. ALLOC_SOCKADDR
  330. r = accept4 (socket, addr, &addrlen, flags);
  331. if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0) {
  332. close (r);
  333. r = -1;
  334. }
  335. if (need_free)
  336. free (addr);
  337. return r;
  338. }
  339. #endif
  340. int
  341. Mono_Posix_Syscall_getpeername (int socket, struct Mono_Posix__SockaddrHeader* address)
  342. {
  343. int r;
  344. ALLOC_SOCKADDR
  345. r = getpeername (socket, addr, &addrlen);
  346. if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
  347. r = -1;
  348. if (need_free)
  349. free (addr);
  350. return r;
  351. }
  352. int
  353. Mono_Posix_Syscall_getsockname (int socket, struct Mono_Posix__SockaddrHeader* address)
  354. {
  355. int r;
  356. ALLOC_SOCKADDR
  357. r = getsockname (socket, addr, &addrlen);
  358. if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
  359. r = -1;
  360. if (need_free)
  361. free (addr);
  362. return r;
  363. }
  364. gint64
  365. Mono_Posix_Syscall_recv (int socket, void* message, guint64 length, int flags)
  366. {
  367. mph_return_if_size_t_overflow (length);
  368. return recv (socket, message, length, flags);
  369. }
  370. gint64
  371. Mono_Posix_Syscall_send (int socket, void* message, guint64 length, int flags)
  372. {
  373. mph_return_if_size_t_overflow (length);
  374. return send (socket, message, length, flags);
  375. }
  376. gint64
  377. Mono_Posix_Syscall_recvfrom (int socket, void* buffer, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
  378. {
  379. int r;
  380. mph_return_if_size_t_overflow (length);
  381. ALLOC_SOCKADDR
  382. r = recvfrom (socket, buffer, length, flags, addr, &addrlen);
  383. if (r != -1 && Mono_Posix_ToSockaddr (addr, addrlen, address) != 0)
  384. r = -1;
  385. if (need_free)
  386. free (addr);
  387. return r;
  388. }
  389. gint64
  390. Mono_Posix_Syscall_sendto (int socket, void* message, guint64 length, int flags, struct Mono_Posix__SockaddrHeader* address)
  391. {
  392. int r;
  393. mph_return_if_size_t_overflow (length);
  394. ALLOC_SOCKADDR
  395. if (Mono_Posix_FromSockaddr (address, addr) != 0) {
  396. if (need_free)
  397. free (addr);
  398. return -1;
  399. }
  400. r = sendto (socket, message, length, flags, addr, addrlen);
  401. if (need_free)
  402. free (addr);
  403. return r;
  404. }
  405. gint64
  406. Mono_Posix_Syscall_recvmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
  407. {
  408. struct msghdr hdr;
  409. int r;
  410. ALLOC_SOCKADDR
  411. memset (&hdr, 0, sizeof (struct msghdr));
  412. hdr.msg_name = addr;
  413. hdr.msg_namelen = addrlen;
  414. hdr.msg_iovlen = message->msg_iovlen;
  415. hdr.msg_control = message->msg_control;
  416. hdr.msg_controllen = message->msg_controllen;
  417. hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
  418. r = recvmsg (socket, &hdr, flags);
  419. if (r != -1 && Mono_Posix_ToSockaddr (addr, hdr.msg_namelen, address) != 0)
  420. r = -1;
  421. free (hdr.msg_iov);
  422. if (need_free)
  423. free (addr);
  424. message->msg_controllen = hdr.msg_controllen;
  425. message->msg_flags = hdr.msg_flags;
  426. return r;
  427. }
  428. gint64
  429. Mono_Posix_Syscall_sendmsg (int socket, struct Mono_Posix_Syscall__Msghdr* message, struct Mono_Posix__SockaddrHeader* address, int flags)
  430. {
  431. struct msghdr hdr;
  432. int r;
  433. ALLOC_SOCKADDR
  434. if (Mono_Posix_FromSockaddr (address, addr) != 0) {
  435. if (need_free)
  436. free (addr);
  437. return -1;
  438. }
  439. memset (&hdr, 0, sizeof (struct msghdr));
  440. hdr.msg_name = addr;
  441. hdr.msg_namelen = addrlen;
  442. hdr.msg_iovlen = message->msg_iovlen;
  443. hdr.msg_control = message->msg_control;
  444. hdr.msg_controllen = message->msg_controllen;
  445. hdr.msg_iov = _mph_from_iovec_array (message->msg_iov, message->msg_iovlen);
  446. r = sendmsg (socket, &hdr, flags);
  447. free (hdr.msg_iov);
  448. if (need_free)
  449. free (addr);
  450. return r;
  451. }
  452. static inline void make_msghdr (struct msghdr* hdr, unsigned char* msg_control, gint64 msg_controllen)
  453. {
  454. memset (hdr, 0, sizeof (struct msghdr));
  455. hdr->msg_control = msg_control;
  456. hdr->msg_controllen = msg_controllen;
  457. }
  458. static inline struct cmsghdr* from_offset (unsigned char* msg_control, gint64 offset)
  459. {
  460. if (offset == -1)
  461. return NULL;
  462. return (struct cmsghdr*) (msg_control + offset);
  463. }
  464. static inline gint64 to_offset (unsigned char* msg_control, void* hdr)
  465. {
  466. if (!hdr)
  467. return -1;
  468. return ((unsigned char*) hdr) - msg_control;
  469. }
  470. #ifdef CMSG_FIRSTHDR
  471. gint64
  472. Mono_Posix_Syscall_CMSG_FIRSTHDR (unsigned char* msg_control, gint64 msg_controllen)
  473. {
  474. struct msghdr hdr;
  475. make_msghdr (&hdr, msg_control, msg_controllen);
  476. return to_offset (msg_control, CMSG_FIRSTHDR (&hdr));
  477. }
  478. #endif
  479. #ifdef CMSG_NXTHDR
  480. gint64
  481. Mono_Posix_Syscall_CMSG_NXTHDR (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
  482. {
  483. struct msghdr hdr;
  484. make_msghdr (&hdr, msg_control, msg_controllen);
  485. return to_offset (msg_control, CMSG_NXTHDR (&hdr, from_offset (msg_control, cmsg)));
  486. }
  487. #endif
  488. #ifdef CMSG_DATA
  489. gint64
  490. Mono_Posix_Syscall_CMSG_DATA (unsigned char* msg_control, gint64 msg_controllen, gint64 cmsg)
  491. {
  492. return to_offset (msg_control, CMSG_DATA (from_offset (msg_control, cmsg)));
  493. }
  494. #endif
  495. #ifdef CMSG_ALIGN
  496. guint64
  497. Mono_Posix_Syscall_CMSG_ALIGN (guint64 length)
  498. {
  499. return CMSG_ALIGN (length);
  500. }
  501. #endif
  502. #ifdef CMSG_SPACE
  503. guint64
  504. Mono_Posix_Syscall_CMSG_SPACE (guint64 length)
  505. {
  506. return CMSG_SPACE (length);
  507. }
  508. #endif
  509. #ifdef CMSG_LEN
  510. guint64
  511. Mono_Posix_Syscall_CMSG_LEN (guint64 length)
  512. {
  513. return CMSG_LEN (length);
  514. }
  515. #endif
  516. /*
  517. * vim: noexpandtab
  518. */
  519. // vim: noexpandtab
  520. // Local Variables:
  521. // tab-width: 4
  522. // c-basic-offset: 4
  523. // indent-tabs-mode: t
  524. // End: