socket.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. *
  3. * Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Marcus Crestani
  4. */
  5. #define NO_OLD_FFI 1
  6. /*
  7. * Unix-specific sockets stuff.
  8. */
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <stdlib.h>
  14. #ifdef HAVE_PTHREAD_H
  15. #include <pthread.h>
  16. #endif
  17. #include <scheme48.h>
  18. #include "c-mods.h"
  19. #include "unix.h"
  20. #include "fd-io.h" /* ps_close_fd() */
  21. #include "event.h" /* add_pending_fd() */
  22. #include "sysdep.h"
  23. #include "socket.h"
  24. #include "address.h"
  25. static s48_ref_t
  26. s48_socket(s48_call_t call, s48_ref_t sch_af, s48_ref_t sch_type, s48_ref_t sch_protocol)
  27. {
  28. socket_t fd;
  29. int mode, status;
  30. s48_ref_t sch_channel;
  31. int af = s48_extract_af(call, sch_af);
  32. int socktype = s48_extract_socket_type(call, sch_type);
  33. int protocol = s48_extract_long_2(call, sch_protocol);
  34. RETRY_OR_RAISE_NEG(fd, socket(af, socktype, protocol));
  35. RETRY_OR_RAISE_NEG(status, fcntl(fd, F_SETFL, O_NONBLOCK));
  36. sch_channel = s48_add_channel_2(call, s48_channel_status_special_input_2(call),
  37. s48_enter_string_latin_1_2(call, "socket"), fd);
  38. if (!s48_channel_p_2(call, sch_channel))
  39. {
  40. ps_close_fd(fd); /* retries if interrupted */
  41. s48_raise_scheme_exception_2(call, s48_extract_long_2(call, sch_channel), 0);
  42. }
  43. return sch_channel;
  44. }
  45. static s48_ref_t
  46. s48_socketpair(s48_call_t call, s48_ref_t sch_af, s48_ref_t sch_type, s48_ref_t sch_protocol)
  47. {
  48. int status;
  49. s48_ref_t sch_channel0, sch_channel1;
  50. s48_ref_t sch_result;
  51. int af = s48_extract_af(call, sch_af);
  52. int socktype = s48_extract_socket_type(call, sch_type);
  53. int protocol = s48_extract_long_2(call, sch_protocol);
  54. socket_t fds[2];
  55. RETRY_OR_RAISE_NEG(status, socketpair(af, socktype, protocol, fds));
  56. RETRY_OR_RAISE_NEG(status, fcntl(fds[0], F_SETFL, O_NONBLOCK));
  57. RETRY_OR_RAISE_NEG(status, fcntl(fds[1], F_SETFL, O_NONBLOCK));
  58. sch_channel0 = s48_add_channel_2(call, s48_channel_status_input_2(call),
  59. s48_enter_string_latin_1_2(call, "socket"), fds[0]);
  60. sch_channel1 = s48_add_channel_2(call, s48_channel_status_input_2(call),
  61. s48_enter_string_latin_1_2(call, "socket"), fds[1]);
  62. sch_result = s48_cons_2(call, sch_channel0, sch_channel1);
  63. return sch_result;
  64. }
  65. /*
  66. * dup() `socket_fd' and return an output channel holding the result.
  67. *
  68. * We have to versions, one for calling from C and one for calling from Scheme.
  69. */
  70. static s48_ref_t
  71. dup_socket_channel(s48_call_t call, socket_t socket_fd)
  72. {
  73. socket_t output_fd;
  74. s48_ref_t output_channel;
  75. int flags;
  76. RETRY_OR_RAISE_NEG(output_fd, dup(socket_fd));
  77. RETRY_OR_RAISE_NEG(flags, fcntl(output_fd, F_GETFL));
  78. flags |= O_NONBLOCK;
  79. RETRY_OR_RAISE_NEG(flags, fcntl(output_fd, F_SETFL, flags));
  80. output_channel = s48_add_channel_2(call, s48_channel_status_output_2(call),
  81. s48_enter_string_latin_1_2(call, "socket connection"),
  82. output_fd);
  83. if (!s48_channel_p_2(call, output_channel))
  84. {
  85. ps_close_fd(output_fd); /* retries if interrupted */
  86. s48_raise_scheme_exception_2(call, s48_extract_long_2(call, output_channel), 0);
  87. };
  88. return output_channel;
  89. }
  90. socket_t
  91. s48_extract_socket_fd(s48_call_t call, s48_ref_t sch_channel)
  92. {
  93. s48_check_channel_2(call, sch_channel);
  94. return s48_extract_long_2(call, s48_unsafe_channel_os_index_2(call, sch_channel));
  95. }
  96. static s48_ref_t
  97. s48_dup_socket_channel(s48_call_t call, s48_ref_t sch_channel)
  98. {
  99. return dup_socket_channel(call, s48_extract_socket_fd(call, sch_channel));
  100. }
  101. /*
  102. * Given a bound socket, accept a connection and return a pair of the
  103. * input channel and the raw socket address.
  104. *
  105. * If the accept fails because the client hasn't connected yet, then we
  106. * return #f.
  107. *
  108. * If it fails for any other reason, then an exception is raised.
  109. */
  110. static s48_ref_t
  111. s48_accept(s48_call_t call, s48_ref_t sch_channel, s48_ref_t sch_retry_p)
  112. {
  113. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  114. socket_t connect_fd;
  115. int status;
  116. struct sockaddr_storage address;
  117. socklen_t len;
  118. s48_ref_t input_channel, output_channel;
  119. len = sizeof(address);
  120. connect_fd = accept(socket_fd, (struct sockaddr *)&address, &len);
  121. if (connect_fd >= 0) {
  122. RETRY_OR_RAISE_NEG(status, fcntl(connect_fd, F_SETFL, O_NONBLOCK));
  123. input_channel = s48_add_channel_2(call, s48_channel_status_input_2(call),
  124. s48_enter_string_latin_1_2(call, "socket connection"),
  125. connect_fd);
  126. if (!s48_channel_p_2(call, input_channel))
  127. {
  128. ps_close_fd(connect_fd); /* retries if interrupted */
  129. s48_raise_scheme_exception_2(call, s48_extract_long_2(call, input_channel), 0);
  130. }
  131. return s48_cons_2(call,
  132. input_channel,
  133. s48_enter_sockaddr(call, (const struct sockaddr*)&address, len));
  134. }
  135. /*
  136. * Check for errors. If we need to retry we mark the socket as pending
  137. * and return #F to tell the Scheme procedure to wait.
  138. */
  139. if ((errno != EWOULDBLOCK) && (errno != EINTR) && (errno != EAGAIN))
  140. s48_os_error_2(call, "s48_accept", errno, 2, sch_channel, sch_retry_p);
  141. if (! s48_add_pending_fd(socket_fd, PSTRUE))
  142. s48_out_of_memory_error_2(call);
  143. return s48_false_2(call);
  144. }
  145. /*
  146. * Given a socket and an address, connect the socket.
  147. *
  148. * If this succeeds, it returns an output channel for the connection.
  149. * If it fails because the connect would block, add the socket to the
  150. * pending queue (for output) and return #f.
  151. * If it fails for any other reason, raise an exception.
  152. */
  153. static s48_ref_t
  154. s48_connect(s48_call_t call, s48_ref_t sch_channel,
  155. s48_ref_t sch_address, s48_ref_t sch_retry_p)
  156. {
  157. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  158. /*
  159. * Try the connection. If it works we make an output channel and return it.
  160. * The original socket channel will be used as the input channel.
  161. *
  162. * FreeBSD's connect() behaves oddly. If you get told to wait, wait for
  163. * select() to signal the all-clear, and then try to connect again, you
  164. * get an `already connected' (EISCONN) error. To handle this we pass in
  165. * a retry_p flag. If retry_p is true the `already connected' error is
  166. * ignored.
  167. */
  168. if (connect(socket_fd,
  169. s48_extract_value_pointer_2(call, sch_address, struct sockaddr),
  170. s48_value_size_2(call, sch_address)) >= 0
  171. || ((errno == EISCONN) && (s48_true_p_2(call, sch_retry_p))))
  172. {
  173. s48_unsafe_stob_set_2(call, sch_channel,
  174. s48_channel_status_offset, s48_channel_status_input_2(call));
  175. return dup_socket_channel(call, socket_fd);
  176. }
  177. /*
  178. * Check for errors. If we need to retry we mark the socket as pending
  179. * and return #F to tell the Scheme procedure to wait.
  180. */
  181. /* already connected, will raise an error from Scheme */
  182. if (errno == EISCONN)
  183. return s48_true_2(call);
  184. if (errno != EWOULDBLOCK && errno != EINTR && errno != EALREADY
  185. && errno != EINPROGRESS && errno != EAGAIN)
  186. s48_os_error_2(call, "s48_connect", errno, 3, sch_channel, sch_address, sch_retry_p);
  187. if (! (s48_add_pending_fd(socket_fd, PSFALSE)))
  188. s48_out_of_memory_error_2(call);
  189. return s48_false_2(call);
  190. }
  191. /*
  192. * Receive a message. Returns pair (<byte-count> . <sender>) or just
  193. * <byte-count> if want_sender_p is false.
  194. */
  195. static s48_ref_t
  196. s48_recvfrom(s48_call_t call, s48_ref_t sch_channel,
  197. s48_ref_t sch_buffer, s48_ref_t sch_start, s48_ref_t sch_count,
  198. s48_ref_t sch_flags,
  199. s48_ref_t sch_want_sender_p,
  200. s48_ref_t sch_retry_p)
  201. {
  202. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  203. int want_sender_p = !(s48_false_p_2(call, sch_want_sender_p));
  204. struct sockaddr_storage from;
  205. socklen_t from_len = (want_sender_p ? sizeof(struct sockaddr_storage) : 0);
  206. int flags = s48_extract_msg_flags(call, sch_flags);
  207. size_t buffer_size = s48_byte_vector_length_2(call, sch_buffer);
  208. size_t start = s48_extract_unsigned_long_2(call, sch_start);
  209. size_t count = s48_extract_unsigned_long_2(call, sch_count);
  210. ssize_t status;
  211. if ((start + count) > buffer_size)
  212. s48_assertion_violation_2(call, "s48_sendto", "buffer start or count is wrong", 3,
  213. sch_buffer, sch_start, sch_count);
  214. status = recvfrom(socket_fd,
  215. s48_extract_byte_vector_2(call, sch_buffer) + start,
  216. count,
  217. flags,
  218. want_sender_p ? (struct sockaddr*)&from : NULL,
  219. &from_len);
  220. if (0 <= status)
  221. if (want_sender_p)
  222. {
  223. s48_ref_t sch_count, sch_saddr;
  224. s48_ref_t sch_result;
  225. sch_count = s48_enter_unsigned_long_2(call, status);
  226. sch_saddr = s48_enter_sockaddr(call, (struct sockaddr *)&from, from_len);
  227. sch_result = s48_cons_2(call, sch_count, sch_saddr);
  228. return sch_result;
  229. }
  230. else
  231. return s48_enter_unsigned_long_2(call, status);
  232. /*
  233. * Check for errors. If we need to retry we mark the socket as pending
  234. * and return #F to tell the Scheme procedure to wait.
  235. */
  236. if (errno != EWOULDBLOCK && errno != EINTR && errno != EALREADY
  237. && errno != EINPROGRESS && errno != EAGAIN)
  238. s48_os_error_2(call, "s48_recv", errno, 6,
  239. sch_channel, sch_buffer, sch_start, sch_count,
  240. sch_flags, sch_want_sender_p);
  241. if (! (s48_add_pending_fd(socket_fd, PSTRUE)))
  242. s48_out_of_memory_error_2(call);
  243. return s48_false_2(call);
  244. }
  245. static s48_ref_t
  246. s48_sendto(s48_call_t call, s48_ref_t sch_channel,
  247. s48_ref_t sch_buffer, s48_ref_t sch_start, s48_ref_t sch_count,
  248. s48_ref_t sch_flags,
  249. s48_ref_t sch_saddr,
  250. s48_ref_t sch_retry_p) /* ignored on Unix */
  251. {
  252. socket_t socket_fd = s48_extract_socket_fd(call, sch_channel);
  253. ssize_t sent;
  254. const struct sockaddr *sa
  255. = s48_extract_value_pointer_2(call, sch_saddr, const struct sockaddr);
  256. socklen_t salen = s48_value_size_2(call, sch_saddr);
  257. int flags = s48_extract_msg_flags(call, sch_flags);
  258. size_t buffer_size = s48_byte_vector_length_2(call, sch_buffer);
  259. size_t start = s48_extract_unsigned_long_2(call, sch_start);
  260. size_t count = s48_extract_unsigned_long_2(call, sch_count);
  261. if ((start + count) > buffer_size)
  262. s48_assertion_violation_2(call, "s48_sendto", "buffer start or count is wrong", 3,
  263. sch_buffer, sch_start, sch_count);
  264. sent = sendto(socket_fd,
  265. s48_extract_byte_vector_readonly_2(call, sch_buffer) + start,
  266. count,
  267. flags,
  268. (struct sockaddr *) sa, salen);
  269. if (0 <= sent)
  270. return s48_enter_unsigned_long_2(call, sent);
  271. /*
  272. * Check for errors. If we need to retry we mark the socket as pending
  273. * and return #F to tell the Scheme procedure to wait.
  274. */
  275. if (errno != EWOULDBLOCK && errno != EINTR && errno != EALREADY
  276. && errno != EINPROGRESS && errno != EAGAIN)
  277. s48_os_error_2(call, "s48_sendto", errno, 6,
  278. sch_channel, sch_saddr, sch_flags, sch_buffer, sch_start, sch_count);
  279. if (! (s48_add_pending_fd(socket_fd, PSFALSE)))
  280. s48_out_of_memory_error_2(call);
  281. return s48_false_2(call);
  282. }
  283. void
  284. s48_init_os_sockets(void)
  285. {
  286. S48_EXPORT_FUNCTION(s48_socket);
  287. S48_EXPORT_FUNCTION(s48_socketpair);
  288. S48_EXPORT_FUNCTION(s48_dup_socket_channel);
  289. S48_EXPORT_FUNCTION(s48_accept);
  290. S48_EXPORT_FUNCTION(s48_connect);
  291. S48_EXPORT_FUNCTION(s48_recvfrom);
  292. S48_EXPORT_FUNCTION(s48_sendto);
  293. }