socket.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /*
  2. * Part of Scheme 48 1.9. See file COPYING for notices and license.
  3. *
  4. * Authors: Mike Sperber, Marcus Crestani
  5. */
  6. #define NO_OLD_FFI 1
  7. /*
  8. * More or less platform-unspecific socket stuff.
  9. */
  10. #include <stdlib.h>
  11. #ifdef _WIN32
  12. #include <winsock2.h>
  13. #include <mswsock.h>
  14. #include <windows.h>
  15. #include <ws2tcpip.h>
  16. #define RETRY_NEG(STATUS, CALL) STATUS = (CALL)
  17. #define RETRY_OR_RAISE_NEG(STATUS, CALL) \
  18. do { \
  19. STATUS = (CALL); \
  20. if (STATUS == SOCKET_ERROR) \
  21. s48_os_error_2(call, NULL, WSAGetLastError(), 0); \
  22. } while (0)
  23. #else
  24. #include <sys/types.h>
  25. #include <sys/socket.h>
  26. #include <netinet/tcp.h>
  27. #include <errno.h>
  28. #include <fcntl.h>
  29. #include "unix.h"
  30. #endif
  31. #include <scheme48.h>
  32. #include "address.h"
  33. #include "socket.h"
  34. /* The C code knows about these constants. */
  35. static int
  36. extract_how(s48_call_t call, s48_ref_t sch_how)
  37. {
  38. long how_val = s48_extract_long_2(call, sch_how);
  39. switch (how_val)
  40. {
  41. #ifdef _WIN32
  42. case 0:
  43. return SD_RECEIVE;
  44. case 1:
  45. return SD_SEND;
  46. case 2:
  47. return SD_BOTH;
  48. #else
  49. case 0:
  50. return SHUT_RD;
  51. case 1:
  52. return SHUT_WR;
  53. case 2:
  54. return SHUT_RDWR;
  55. #endif
  56. }
  57. }
  58. int
  59. s48_extract_msg_flags(s48_call_t call, s48_ref_t sch_flags)
  60. {
  61. long flags = s48_extract_long_2(call, sch_flags);
  62. return (((flags & 0x01) ? MSG_OOB : 0)
  63. | ((flags & 0x02) ? MSG_PEEK : 0)
  64. | ((flags & 0x04) ? MSG_DONTROUTE : 0));
  65. }
  66. /*
  67. * Close half of a socket; if `input_p' is true we close the input half,
  68. * otherwise the output half. This horribleness is forced upon us by
  69. * Unix's use of bidirectional file descriptors.
  70. */
  71. static s48_ref_t
  72. s48_shutdown(s48_call_t call, s48_ref_t sch_channel, s48_ref_t sch_how)
  73. {
  74. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  75. int how = extract_how(call, sch_how);
  76. int status;
  77. /*
  78. * We ignore `endpoint is not connected' errors, as we just want to get
  79. * the file descriptor closed.
  80. */
  81. RETRY_NEG(status, shutdown(socket_fd, how));
  82. #ifdef _WIN32
  83. if ((status == SOCKET_ERROR) && (WSAGetLastError() != WSAENOTCONN))
  84. #else
  85. if ((0 > status) && (errno != ENOTCONN))
  86. #endif
  87. s48_os_error_2(call, "s48_close_socket_half", errno, 1, sch_channel);
  88. return s48_unspecific_2(call);
  89. }
  90. static s48_ref_t
  91. s48_bind(s48_call_t call, s48_ref_t sch_channel, s48_ref_t sch_saddr)
  92. {
  93. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  94. int status;
  95. const struct sockaddr *sa
  96. = s48_extract_value_pointer_2(call, sch_saddr, const struct sockaddr);
  97. socklen_t salen = s48_value_size_2(call, sch_saddr);
  98. RETRY_OR_RAISE_NEG(status, bind(socket_fd, sa, salen));
  99. return s48_unspecific_2(call);
  100. }
  101. static s48_ref_t
  102. s48_listen(s48_call_t call, s48_ref_t sch_channel, s48_ref_t sch_queue_size)
  103. {
  104. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  105. int queue_size = s48_extract_long_2(call, sch_queue_size);
  106. int status;
  107. RETRY_OR_RAISE_NEG(status, listen(socket_fd, queue_size));
  108. return s48_unspecific_2(call);
  109. }
  110. static s48_ref_t
  111. s48_max_connection_count(s48_call_t call)
  112. {
  113. /* not a fixnum on Windows! */
  114. return s48_enter_long_2(call, SOMAXCONN);
  115. }
  116. static s48_ref_t
  117. s48_getsockname(s48_call_t call, s48_ref_t sch_channel)
  118. {
  119. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  120. int status;
  121. struct sockaddr_storage sa;
  122. socklen_t salen = sizeof(struct sockaddr_storage);
  123. RETRY_OR_RAISE_NEG(status,
  124. getsockname(socket_fd, (struct sockaddr*)&sa, &salen));
  125. return s48_enter_sockaddr(call, (struct sockaddr *)&sa, salen);
  126. }
  127. static s48_ref_t
  128. s48_getpeername(s48_call_t call, s48_ref_t sch_channel)
  129. {
  130. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  131. int status;
  132. struct sockaddr_storage sa;
  133. socklen_t salen = sizeof(struct sockaddr_storage);
  134. RETRY_OR_RAISE_NEG(status,
  135. getpeername(socket_fd, (struct sockaddr*)&sa, &salen));
  136. return s48_enter_sockaddr(call, (struct sockaddr *)&sa, salen);
  137. }
  138. static s48_ref_t
  139. setsockopt_boolean(s48_call_t call, int level, int option,
  140. s48_ref_t sch_channel, s48_ref_t sch_val)
  141. {
  142. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  143. int status, on;
  144. on = (s48_false_p_2(call, sch_val) ? 0 : 1);
  145. RETRY_OR_RAISE_NEG(status, \
  146. setsockopt(socket_fd, level, option,
  147. (void*)&on, sizeof(on)));
  148. return s48_unspecific_2(call);
  149. }
  150. static s48_ref_t
  151. getsockopt_boolean(s48_call_t call, int level, int option,
  152. s48_ref_t sch_channel)
  153. {
  154. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  155. int status, on;
  156. socklen_t onlen = sizeof(on);
  157. RETRY_OR_RAISE_NEG(status,
  158. getsockopt(socket_fd, level, option,
  159. (void*)&on, &onlen));
  160. return (on ? s48_true_2(call) : s48_false_2(call));
  161. }
  162. static s48_ref_t
  163. setsockopt_int(s48_call_t call, int level, int option,
  164. s48_ref_t sch_channel, s48_ref_t sch_val)
  165. {
  166. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  167. int status, val;
  168. val = s48_extract_long_2(call, sch_val);
  169. RETRY_OR_RAISE_NEG(status,
  170. setsockopt(socket_fd, level, option,
  171. (void*)&val, sizeof(val)));
  172. return s48_unspecific_2(call);
  173. }
  174. static s48_ref_t
  175. getsockopt_int(s48_call_t call, int level, int option,
  176. s48_ref_t sch_channel)
  177. {
  178. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  179. int status, val;
  180. socklen_t vallen = sizeof(val);
  181. RETRY_OR_RAISE_NEG(status,
  182. getsockopt(socket_fd, level, option,
  183. (void*)&val, &vallen));
  184. return s48_enter_long_2(call, val);
  185. }
  186. #define DEFINE_SOCKET_OPTION_SETTER(name, level, option, type) \
  187. static s48_ref_t \
  188. name(s48_call_t call, s48_ref_t sch_channel, s48_ref_t sch_val) \
  189. { \
  190. return setsockopt_##type(call, level, option, \
  191. sch_channel, sch_val); \
  192. }
  193. #define DEFINE_SOCKET_OPTION_GETTER(name, level, option, type) \
  194. static s48_ref_t \
  195. name(s48_call_t call, s48_ref_t sch_channel) \
  196. { \
  197. return getsockopt_##type(call, level, option, \
  198. sch_channel); \
  199. }
  200. /* POSIX */
  201. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_DEBUG, SOL_SOCKET, SO_DEBUG, boolean)
  202. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_DEBUG, SOL_SOCKET, SO_DEBUG, boolean)
  203. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_ACCEPTCONN, SOL_SOCKET, SO_ACCEPTCONN, boolean)
  204. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_ACCEPTCONN, SOL_SOCKET, SO_ACCEPTCONN, boolean)
  205. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST, boolean)
  206. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST, boolean)
  207. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR, boolean)
  208. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR, boolean)
  209. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE, boolean)
  210. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE, boolean)
  211. /* LINGER leads to close() blocking */
  212. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE, boolean)
  213. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_OOBINLINE, SOL_SOCKET, SO_OOBINLINE, boolean)
  214. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF, int)
  215. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_SNDBUF, SOL_SOCKET, SO_SNDBUF, int)
  216. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF, int)
  217. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF, int)
  218. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_ERROR, SOL_SOCKET, SO_ERROR, int)
  219. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_DONTROUTE, SOL_SOCKET, SO_DONTROUTE, boolean)
  220. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_DONTROUTE, SOL_SOCKET, SO_DONTROUTE, boolean)
  221. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_RCVLOWAT, SOL_SOCKET, SO_RCVLOWAT, int)
  222. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_RCVLOWAT, SOL_SOCKET, SO_RCVLOWAT, int)
  223. /* SO_RCVTIMEO makes input functions block */
  224. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_SO_SNDLOWAT, SOL_SOCKET, SO_SNDLOWAT, int)
  225. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_SO_SNDLOWAT, SOL_SOCKET, SO_SNDLOWAT, int)
  226. /* SO_SNDTIMEO makes output functions block */
  227. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY, boolean)
  228. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_TCP_NODELAY, IPPROTO_TCP, TCP_NODELAY, boolean)
  229. /* RFC 3493 */
  230. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_IPV6_UNICAST_HOPS, SOL_SOCKET, IPV6_UNICAST_HOPS, int)
  231. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_IPV6_UNICAST_HOPS, SOL_SOCKET, IPV6_UNICAST_HOPS, int)
  232. /* IPV6_MULTICAST_IF is really unsigned */
  233. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_IPV6_MULTICAST_IF, SOL_SOCKET, IPV6_MULTICAST_IF, int)
  234. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_IPV6_MULTICAST_IF, SOL_SOCKET, IPV6_MULTICAST_IF, int)
  235. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_IPV6_MULTICAST_HOPS, SOL_SOCKET, IPV6_MULTICAST_HOPS, int)
  236. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_IPV6_MULTICAST_HOPS, SOL_SOCKET, IPV6_MULTICAST_HOPS, int)
  237. DEFINE_SOCKET_OPTION_SETTER(s48_setsockopt_IPV6_MULTICAST_LOOP, SOL_SOCKET, IPV6_MULTICAST_LOOP, boolean)
  238. DEFINE_SOCKET_OPTION_GETTER(s48_getsockopt_IPV6_MULTICAST_LOOP, SOL_SOCKET, IPV6_MULTICAST_LOOP, boolean)
  239. static s48_ref_t
  240. ipv6_socket_group_op(s48_call_t call, int group_op,
  241. s48_ref_t sch_channel,
  242. s48_ref_t sch_address,
  243. s48_ref_t sch_if)
  244. {
  245. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  246. int status;
  247. struct ipv6_mreq mreq;
  248. s48_extract_in6_addr(call, sch_address, &(mreq.ipv6mr_multiaddr));
  249. mreq.ipv6mr_interface = s48_extract_unsigned_long_2(call, sch_if);
  250. RETRY_OR_RAISE_NEG(status,
  251. setsockopt(socket_fd, IPPROTO_IPV6, group_op,
  252. (void*)&mreq, sizeof(struct ipv6_mreq)));
  253. return s48_unspecific_2(call);
  254. }
  255. static s48_ref_t
  256. s48_ipv6_socket_join_group(s48_call_t call, s48_ref_t sch_channel,
  257. s48_ref_t sch_address,
  258. s48_ref_t sch_if)
  259. {
  260. return ipv6_socket_group_op(call, IPV6_JOIN_GROUP,
  261. sch_channel, sch_address, sch_if);
  262. }
  263. static s48_ref_t
  264. s48_ipv6_socket_leave_group(s48_call_t call, s48_ref_t sch_channel,
  265. s48_ref_t sch_address,
  266. s48_ref_t sch_if)
  267. {
  268. return ipv6_socket_group_op(call, IPV6_LEAVE_GROUP,
  269. sch_channel, sch_address, sch_if);
  270. }
  271. void
  272. s48_init_net_sockets(void)
  273. {
  274. S48_EXPORT_FUNCTION(s48_bind);
  275. S48_EXPORT_FUNCTION(s48_listen);
  276. S48_EXPORT_FUNCTION(s48_max_connection_count);
  277. S48_EXPORT_FUNCTION(s48_shutdown);
  278. S48_EXPORT_FUNCTION(s48_getsockname);
  279. S48_EXPORT_FUNCTION(s48_getpeername);
  280. S48_EXPORT_FUNCTION(s48_setsockopt_SO_DEBUG);
  281. S48_EXPORT_FUNCTION(s48_getsockopt_SO_DEBUG);
  282. S48_EXPORT_FUNCTION(s48_getsockopt_SO_ACCEPTCONN);
  283. S48_EXPORT_FUNCTION(s48_setsockopt_SO_BROADCAST);
  284. S48_EXPORT_FUNCTION(s48_getsockopt_SO_BROADCAST);
  285. S48_EXPORT_FUNCTION(s48_setsockopt_SO_REUSEADDR);
  286. S48_EXPORT_FUNCTION(s48_getsockopt_SO_REUSEADDR);
  287. S48_EXPORT_FUNCTION(s48_setsockopt_SO_KEEPALIVE);
  288. S48_EXPORT_FUNCTION(s48_getsockopt_SO_KEEPALIVE);
  289. S48_EXPORT_FUNCTION(s48_setsockopt_SO_OOBINLINE);
  290. S48_EXPORT_FUNCTION(s48_getsockopt_SO_OOBINLINE);
  291. S48_EXPORT_FUNCTION(s48_setsockopt_SO_SNDBUF);
  292. S48_EXPORT_FUNCTION(s48_getsockopt_SO_SNDBUF);
  293. S48_EXPORT_FUNCTION(s48_setsockopt_SO_RCVBUF);
  294. S48_EXPORT_FUNCTION(s48_getsockopt_SO_RCVBUF);
  295. S48_EXPORT_FUNCTION(s48_getsockopt_SO_ERROR);
  296. S48_EXPORT_FUNCTION(s48_setsockopt_SO_DONTROUTE);
  297. S48_EXPORT_FUNCTION(s48_getsockopt_SO_DONTROUTE);
  298. S48_EXPORT_FUNCTION(s48_setsockopt_SO_RCVLOWAT);
  299. S48_EXPORT_FUNCTION(s48_getsockopt_SO_RCVLOWAT);
  300. S48_EXPORT_FUNCTION(s48_setsockopt_SO_SNDLOWAT);
  301. S48_EXPORT_FUNCTION(s48_getsockopt_SO_SNDLOWAT);
  302. S48_EXPORT_FUNCTION(s48_setsockopt_TCP_NODELAY);
  303. S48_EXPORT_FUNCTION(s48_getsockopt_TCP_NODELAY);
  304. S48_EXPORT_FUNCTION(s48_setsockopt_IPV6_UNICAST_HOPS);
  305. S48_EXPORT_FUNCTION(s48_getsockopt_IPV6_UNICAST_HOPS);
  306. S48_EXPORT_FUNCTION(s48_setsockopt_IPV6_MULTICAST_IF);
  307. S48_EXPORT_FUNCTION(s48_getsockopt_IPV6_MULTICAST_IF);
  308. S48_EXPORT_FUNCTION(s48_setsockopt_IPV6_MULTICAST_HOPS);
  309. S48_EXPORT_FUNCTION(s48_getsockopt_IPV6_MULTICAST_HOPS);
  310. S48_EXPORT_FUNCTION(s48_setsockopt_IPV6_MULTICAST_LOOP);
  311. S48_EXPORT_FUNCTION(s48_getsockopt_IPV6_MULTICAST_LOOP);
  312. S48_EXPORT_FUNCTION(s48_ipv6_socket_join_group);
  313. S48_EXPORT_FUNCTION(s48_ipv6_socket_leave_group);
  314. }