socket.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /* Copyright (c) 1993-2007 by Richard Kelsey and Jonathan Rees.
  2. See file COPYING. */
  3. /*
  4. * An interface to Unix sockets.
  5. */
  6. #define _XOPEN_SOURCE_EXTENDED 1 /* AIX wants this to be 1 */
  7. #include "sysdep.h"
  8. #include <stdio.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <sys/param.h>
  12. #include <errno.h>
  13. #include <fcntl.h>
  14. #include <netdb.h>
  15. #include <unistd.h>
  16. #include <string.h>
  17. #include <netinet/in.h>
  18. #include <arpa/inet.h>
  19. #include "c-mods.h"
  20. #include "scheme48.h"
  21. #include "unix.h"
  22. #include "fd-io.h" /* ps_close_fd() */
  23. #include "event.h" /* add_pending_fd() */
  24. /* Henry Cejtin says that 5 is the largest safe number for this. */
  25. #define LISTEN_QUEUE_SIZE 5
  26. extern void s48_init_socket(void);
  27. static s48_value s48_socket(s48_value udp_p, s48_value input_p),
  28. s48_bind(s48_value socket_channel, s48_value number),
  29. s48_socket_number(s48_value socket_channel),
  30. s48_listen(s48_value socket_channel),
  31. s48_accept(s48_value socket_channel),
  32. s48_connect(s48_value socket_channel,
  33. s48_value machine,
  34. s48_value port,
  35. s48_value retry_p),
  36. s48_dup_socket_channel(s48_value socket_fd),
  37. s48_close_socket_half(s48_value socket_channel,
  38. s48_value input_p),
  39. s48_get_host_name(void),
  40. s48_udp_send(s48_value channel,
  41. s48_value udp_address,
  42. s48_value buffer,
  43. s48_value length),
  44. s48_udp_receive(s48_value channel, s48_value message),
  45. s48_lookup_udp_address(s48_value name, s48_value port);
  46. /* Forward declaration. */
  47. static s48_value dup_socket_channel(int socket_fd);
  48. /*
  49. * Record type imported from Scheme.
  50. */
  51. static s48_value s48_udp_address_type_binding = S48_FALSE;
  52. /*
  53. * An array of udp_addresess (and S48_FALSE's) acting as a hash table.
  54. * The initial size is small so that rehashing will be tested often.
  55. */
  56. #define INITIAL_CONNECTIONS_SIZE 16
  57. static s48_value connections = S48_FALSE;
  58. static long connections_size = INITIAL_CONNECTIONS_SIZE;
  59. static long connections_index_mask = INITIAL_CONNECTIONS_SIZE - 1;
  60. static long connection_count = 0;
  61. /*
  62. * Install all exported functions in Scheme48.
  63. */
  64. void
  65. s48_init_socket(void)
  66. {
  67. S48_EXPORT_FUNCTION(s48_socket);
  68. S48_EXPORT_FUNCTION(s48_bind);
  69. S48_EXPORT_FUNCTION(s48_socket_number);
  70. S48_EXPORT_FUNCTION(s48_listen);
  71. S48_EXPORT_FUNCTION(s48_accept);
  72. S48_EXPORT_FUNCTION(s48_connect);
  73. S48_EXPORT_FUNCTION(s48_dup_socket_channel);
  74. S48_EXPORT_FUNCTION(s48_close_socket_half);
  75. S48_EXPORT_FUNCTION(s48_get_host_name);
  76. S48_EXPORT_FUNCTION(s48_udp_send);
  77. S48_EXPORT_FUNCTION(s48_udp_receive);
  78. S48_EXPORT_FUNCTION(s48_lookup_udp_address);
  79. S48_GC_PROTECT_GLOBAL(s48_udp_address_type_binding);
  80. s48_udp_address_type_binding = s48_get_imported_binding("s48-udp-address-type");
  81. S48_GC_PROTECT_GLOBAL(connections);
  82. connections = s48_make_vector(INITIAL_CONNECTIONS_SIZE, S48_FALSE);
  83. }
  84. /*
  85. * Create an internet-domain stream (reliable, sequenced) socket.
  86. * We return an input channel on success and raise an exception on failure.
  87. * The socket has been made non-blocking.
  88. */
  89. static s48_value
  90. s48_socket(s48_value udp_p, s48_value input_p)
  91. {
  92. int fd,
  93. mode,
  94. status;
  95. s48_value channel;
  96. int on = 1;
  97. RETRY_OR_RAISE_NEG(fd, socket(AF_INET,
  98. (udp_p == S48_FALSE) ?
  99. SOCK_STREAM :
  100. SOCK_DGRAM,
  101. 0));
  102. RETRY_OR_RAISE_NEG(status, fcntl(fd, F_SETFL, O_NONBLOCK));
  103. /*
  104. * If we don't do this, we may get "Address already in use" if we
  105. * try to do anything on the same port too soon.
  106. * Alan Bawden says this is OK:
  107. * http://news.gmane.org/gmane.lisp.scheme.scheme48/cutoff=1672
  108. */
  109. RETRY_OR_RAISE_NEG(status,
  110. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
  111. &on, sizeof(on)));
  112. mode = (input_p == S48_FALSE) ?
  113. S48_CHANNEL_STATUS_SPECIAL_OUTPUT :
  114. S48_CHANNEL_STATUS_SPECIAL_INPUT;
  115. channel = s48_add_channel(mode, s48_enter_string_latin_1("socket"), fd);
  116. if (!S48_CHANNEL_P(channel)) {
  117. ps_close_fd(fd); /* retries if interrupted */
  118. s48_raise_scheme_exception(s48_extract_fixnum(channel), 0); };
  119. return channel;
  120. }
  121. /*
  122. * Given an internet-domain stream socket and a port number, bind
  123. * the socket to the port and prepare to receive connections.
  124. * If the port number is #f, then we bind the socket to any available
  125. * port.
  126. *
  127. * Nothing useful is returned.
  128. */
  129. static s48_value
  130. s48_bind(s48_value channel, s48_value port_number)
  131. {
  132. int socket_fd,
  133. port,
  134. status;
  135. struct sockaddr_in address;
  136. S48_CHECK_CHANNEL(channel);
  137. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  138. if (port_number == S48_FALSE)
  139. port = 0;
  140. else
  141. port = s48_extract_fixnum(port_number);
  142. memset(&address, 0, sizeof(address));
  143. address.sin_family = AF_INET;
  144. address.sin_addr.s_addr = htonl(INADDR_ANY);
  145. address.sin_port = htons(port);
  146. RETRY_OR_RAISE_NEG(status,
  147. bind(socket_fd,
  148. (struct sockaddr *)&address,
  149. sizeof(address)));
  150. return S48_UNSPECIFIC;
  151. }
  152. /*
  153. * Return the port number associated with an internet stream socket.
  154. */
  155. static s48_value
  156. s48_socket_number(s48_value channel)
  157. {
  158. int socket_fd,
  159. status;
  160. socklen_t len;
  161. struct sockaddr_in address;
  162. S48_CHECK_CHANNEL(channel);
  163. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  164. address.sin_addr.s_addr = htonl(INADDR_ANY);
  165. len = sizeof(address);
  166. RETRY_NEG(status, getsockname(socket_fd, (struct sockaddr *)&address, &len));
  167. if ((status < 0) || (address.sin_family != AF_INET))
  168. s48_raise_os_error(errno);
  169. return s48_enter_fixnum(ntohs(address.sin_port));
  170. }
  171. static s48_value
  172. s48_listen(s48_value channel)
  173. {
  174. int socket_fd;
  175. int status;
  176. S48_CHECK_CHANNEL(channel);
  177. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  178. RETRY_OR_RAISE_NEG(status, listen(socket_fd, LISTEN_QUEUE_SIZE));
  179. return S48_UNSPECIFIC;
  180. }
  181. /*
  182. * Given an internet-domain stream socket which has been bound
  183. * accept a connection and return the resulting socket as a pair of channels
  184. * (after marking it non-blocking).
  185. *
  186. * If the accept fails because the client hasn't connected yet, then we
  187. * return #f.
  188. *
  189. * If it fails for any other reason, then an exception is raised.
  190. */
  191. static s48_value
  192. s48_accept(s48_value channel)
  193. {
  194. int socket_fd,
  195. connect_fd,
  196. status;
  197. socklen_t len;
  198. struct sockaddr_in address;
  199. s48_value input_channel,
  200. output_channel;
  201. S48_CHECK_CHANNEL(channel);
  202. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  203. len = sizeof(address);
  204. connect_fd = accept(socket_fd, (struct sockaddr *)&address, &len);
  205. /*
  206. * Check for a connection. If we have one we create two channels, one
  207. * input and one, with a dup()'ed fd, output. Lots of error checking
  208. * makes this messy.
  209. */
  210. if (connect_fd >= 0) {
  211. S48_DECLARE_GC_PROTECT(1);
  212. RETRY_OR_RAISE_NEG(status, fcntl(connect_fd, F_SETFL, O_NONBLOCK));
  213. input_channel = s48_add_channel(S48_CHANNEL_STATUS_INPUT,
  214. s48_enter_string_latin_1("socket connection"),
  215. connect_fd);
  216. if (!S48_CHANNEL_P(input_channel)) {
  217. ps_close_fd(connect_fd); /* retries if interrupted */
  218. s48_raise_scheme_exception(s48_extract_fixnum(input_channel), 0); };
  219. return input_channel;
  220. }
  221. /*
  222. * Check for errors. If we need to retry we mark the socket as pending
  223. * and return #F to tell the Scheme procedure to wait.
  224. */
  225. if ((errno != EWOULDBLOCK) && (errno != EINTR) && (errno != EAGAIN))
  226. s48_raise_os_error(errno);
  227. if (! s48_add_pending_fd(socket_fd, PSTRUE))
  228. s48_raise_out_of_memory_error();
  229. return S48_FALSE;
  230. }
  231. /*
  232. * Given an internet-domain stream socket, a machine name and a port number,
  233. * connect the socket to that machine/port.
  234. *
  235. * If this succeeds, it returns an output channel for the connection.
  236. * If it fails because the connect would block, add the socket to the
  237. * pending queue (for output) and return #f.
  238. * If it fails for any other reason, raise an exception.
  239. */
  240. static s48_value
  241. s48_connect(s48_value channel,
  242. s48_value machine,
  243. s48_value port,
  244. s48_value retry_p)
  245. {
  246. int socket_fd,
  247. port_number;
  248. char *machine_name;
  249. struct hostent *host;
  250. struct sockaddr_in address;
  251. S48_CHECK_CHANNEL(channel);
  252. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  253. machine_name = s48_extract_byte_vector(machine);
  254. S48_CHECK_FIXNUM(port);
  255. port_number = S48_UNSAFE_EXTRACT_FIXNUM(port);
  256. /*
  257. * Get the host and initialize `address'.
  258. */
  259. RETRY_NULL(host, gethostbyname(machine_name));
  260. if (host == NULL)
  261. s48_raise_os_error(h_errno);
  262. memset((void *)&address, 0, sizeof(address));
  263. address.sin_family = host->h_addrtype;
  264. if (host->h_length > sizeof(address.sin_addr))
  265. s48_raise_range_error(s48_enter_fixnum(host->h_length),
  266. S48_UNSAFE_ENTER_FIXNUM(0),
  267. s48_enter_fixnum(sizeof(address.sin_addr)));
  268. memcpy((void *)&address.sin_addr, (void *)host->h_addr, host->h_length);
  269. address.sin_port = htons(port_number);
  270. /*
  271. * Try the connection. If it works we make an output channel and return it.
  272. * The original socket channel will be used as the input channel.
  273. *
  274. * FreeBSD's connect() behaves oddly. If you get told to wait, wait for
  275. * select() to signal the all-clear, and then try to connect again, you
  276. * get an `already connected' (EISCONN) error. To handle this we pass in
  277. * a retry_p flag. If retry_p is true the `already connected' error is
  278. * ignored.
  279. */
  280. if (connect(socket_fd, (struct sockaddr *)&address, sizeof(address)) >= 0
  281. || ((errno == EISCONN) && (retry_p == S48_TRUE))) {
  282. S48_STOB_SET(channel, S48_CHANNEL_STATUS_OFFSET, S48_CHANNEL_STATUS_INPUT);
  283. return dup_socket_channel(socket_fd); }
  284. /*
  285. * Check for errors. If we need to retry we mark the socket as pending
  286. * and return #F to tell the Scheme procedure to wait.
  287. */
  288. /* already connected, will raise an error from Scheme */
  289. if (errno == EISCONN)
  290. return S48_TRUE;
  291. if (errno != EWOULDBLOCK && errno != EINTR && errno != EALREADY
  292. && errno != EINPROGRESS && errno != EAGAIN)
  293. s48_raise_os_error(errno);
  294. if (! (s48_add_pending_fd(socket_fd, PSFALSE)))
  295. s48_raise_out_of_memory_error();
  296. return S48_FALSE;
  297. }
  298. /*
  299. * dup() `socket_fd' and return an output channel holding the result.
  300. *
  301. * We have to versions, one for calling from C and one for calling from Scheme.
  302. */
  303. static s48_value
  304. s48_dup_socket_channel(s48_value channel)
  305. {
  306. int socket_fd;
  307. S48_CHECK_CHANNEL(channel);
  308. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  309. return dup_socket_channel(socket_fd);
  310. }
  311. static s48_value
  312. dup_socket_channel(int socket_fd)
  313. {
  314. int output_fd;
  315. s48_value output_channel;
  316. RETRY_OR_RAISE_NEG(output_fd, dup(socket_fd));
  317. output_channel = s48_add_channel(S48_CHANNEL_STATUS_OUTPUT,
  318. s48_enter_string_latin_1("socket connection"),
  319. output_fd);
  320. if (!S48_CHANNEL_P(output_channel)) {
  321. ps_close_fd(output_fd); /* retries if interrupted */
  322. s48_raise_scheme_exception(s48_extract_fixnum(output_channel), 0); };
  323. return output_channel;
  324. }
  325. /*
  326. * Close half of a socket; if `input_p' is true we close the input half,
  327. * otherwise the output half. This horribleness is forced upon us by
  328. * Unix's use of bidirectional file descriptors.
  329. */
  330. static s48_value
  331. s48_close_socket_half(s48_value channel, s48_value input_p)
  332. {
  333. int socket_fd,
  334. status;
  335. S48_CHECK_CHANNEL(channel);
  336. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  337. /* We ignore `endpoint is not connected' errors, as we just want to get
  338. the file descriptor closed. */
  339. RETRY_NEG(status, shutdown(socket_fd, S48_EXTRACT_BOOLEAN(input_p) ? 0 : 1));
  340. if ((0 > status) && (errno != ENOTCONN))
  341. s48_raise_os_error(errno);
  342. return S48_TRUE;
  343. }
  344. /*
  345. * Get the name of the local machine.
  346. */
  347. static s48_value
  348. s48_get_host_name(void)
  349. {
  350. char mbuff[MAXHOSTNAMELEN];
  351. int status;
  352. RETRY_OR_RAISE_NEG(status, gethostname(mbuff, sizeof(mbuff)));
  353. return s48_enter_string_latin_1(mbuff);
  354. }
  355. /*
  356. * UDP sockets.
  357. */
  358. /*
  359. * A udp_address is a Scheme record with the following fields:
  360. * address ; an in_addr inside a Scheme byte vector
  361. * port ; the port as a fixnum
  362. * name ; printable version of the name as a Scheme string
  363. * + possibly others that we don't care about
  364. */
  365. #define UDP_ADDRESS_PTR(udp) \
  366. (S48_UNSAFE_EXTRACT_VALUE_POINTER(S48_UNSAFE_RECORD_REF((udp), 0), \
  367. struct in_addr))
  368. #define UDP_PORT(udp) \
  369. (S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_RECORD_REF((udp), 1)))
  370. /*
  371. * Forward declaration of internal procedures.
  372. */
  373. static void connection_init();
  374. static s48_value address_connection(struct sockaddr_in *addr);
  375. static s48_value lookup_connection(struct in_addr address,
  376. unsigned long port);
  377. static s48_value address_hash(struct in_addr address,
  378. unsigned long port);
  379. static s48_value add_new_connection(int index,
  380. struct in_addr address,
  381. unsigned long port);
  382. static void expand_and_rehash();
  383. static s48_value get_hostname(struct in_addr addr);
  384. /*
  385. * Receive a message. Returns pair (<byte-count> . <sender>).
  386. */
  387. static s48_value
  388. s48_udp_receive(s48_value channel, s48_value buffer)
  389. {
  390. int socket_fd;
  391. struct sockaddr_in from;
  392. socklen_t from_len = sizeof(struct sockaddr_in);
  393. int count;
  394. S48_CHECK_CHANNEL(channel);
  395. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  396. S48_CHECK_VALUE(buffer);
  397. count = recvfrom(socket_fd,
  398. S48_UNSAFE_EXTRACT_VALUE_POINTER(buffer, void *),
  399. S48_UNSAFE_BYTE_VECTOR_LENGTH(buffer),
  400. 0,
  401. (struct sockaddr*)&from,
  402. &from_len);
  403. if (0 <= count)
  404. return s48_cons(S48_UNSAFE_ENTER_FIXNUM(count),
  405. address_connection(&from));
  406. /*
  407. * Check for errors. If we need to retry we mark the socket as pending
  408. * and return #F to tell the Scheme procedure to wait.
  409. */
  410. if (errno != EWOULDBLOCK && errno != EINTR && errno != EALREADY
  411. && errno != EINPROGRESS && errno != EAGAIN)
  412. s48_raise_os_error(errno);
  413. if (! (s48_add_pending_fd(socket_fd, PSTRUE)))
  414. s48_raise_out_of_memory_error();
  415. return S48_FALSE;
  416. }
  417. static s48_value
  418. s48_udp_send(s48_value channel,
  419. s48_value address,
  420. s48_value buffer,
  421. s48_value count)
  422. {
  423. int socket_fd;
  424. int sent;
  425. struct sockaddr_in to;
  426. S48_CHECK_CHANNEL(channel);
  427. s48_check_record_type(address, s48_udp_address_type_binding);
  428. S48_CHECK_VALUE(buffer);
  429. S48_CHECK_FIXNUM(count);
  430. socket_fd = S48_UNSAFE_EXTRACT_FIXNUM(S48_UNSAFE_CHANNEL_OS_INDEX(channel));
  431. memset(&to, 0, sizeof(to));
  432. to.sin_family = AF_INET;
  433. to.sin_addr = *(UDP_ADDRESS_PTR(address));
  434. to.sin_port = htons(UDP_PORT(address));
  435. sent = sendto(socket_fd,
  436. S48_UNSAFE_EXTRACT_VALUE_POINTER(buffer, void *),
  437. S48_UNSAFE_EXTRACT_FIXNUM(count),
  438. 0,
  439. (struct sockaddr *)&to,
  440. sizeof(struct sockaddr_in));
  441. if (0 <= sent)
  442. return S48_UNSAFE_ENTER_FIXNUM(sent);
  443. /*
  444. * Check for errors. If we need to retry we mark the socket as pending
  445. * and return #F to tell the Scheme procedure to wait.
  446. */
  447. if (errno != EWOULDBLOCK && errno != EINTR && errno != EALREADY
  448. && errno != EINPROGRESS && errno != EAGAIN)
  449. s48_raise_os_error(errno);
  450. if (! (s48_add_pending_fd(socket_fd, PSFALSE)))
  451. s48_raise_out_of_memory_error();
  452. return S48_FALSE;
  453. }
  454. /*
  455. * We keep a hash table of the sockets we have corresponded with.
  456. *
  457. * Get the connection struct for `addr', creating a new one if necessary.
  458. * We hash the address and port to get an initial index into the `connections'
  459. * array and then search linearly from there.
  460. */
  461. static s48_value
  462. address_connection(struct sockaddr_in *addr)
  463. {
  464. return lookup_connection(addr->sin_addr, ntohs(addr->sin_port));
  465. }
  466. static s48_value
  467. s48_lookup_udp_address(s48_value name, s48_value port)
  468. {
  469. struct hostent * host = gethostbyname(s48_extract_byte_vector(name));
  470. struct in_addr address;
  471. if (host == NULL ||
  472. host->h_addrtype != AF_INET || /* could happen, I suppose */
  473. host->h_addr_list[0] == NULL)
  474. s48_raise_os_error(errno);
  475. address = *((struct in_addr *) host->h_addr_list[0]);
  476. return lookup_connection(address, s48_extract_fixnum(port));
  477. }
  478. /*
  479. * `port' should be in host byte order.
  480. */
  481. static s48_value
  482. lookup_connection(struct in_addr address, unsigned long port)
  483. {
  484. unsigned long hash = address_hash(address, port);
  485. int i = hash & connections_index_mask;
  486. while (1) {
  487. s48_value search = S48_UNSAFE_VECTOR_REF(connections, i);
  488. if (search == S48_FALSE)
  489. return add_new_connection(i, address, port);
  490. else if ((address.s_addr == UDP_ADDRESS_PTR(search)->s_addr)
  491. && port == UDP_PORT(search))
  492. return search;
  493. else
  494. i = (i + 1) & connections_index_mask; }
  495. }
  496. static s48_value
  497. address_hash(struct in_addr address, unsigned long port)
  498. {
  499. unsigned long hash = port ^ address.s_addr;
  500. return (hash >> 16) * (hash & 0xFFFF);
  501. }
  502. /*
  503. * Add a new connection record for `addr', putting it at `index' in the
  504. * connections' hash table.
  505. */
  506. static s48_value
  507. add_new_connection(int index, struct in_addr address, unsigned long port)
  508. {
  509. s48_value udp_address;
  510. s48_value sch_address;
  511. s48_value name;
  512. S48_DECLARE_GC_PROTECT(1);
  513. udp_address = s48_make_record(s48_udp_address_type_binding);
  514. S48_GC_PROTECT_1(udp_address);
  515. sch_address = S48_MAKE_VALUE(struct in_addr); /* may GC */
  516. S48_UNSAFE_EXTRACT_VALUE(sch_address, struct in_addr) = address;
  517. S48_UNSAFE_RECORD_SET(udp_address, 0, sch_address);
  518. S48_UNSAFE_RECORD_SET(udp_address, 1, S48_UNSAFE_ENTER_FIXNUM(port));
  519. name = get_hostname(address); /* may GC */
  520. S48_UNSAFE_RECORD_SET(udp_address, 2, name);
  521. S48_UNSAFE_VECTOR_SET(connections, index, udp_address);
  522. connection_count += 1;
  523. if (connection_count * 3 > connections_size)
  524. expand_and_rehash(); /* may GC */
  525. S48_GC_UNPROTECT();
  526. return udp_address;
  527. }
  528. /*
  529. * Get the name of the `addr''s host. If we can't get the real host name
  530. * we use the numbers-and-dots representation of the address.
  531. */
  532. static s48_value
  533. get_hostname(struct in_addr addr)
  534. {
  535. char *hostname;
  536. struct hostent *hostdata;
  537. hostdata = gethostbyaddr((char *) &addr, sizeof(struct in_addr), AF_INET);
  538. if (hostdata == NULL)
  539. hostname = inet_ntoa(addr);
  540. else
  541. hostname = hostdata->h_name;
  542. return s48_enter_string_latin_1(hostname);
  543. }
  544. /*
  545. * Double the size of the hash table and rehash all connections into it.
  546. */
  547. static void
  548. expand_and_rehash()
  549. {
  550. s48_value new_connections;
  551. long new_size = connections_size * 2;
  552. long new_index_mask = new_size - 1;
  553. long i;
  554. new_connections = s48_make_vector(new_size, S48_FALSE);
  555. for(i = 0; i < connections_size; i++) {
  556. s48_value next = S48_UNSAFE_VECTOR_REF(connections, i);
  557. if (next != S48_FALSE) {
  558. i = address_hash(*UDP_ADDRESS_PTR(next), UDP_PORT(next))
  559. & new_index_mask;
  560. for (; S48_UNSAFE_VECTOR_REF(new_connections, i) != S48_FALSE;
  561. i = (i + 1) & new_index_mask);
  562. S48_UNSAFE_VECTOR_SET(new_connections, i, next); }}
  563. connections = new_connections;
  564. connections_size = new_size;
  565. connections_index_mask = new_index_mask;
  566. }