1 #include "rktio.h"
2 #include "rktio_private.h"
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #ifdef HAVE_POLL_SYSCALL
7 # include <poll.h>
8 #endif
9 
10 #ifdef RKTIO_SYSTEM_UNIX
11 # include <unistd.h>
12 # include <netinet/in.h>
13 # include <netdb.h>
14 # include <sys/socket.h>
15 # include <sys/types.h>
16 # include <sys/time.h>
17 # include <fcntl.h>
18 # include <errno.h>
19 # define TCP_SOCKSENDBUF_SIZE 32768
20 # define NOT_WINSOCK(x) (x)
21 # define SOCK_ERRNO() errno
22 # define WAS_EAGAIN(e) ((e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS) || (e == EALREADY))
23 # define WAS_ECONNREFUSED(e) (e == ECONNREFUSED)
24 # define WAS_EBADADDRESS(e) (e == EINVAL)
25 # define WAS_WSAEMSGSIZE(e) 0
26 # define RKTIO_AFNOSUPPORT EAFNOSUPPORT
27 
28 #define RKTIO_SHUT_RD SHUT_RD
29 #define RKTIO_SHUT_WR SHUT_WR
30 
31 #define RKTIO_SOCKS(s) s
32 
33 typedef intptr_t rktio_socket_t;
34 typedef unsigned int rktio_sockopt_len_t;
35 
36 # define INVALID_SOCKET (-1)
37 
closesocket(rktio_socket_t s)38 static int closesocket(rktio_socket_t s) {
39   return rktio_reliably_close_err(s);
40 }
41 
42 typedef struct sockaddr_in rktio_unspec_address;
43 #define REGISTER_SOCKET(s) /**/
44 #define UNREGISTER_SOCKET(s) /**/
45 
46 #endif
47 
48 #ifdef CANT_SET_SOCKET_BUFSIZE
49 # undef SET_SOCKET_BUFFSIZE_ON_CREATE
50 #endif
51 
52 #ifdef SET_SOCKET_BUFFSIZE_ON_CREATE
53 # define RKTIO_WHEN_SET_SOCKBUF_SIZE(x) x
54 #else
55 # define RKTIO_WHEN_SET_SOCKBUF_SIZE(x) /* empty */
56 #endif
57 
58 #ifdef RKTIO_SYSTEM_WINDOWS
59 # include <process.h>
60 # include <winsock2.h>
61 # include <ws2tcpip.h>
62 # ifndef __MINGW32__
63 #  include <wspiapi.h>
64 # else
65 typedef int (WINAPI*gai_t)(const char*, const char*, const struct rktio_addrinfo_t *, struct rktio_addrinfo_t **);
66 typedef void (WINAPI*fai_t)(struct rktio_addrinfo_t *ai);
67 # endif
68 struct SOCKADDR_IN {
69   short sin_family;
70   unsigned short sin_port;
71   struct in_addr sin_addr;
72   char sin_zero[8];
73 };
74 # define NOT_WINSOCK(x) 0
75 # define SOCK_ERRNO() WSAGetLastError()
76 # define WAS_EAGAIN(e) ((e == WSAEWOULDBLOCK) || (e == WSAEINPROGRESS))
77 # define WAS_WSAEMSGSIZE(e) (e == WSAEMSGSIZE)
78 # define WAS_ECONNREFUSED(e) (e == WSAECONNREFUSED)
79 # define WAS_EBADADDRESS(e) 0
80 # define RKTIO_AFNOSUPPORT WSAEAFNOSUPPORT
81 
82 #define RKTIO_SHUT_RD SD_RECEIVE
83 #define RKTIO_SHUT_WR SD_SEND
84 
85 typedef SOCKET rktio_socket_t;
86 typedef int rktio_sockopt_len_t;
87 
88 /* Avoid warnings, since select() first argument is ignored: */
89 #define RKTIO_SOCKS(s) 0
90 
91 typedef struct SOCKADDR_IN rktio_unspec_address;
92 # define REGISTER_SOCKET(s) winsock_remember(s)
93 # define UNREGISTER_SOCKET(s) winsock_forget(s)
94 
95 # ifdef errno
96 #  undef errno
97 # endif
98 # define errno [do not use errno with winsock]
99 
100 #endif
101 
do_get_socket_error(rktio_t * rktio)102 static void do_get_socket_error(rktio_t *rktio) {
103   rktio->errid = SOCK_ERRNO();
104 #ifdef RKTIO_SYSTEM_WINDOWS
105   rktio->errkind = RKTIO_ERROR_KIND_WINDOWS;
106 #else
107   rktio->errkind = RKTIO_ERROR_KIND_POSIX;
108 #endif
109 }
110 #define get_socket_error() do_get_socket_error(rktio)
111 
do_set_socket_error(rktio_t * rktio,int errid)112 static void do_set_socket_error(rktio_t *rktio, int errid) {
113   rktio->errid = errid;
114 #ifdef RKTIO_SYSTEM_WINDOWS
115   rktio->errkind = RKTIO_ERROR_KIND_WINDOWS;
116 #else
117   rktio->errkind = RKTIO_ERROR_KIND_POSIX;
118 #endif
119 }
120 #define set_socket_error(errid) do_set_socket_error(rktio, errid)
121 
do_set_gai_error(rktio_t * rktio,int errid)122 static void do_set_gai_error(rktio_t *rktio, int errid) {
123   rktio->errid = errid;
124   rktio->errkind = RKTIO_ERROR_KIND_GAI;
125 }
126 #define set_gai_error(err) do_set_gai_error(rktio, err)
127 
128 #define TCP_BUFFER_SIZE 4096
129 
130 struct rktio_udp_t {
131   rktio_socket_t s;
132   char bound, connected;
133 };
134 
135 
136 #ifdef RKTIO_SYSTEM_WINDOWS
137 # define DECL_SOCK_FDSET(n) fd_set n[1]
138 # define INIT_DECL_SOCK_FDSET(r, w, e) /* empty */
139 # define INIT_DECL_SOCK_RD_FDSET(r) /* empty */
140 # define INIT_DECL_SOCK_WR_FDSET(r) /* empty */
141 # define INIT_DECL_SOCK_ER_FDSET(r) /* empty */
142 # define RKTIO_SOCK_FD_ZERO(p) FD_ZERO(p)
143 # define RKTIO_SOCK_FD_SET(n, p) FD_SET(n, p)
144 # define RKTIO_SOCK_FD_CLR(n, p) FD_CLR(n, p)
145 # define RKTIO_SOCK_FD_ISSET(n, p) FD_ISSET(n, p)
146 # define RKTIO_SOCK_FDS(p) (p)
147 #else
148 # define DECL_SOCK_FDSET(n) DECL_FDSET(n, 1)
149 # define INIT_DECL_SOCK_FDSET(r, w, e) INIT_DECL_FDSET(r, w, e)
150 # define INIT_DECL_SOCK_RD_FDSET(r) INIT_DECL_RD_FDSET(r)
151 # define INIT_DECL_SOCK_WR_FDSET(r) INIT_DECL_WR_FDSET(r)
152 # define INIT_DECL_SOCK_ER_FDSET(r) INIT_DECL_ER_FDSET(r)
153 # define RKTIO_SOCK_FD_ZERO(p) RKTIO_FD_ZERO(p)
154 # define RKTIO_SOCK_FD_SET(n, p) RKTIO_FD_SET(n, p)
155 # define RKTIO_SOCK_FD_CLR(n, p) RKTIO_FD_CLR(n, p)
156 # define RKTIO_SOCK_FD_ISSET(n, p) RKTIO_FD_ISSET(n, p)
157 # define RKTIO_SOCK_FDS(p) RKTIO_FDS(p)
158 #endif
159 
160 /*========================================================================*/
161 /* Host address lookup, including asynchronous-lookup support             */
162 /*========================================================================*/
163 
164 # ifdef PROTOENT_IS_INT
165 #  define PROTO_P_PROTO PROTOENT_IS_INT
166 # else
167 static struct protoent *proto;
168 #  define PROTO_P_PROTO (proto ? proto->p_proto : 0)
169 # endif
170 
171 # ifndef RKTIO_PF_INET
172 #  define RKTIO_PF_INET PF_INET
173 # endif
174 
175 /* For getting connection names: */
176 #define RKTIO_SOCK_NAME_MAX_LEN 256
177 #define RKTIO_SOCK_HOST_NAME_MAX_LEN 64
178 #define RKTIO_SOCK_SVC_NAME_MAX_LEN 32
179 
180 #if defined(HAVE_GETADDRINFO) || defined(__MINGW32__)
181 struct rktio_addrinfo_t {
182   struct addrinfo ai;
183 };
184 # define RKTIO_AS_ADDRINFO(x) (&(x)->ai)
185 # define RKTIO_AS_ADDRINFO_PTR(xp) ((struct addrinfo **)(xp))
186 #else
187 struct rktio_addrinfo_t {
188   int ai_flags;
189   int ai_family;
190   int ai_socktype;
191   int ai_protocol;
192   size_t  ai_addrlen;
193   struct sockaddr *ai_addr;
194   struct rktio_addrinfo_t *ai_next;
195 };
196 # define RKTIO_AS_ADDRINFO(x) x
197 # define RKTIO_AS_ADDRINFO_PTR(x) x
198 #endif
199 
200 #if defined(__MINGW32__) && !defined(HAVE_GETADDRINFO)
201 /* Although `configure` didn't discover it, we do have getaddrinfo()
202    from Winsock */
203 # define HAVE_GETADDRINFO
204 #endif
205 
206 /*****************************************************************/
207 /* Fallback using gethostbyname where getddrinfo isn't available */
208 
209 #ifdef HAVE_GETADDRINFO
210 # define rktio_AI_PASSIVE AI_PASSIVE
211 # define do_getaddrinfo(n, s, h, res) getaddrinfo(n, s, RKTIO_AS_ADDRINFO(h), RKTIO_AS_ADDRINFO_PTR(res))
212 # define do_freeaddrinfo freeaddrinfo
213 # ifndef RKTIO_SYSTEM_WINDOWS
214 #  define do_gai_strerror gai_strerror
215 # endif
216 #else
217 # define rktio_AI_PASSIVE 0
do_getaddrinfo(const char * nodename,const char * servname,const struct rktio_addrinfo_t * hints,struct rktio_addrinfo_t ** res)218 static int do_getaddrinfo(const char *nodename, const char *servname,
219 			  const struct rktio_addrinfo_t *hints, struct rktio_addrinfo_t **res)
220 {
221   struct hostent *h;
222 
223   if (nodename)
224     h = gethostbyname(nodename);
225   else
226     h = NULL;
227 
228   if (h || !nodename) {
229     struct rktio_addrinfo_t *ai;
230     struct sockaddr_in *sa;
231     int j, id = 0;
232 
233     ai = malloc(sizeof(struct rktio_addrinfo_t));
234     sa = malloc(sizeof(struct sockaddr_in));
235     ai->ai_addr = (struct sockaddr *)sa;
236 
237     ai->ai_addrlen = sizeof(struct sockaddr_in);
238     if (servname) {
239       for (j = 0; servname[j]; j++) {
240 	id = (id * 10) + (servname[j] - '0');
241       }
242     }
243 
244     ai->ai_family = RKTIO_PF_INET;
245     ai->ai_socktype = hints->ai_socktype;
246     ai->ai_protocol = hints->ai_protocol;
247     ai->ai_next = NULL;
248 
249     sa->sin_family = (id ? AF_INET : AF_UNSPEC);
250     j = htons(id);
251     sa->sin_port = j;
252     memset(&(sa->sin_addr), 0, sizeof(sa->sin_addr));
253     memset(&(sa->sin_zero), 0, sizeof(sa->sin_zero));
254     if (h)
255       memcpy(&sa->sin_addr, h->h_addr_list[0], h->h_length);
256 
257     *res = ai;
258     return 0;
259   }
260   return h_errno;
261 }
262 
do_freeaddrinfo(struct rktio_addrinfo_t * ai)263 void do_freeaddrinfo(struct rktio_addrinfo_t *ai)
264 {
265   free(ai->ai_addr);
266   free(ai);
267 }
268 
do_gai_strerror(int ecode)269 const char *do_gai_strerror(int ecode)
270 {
271   return hstrerror(ecode);
272 }
273 #endif
274 
275 /*******************************************************************/
276 /* Running getddrinfo in a separate thread to make it asynchronous */
277 
278 struct rktio_addrinfo_lookup_t {
279   int mode;
280 
281   char *name, *svc;
282   struct rktio_addrinfo_t *hints;
283 
284 #if defined(RKTIO_SYSTEM_WINDOWS) || defined(RKTIO_USE_PTHREADS)
285   /* For delivering the result: */
286   struct rktio_addrinfo_t *result;
287   int err;
288 
289   /* For signaling that the result is ready: */
290 # ifdef RKTIO_SYSTEM_WINDOWS
291   HANDLE done_sema;
292 # else
293   int done_fd[2];
294 # endif
295 
296   /* For chaining active requests: */
297   struct rktio_addrinfo_lookup_t *next;
298 #endif
299 };
300 
free_lookup(rktio_addrinfo_lookup_t * lookup)301 static void free_lookup(rktio_addrinfo_lookup_t *lookup)
302 {
303 #if defined(RKTIO_SYSTEM_WINDOWS) || defined(RKTIO_USE_PTHREADS)
304   if (lookup->result)
305     do_freeaddrinfo(RKTIO_AS_ADDRINFO(lookup->result));
306 #endif
307 
308   if (lookup->name)
309     free(lookup->name);
310   if (lookup->svc)
311     free(lookup->svc);
312   free(lookup->hints);
313   free(lookup);
314 }
315 
init_lookup(rktio_addrinfo_lookup_t * lookup)316 static void init_lookup(rktio_addrinfo_lookup_t *lookup)
317 {
318 #if defined(RKTIO_SYSTEM_WINDOWS) || defined(RKTIO_USE_PTHREADS)
319   lookup->result = NULL;
320 #endif
321 }
322 
323 #if defined(RKTIO_SYSTEM_WINDOWS) || defined(RKTIO_USE_PTHREADS)
324 
325 # ifdef RKTIO_SYSTEM_WINDOWS
326 #  ifdef __BORLANDC__
327 #   define RKTIO_LPTHREAD_START_ROUTINE unsigned int (__stdcall*)(void*)
328 #  else
329 #   define RKTIO_LPTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE
330 #  endif
331 # else
332 #  include <pthread.h>
333 #   define RKTIO_LPTHREAD_START_ROUTINE void *(*)(void *)
334 # endif
335 
336 #define GHBN_WAIT        1
337 #define GHBN_DONE        2
338 #define GHBN_ABANDONED   3
339 
340 # ifdef RKTIO_SYSTEM_WINDOWS
341 
ghbn_lock(rktio_t * rktio)342 static void ghbn_lock(rktio_t *rktio)
343 {
344   WaitForSingleObject(rktio->ghbn_lock, INFINITE);
345 }
346 
ghbn_unlock(rktio_t * rktio)347 static void ghbn_unlock(rktio_t *rktio)
348 {
349   ReleaseSemaphore(rktio->ghbn_lock, 1, NULL);
350 }
351 
ghbn_wait(rktio_t * rktio)352 static void ghbn_wait(rktio_t *rktio)
353 {
354   ghbn_unlock(rktio);
355   WaitForSingleObject(rktio->ghbn_start, INFINITE);
356   ghbn_lock(rktio);
357 }
358 
ghbn_signal(rktio_t * rktio)359 static void ghbn_signal(rktio_t *rktio)
360 {
361   ReleaseSemaphore(rktio->ghbn_start, 1, NULL);
362 }
363 
ghbn_wait_exit(rktio_t * rktio)364 static void ghbn_wait_exit(rktio_t *rktio)
365 {
366   WaitForSingleObject(rktio->ghbn_th, INFINITE);
367 }
368 
369 # else
370 
ghbn_lock(rktio_t * rktio)371 static void ghbn_lock(rktio_t *rktio)
372 {
373   pthread_mutex_lock(&rktio->ghbn_lock);
374 }
375 
ghbn_unlock(rktio_t * rktio)376 static void ghbn_unlock(rktio_t *rktio)
377 {
378   pthread_mutex_unlock(&rktio->ghbn_lock);
379 }
380 
ghbn_wait(rktio_t * rktio)381 static void ghbn_wait(rktio_t *rktio)
382 {
383   pthread_cond_wait(&rktio->ghbn_start, &rktio->ghbn_lock);
384 }
385 
ghbn_signal(rktio_t * rktio)386 static void ghbn_signal(rktio_t *rktio)
387 {
388   pthread_cond_signal(&rktio->ghbn_start);
389 }
390 
ghbn_wait_exit(rktio_t * rktio)391 static void ghbn_wait_exit(rktio_t *rktio)
392 {
393   pthread_join(rktio->ghbn_th, NULL);
394 }
395 
396 # endif
397 
getaddrinfo_in_thread(void * _data)398 static intptr_t getaddrinfo_in_thread(void *_data)
399 {
400   rktio_t *rktio = (rktio_t *)_data;
401   rktio_addrinfo_lookup_t *lookup;
402   rktio_addrinfo_t *result;
403   int err;
404 
405   ghbn_lock(rktio);
406   while (rktio->ghbn_run) {
407     lookup = rktio->ghbn_requests;
408     if (lookup) {
409       rktio->ghbn_requests = lookup->next;
410       ghbn_unlock(rktio);
411 
412       /* Handle one lookup request: */
413       err = do_getaddrinfo(lookup->name, lookup->svc, lookup->hints, &result);
414       lookup->err = err;
415       if (!err)
416         lookup->result = result;
417 
418       ghbn_lock(rktio);
419 
420 # ifdef RKTIO_SYSTEM_WINDOWS
421       ReleaseSemaphore(lookup->done_sema, 1, NULL);
422 # else
423       {
424         long v = 1;
425         do {
426           err = write(lookup->done_fd[1], &v, sizeof(v));
427         } while ((err == -1) && (errno == EINTR));
428         rktio_reliably_close(lookup->done_fd[1]);
429       }
430 # endif
431 
432       if (lookup->mode == GHBN_ABANDONED) {
433 # ifdef RKTIO_SYSTEM_WINDOWS
434         CloseHandle(lookup->done_sema);
435 # else
436         rktio_reliably_close(lookup->done_fd[0]);
437 # endif
438         free_lookup(lookup);
439       }
440     } else {
441       ghbn_wait(rktio);
442     }
443   }
444 
445   ghbn_unlock(rktio);
446 
447   return 0;
448 }
449 
450 # ifdef RKTIO_SYSTEM_WINDOWS
451 
win_getaddrinfo_in_thread(void * _data)452 static unsigned int WINAPI win_getaddrinfo_in_thread(void *_data)
453 {
454   return (unsigned int)getaddrinfo_in_thread(_data);
455 }
456 
ghbn_init(rktio_t * rktio)457 static int ghbn_init(rktio_t *rktio)
458 {
459   rktio->ghbn_lock = CreateSemaphore(NULL, 1, 1, NULL);
460   if (!rktio->ghbn_lock) {
461     get_windows_error();
462     return 0;
463   }
464   rktio->ghbn_start = CreateSemaphore(NULL, 0, 1, NULL);
465   if (!rktio->ghbn_start) {
466     get_windows_error();
467     return 0;
468   }
469   rktio->ghbn_th = (HANDLE)_beginthreadex(NULL, 5000,
470                                           win_getaddrinfo_in_thread,
471                                           rktio, 0, NULL);
472   if (rktio->ghbn_th == INVALID_HANDLE_VALUE) {
473     get_posix_error();
474     return 0;
475   }
476 
477   return 1;
478 }
479 
480 # else
481 
ghbn_init(rktio_t * rktio)482 static int ghbn_init(rktio_t *rktio)
483 {
484   if (pthread_mutex_init(&rktio->ghbn_lock, NULL)) {
485     get_posix_error();
486     return 0;
487   }
488   if (pthread_cond_init(&rktio->ghbn_start, NULL)) {
489     get_posix_error();
490     return 0;
491   }
492   if (pthread_create(&rktio->ghbn_th, NULL,
493                      (RKTIO_LPTHREAD_START_ROUTINE)getaddrinfo_in_thread,
494                      rktio)) {
495     return 0;
496   }
497   return 1;
498 }
499 
500 # endif
501 
rktio_free_ghbn(rktio_t * rktio)502 void rktio_free_ghbn(rktio_t *rktio)
503 {
504   if (rktio->ghbn_started) {
505     ghbn_lock(rktio);
506     rktio->ghbn_run = 0;
507     ghbn_signal(rktio);
508     ghbn_unlock(rktio);
509     ghbn_wait_exit(rktio);
510   }
511 }
512 
start_lookup(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)513 static rktio_addrinfo_lookup_t *start_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
514 {
515   lookup->mode = GHBN_WAIT;
516 
517   if (!rktio->ghbn_started) {
518     rktio->ghbn_run = 1;
519     if (!ghbn_init(rktio)) {
520       free_lookup(lookup);
521       return NULL;
522     }
523     rktio->ghbn_started = 1;
524   }
525 
526 # ifdef RKTIO_SYSTEM_WINDOWS
527   {
528     lookup->done_sema = CreateSemaphore(NULL, 0, 1, NULL);
529     if (!lookup->done_sema) {
530       get_windows_error();
531       free_lookup(lookup);
532       return NULL;
533     }
534   }
535 # else
536   if (pipe(lookup->done_fd)) {
537     get_posix_error();
538     free_lookup(lookup);
539     return NULL;
540   } else {
541     fcntl(lookup->done_fd[0], F_SETFL, RKTIO_NONBLOCKING);
542   }
543 # endif
544 
545   ghbn_lock(rktio);
546   lookup->next = rktio->ghbn_requests;
547   rktio->ghbn_requests = lookup;
548   ghbn_signal(rktio);
549   ghbn_unlock(rktio);
550 
551   return lookup;
552 }
553 
rktio_poll_addrinfo_lookup_ready(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)554 int rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
555 {
556   int done = 0;
557 
558   ghbn_lock(rktio);
559 
560   if (lookup->mode == GHBN_DONE) {
561     ghbn_unlock(rktio);
562     return RKTIO_POLL_READY;
563   }
564 
565 # ifdef RKTIO_SYSTEM_WINDOWS
566   if (WaitForSingleObject(lookup->done_sema, 0) == WAIT_OBJECT_0) {
567     CloseHandle(lookup->done_sema);
568     done = 1;
569   }
570 # else
571   {
572     long v;
573     int cr;
574     do {
575       cr = read(lookup->done_fd[0], &v, sizeof(long));
576     } while ((cr == -1) && (errno == EINTR));
577     if (cr > 0) {
578       rktio_reliably_close(lookup->done_fd[0]);
579       done = 1;
580     }
581   }
582 # endif
583 
584   if (done)
585     lookup->mode = GHBN_DONE;
586 
587   ghbn_unlock(rktio);
588 
589   return (done ? RKTIO_POLL_READY : 0);
590 }
591 
rktio_poll_add_addrinfo_lookup(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup,rktio_poll_set_t * fds)592 void rktio_poll_add_addrinfo_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup, rktio_poll_set_t *fds)
593 {
594   ghbn_lock(rktio);
595 
596   if (lookup->mode != GHBN_WAIT) {
597     ghbn_unlock(rktio);
598     rktio_poll_set_add_nosleep(rktio, fds);
599     return;
600   }
601 
602   ghbn_unlock(rktio);
603 
604 # ifdef RKTIO_SYSTEM_WINDOWS
605   rktio_poll_set_add_handle(rktio, (intptr_t)lookup->done_sema, fds, 1);
606 # else
607   {
608     rktio_poll_set_t *fds2;
609 
610     fds2 = RKTIO_GET_FDSET(fds, 2);
611 
612     RKTIO_FD_SET(lookup->done_fd[0], fds);
613     RKTIO_FD_SET(lookup->done_fd[0], fds2);
614   }
615 # endif
616 }
617 
rktio_addrinfo_lookup_stop(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)618 void rktio_addrinfo_lookup_stop(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
619 {
620   ghbn_lock(rktio);
621   if (lookup->mode != GHBN_DONE) {
622     lookup->mode = GHBN_ABANDONED;
623     ghbn_unlock(rktio);
624   } else {
625     ghbn_unlock(rktio);
626 # ifdef RKTIO_SYSTEM_WINDOWS
627     CloseHandle(lookup->done_sema);
628 # else
629     rktio_reliably_close(lookup->done_fd[0]);
630 # endif
631     free_lookup(lookup);
632   }
633 }
634 
rktio_addrinfo_lookup_get(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)635 rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
636 {
637   rktio_addrinfo_t *addr = NULL;
638 
639   if (lookup->err)
640     set_gai_error(lookup->err);
641   else {
642     addr = lookup->result;
643     lookup->result = NULL; /* so it's not freed */
644   }
645 
646   free_lookup(lookup);
647 
648   return addr;
649 }
650 
651 #else
652 
rktio_free_ghbn(rktio_t * rktio)653 void rktio_free_ghbn(rktio_t *rktio)
654 {
655 }
656 
start_lookup(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)657 static rktio_addrinfo_lookup_t *start_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
658 {
659   return lookup;
660 }
661 
rktio_poll_addrinfo_lookup_ready(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)662 int rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
663 {
664   return RKTIO_POLL_READY;
665 }
666 
rktio_poll_add_addrinfo_lookup(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup,rktio_poll_set_t * fds)667 void rktio_poll_add_addrinfo_lookup(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup, rktio_poll_set_t *fds)
668 {
669   rktio_poll_set_add_nosleep(rktio, fds);
670 }
671 
rktio_addrinfo_lookup_stop(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)672 void rktio_addrinfo_lookup_stop(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
673 {
674   free_lookup(lookup);
675 }
676 
rktio_addrinfo_lookup_get(rktio_t * rktio,rktio_addrinfo_lookup_t * lookup)677 rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup)
678 {
679   int err;
680   rktio_addrinfo_t *result;
681 
682   err = do_getaddrinfo(lookup->name, lookup->svc, lookup->hints, &result);
683   if (err)
684     set_gai_error(err);
685 
686   free_lookup(lookup);
687 
688   if (err)
689     return NULL;
690   else
691     return result;
692 }
693 
694 #endif
695 
rktio_get_ipv4_family(rktio_t * rktio)696 int rktio_get_ipv4_family(rktio_t *rktio)
697 {
698   return RKTIO_PF_INET;
699 }
700 
rktio_start_addrinfo_lookup(rktio_t * rktio,const char * hostname,int portno,int family,int passive,int tcp)701 rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio,
702                                                      const char *hostname, int portno,
703                                                      int family, int passive, int tcp)
704 {
705   rktio_addrinfo_lookup_t *lookup;
706   char buf[32], *service;
707   struct rktio_addrinfo_t *hints;
708 
709   if (portno >= 0) {
710     service = buf;
711     sprintf(buf, "%d", portno);
712   } else
713     service = NULL;
714 
715   if (!hostname && !service) {
716     set_racket_error(RKTIO_ERROR_HOST_AND_PORT_BOTH_UNSPECIFIED);
717     return NULL;
718   }
719 
720   hints = malloc(sizeof(rktio_addrinfo_t));
721   memset(hints, 0, sizeof(struct rktio_addrinfo_t));
722   RKTIO_AS_ADDRINFO(hints)->ai_family = ((family < 0) ? PF_UNSPEC : family);
723   if (passive) {
724     RKTIO_AS_ADDRINFO(hints)->ai_flags |= rktio_AI_PASSIVE;
725   }
726   if (tcp) {
727     RKTIO_AS_ADDRINFO(hints)->ai_socktype = SOCK_STREAM;
728 # ifndef PROTOENT_IS_INT
729     if (!proto) {
730       proto = getprotobyname("tcp");
731     }
732 # endif
733     RKTIO_AS_ADDRINFO(hints)->ai_protocol= PROTO_P_PROTO;
734   } else {
735     RKTIO_AS_ADDRINFO(hints)->ai_socktype = SOCK_DGRAM;
736   }
737 
738   lookup = malloc(sizeof(rktio_addrinfo_lookup_t));
739   lookup->name = (hostname ? MSC_IZE(strdup)(hostname) : NULL);
740   lookup->svc = (service ? MSC_IZE(strdup)(service) : NULL);
741   lookup->hints = hints;
742   init_lookup(lookup);
743 
744   return start_lookup(rktio, lookup);
745 }
746 
rktio_addrinfo_free(rktio_t * rktio,rktio_addrinfo_t * a)747 void rktio_addrinfo_free(rktio_t *rktio, rktio_addrinfo_t *a)
748 {
749   do_freeaddrinfo(RKTIO_AS_ADDRINFO(a));
750 }
751 
rktio_gai_strerror(rktio_t * rktio,int errnum)752 const char *rktio_gai_strerror(rktio_t *rktio, int errnum)
753 {
754 #ifdef RKTIO_SYSTEM_WINDOWS
755   char *s;
756   s = NARROW_PATH_copy(gai_strerrorW(errnum));
757   if (rktio->last_err_str)
758     free(rktio->last_err_str);
759   rktio->last_err_str = s;
760   return s;
761 #else
762   return do_gai_strerror(errnum);
763 #endif
764 }
765 
766 /*========================================================================*/
767 /* Winsock management                                                     */
768 /*========================================================================*/
769 
770 #ifdef RKTIO_SYSTEM_WINDOWS
771 
772 static HANDLE winsock_sema;
773 static int winsock_started = 0;
774 static int wsr_size = 0;
775 static rktio_socket_t *wsr_array;
776 
winsock_remember(rktio_socket_t s)777 static void winsock_remember(rktio_socket_t s)
778 {
779   int i, new_size;
780   rktio_socket_t *naya;
781 
782   WaitForSingleObject(winsock_sema, INFINITE);
783 
784   for (i = 0; i < wsr_size; i++) {
785     if (!wsr_array[i]) {
786       wsr_array[i] = s;
787       break;
788     }
789   }
790 
791   if (i >= wsr_size) {
792     if (!wsr_size) {
793       new_size = 32;
794     } else
795       new_size = 2 * wsr_size;
796 
797     naya = malloc(sizeof(rktio_socket_t) * new_size);
798     for (i = 0; i < wsr_size; i++) {
799       naya[i] = wsr_array[i];
800     }
801 
802     naya[wsr_size] = s;
803 
804     if (wsr_array) free(wsr_array);
805 
806     wsr_array = naya;
807     wsr_size = new_size;
808   }
809 
810   ReleaseSemaphore(winsock_sema, 1, NULL);
811 }
812 
winsock_forget(rktio_socket_t s)813 static void winsock_forget(rktio_socket_t s)
814 {
815   int i;
816 
817   WaitForSingleObject(winsock_sema, INFINITE);
818 
819   for (i = 0; i < wsr_size; i++) {
820     if (wsr_array[i] == s) {
821       wsr_array[i] = (rktio_socket_t)NULL;
822       break;
823     }
824   }
825 
826   ReleaseSemaphore(winsock_sema, 1, NULL);
827 }
828 
rktio_winsock_init(rktio_t * rktio)829 int rktio_winsock_init(rktio_t *rktio)
830 {
831   if (!winsock_sema) {
832     winsock_sema = CreateSemaphore(NULL, 1, 1, NULL);
833   }
834 
835   WaitForSingleObject(winsock_sema, INFINITE);
836 
837   if (!winsock_started) {
838     WSADATA data;
839     if (!WSAStartup(MAKEWORD(1, 1), &data)) {
840       winsock_started = 1;
841     } else {
842       get_windows_error();
843       ReleaseSemaphore(winsock_sema, 1, NULL);
844       return 0;
845     }
846   } else
847     winsock_started++;
848 
849   ReleaseSemaphore(winsock_sema, 1, NULL);
850 
851   return 1;
852 }
853 
rktio_winsock_done(rktio_t * rktio)854 void rktio_winsock_done(rktio_t *rktio)
855 {
856   int i;
857 
858   WaitForSingleObject(winsock_sema, INFINITE);
859 
860   if (!--winsock_started) {
861     for (i = 0; i < wsr_size; i++) {
862       if (wsr_array[i]) {
863         closesocket(wsr_array[i]);
864         wsr_array[i] = (rktio_socket_t)NULL;
865       }
866     }
867 
868     wsr_size = 0;
869     wsr_array = NULL;
870 
871     WSACleanup();
872   }
873 
874   ReleaseSemaphore(winsock_sema, 1, NULL);
875 }
876 #endif
877 
878 /*========================================================================*/
879 /* TCP sockets                                                            */
880 /*========================================================================*/
881 
rktio_fd_socket(rktio_t * rktio,rktio_fd_t * rfd)882 static rktio_socket_t rktio_fd_socket(rktio_t *rktio, rktio_fd_t *rfd)
883 {
884   return (rktio_socket_t)rktio_fd_system_fd(rktio, rfd);
885 }
886 
887 #ifdef RKTIO_SYSTEM_WINDOWS
rktio_internal_fd_socket(rktio_fd_t * rfd)888 static rktio_socket_t rktio_internal_fd_socket(rktio_fd_t *rfd)
889 {
890   return (rktio_socket_t)rktio_internal_fd_system_fd(rfd);
891 }
892 #endif
893 
rktio_socket_init(rktio_t * rktio,rktio_fd_t * rfd)894 void rktio_socket_init(rktio_t *rktio, rktio_fd_t *rfd)
895 {
896   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
897 
898 #ifdef RKTIO_SYSTEM_UNIX
899   fcntl(s, F_SETFL, RKTIO_NONBLOCKING);
900 #endif
901 #ifdef RKTIO_SYSTEM_WINDOWS
902   {
903     unsigned long ioarg = 1;
904     ioctlsocket(s, FIONBIO, &ioarg);
905   }
906 #endif
907 
908   if (rktio_fd_is_udp(rktio, rfd)) {
909 #ifdef RKTIO_SYSTEM_UNIX
910 # ifdef SO_BROADCAST
911     {
912       int bc = 1;
913       setsockopt(s, SOL_SOCKET, SO_BROADCAST, &bc, sizeof(bc));
914     }
915 # endif
916 #endif
917 #ifdef RKTIO_SYSTEM_WINDOWS
918     {
919       BOOL bc = 1;
920       setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)(&bc), sizeof(BOOL));
921     }
922 #endif
923   }
924 }
925 
rktio_socket_close(rktio_t * rktio,rktio_fd_t * rfd,int set_error)926 int rktio_socket_close(rktio_t *rktio /* may be NULL */, rktio_fd_t *rfd, int set_error)
927 {
928 #ifdef RKTIO_SYSTEM_UNIX
929   return rktio_internal_close(rktio, rfd, set_error);
930 #endif
931 #ifdef RKTIO_SYSTEM_WINDOWS
932   rktio_socket_t s = rktio_internal_fd_socket(rfd);
933   int err;
934   UNREGISTER_SOCKET(s);
935   err = closesocket(s);
936   if (!err && set_error)
937     get_socket_error();
938   free(rfd);
939 
940   return !err;
941 #endif
942 }
943 
rktio_socket_own(rktio_t * rktio,rktio_fd_t * rfd)944 void rktio_socket_own(rktio_t *rktio, rktio_fd_t *rfd)
945 {
946 #ifdef RKTIO_SYSTEM_WINDOWS
947   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
948   REGISTER_SOCKET(s);
949 #endif
950 }
951 
rktio_socket_forget_owned(rktio_t * rktio,rktio_fd_t * rfd)952 void rktio_socket_forget_owned(rktio_t *rktio, rktio_fd_t *rfd)
953 {
954 #ifdef RKTIO_SYSTEM_WINDOWS
955   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
956   UNREGISTER_SOCKET(s);
957 #endif
958 }
959 
rktio_socket_shutdown(rktio_t * rktio,rktio_fd_t * rfd,int mode)960 int rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, int mode)
961 {
962   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
963 
964   if (shutdown(s, ((mode == RKTIO_SHUTDOWN_READ) ? RKTIO_SHUT_RD : RKTIO_SHUT_WR))) {
965     get_socket_error();
966     return 0;
967   }
968 
969   return 1;
970 }
971 
rktio_socket_poll_write_ready(rktio_t * rktio,rktio_fd_t * rfd)972 int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd)
973 {
974 #ifdef RKTIO_SYSTEM_UNIX
975   return rktio_poll_write_ready(rktio, rfd);
976 #endif
977 #ifdef RKTIO_SYSTEM_WINDOWS
978   {
979     rktio_socket_t s = rktio_fd_socket(rktio, rfd);
980     DECL_SOCK_FDSET(writefds);
981     DECL_SOCK_FDSET(exnfds);
982     struct timeval time = {0, 0};
983     int sr;
984 
985     INIT_DECL_SOCK_WR_FDSET(writefds);
986     INIT_DECL_SOCK_ER_FDSET(exnfds);
987 
988     RKTIO_SOCK_FD_ZERO(writefds);
989     RKTIO_SOCK_FD_SET(s, writefds);
990     RKTIO_SOCK_FD_ZERO(exnfds);
991     RKTIO_SOCK_FD_SET(s, exnfds);
992 
993     sr = select(RKTIO_SOCKS(s + 1), NULL, writefds, exnfds, &time);
994 
995     if (sr == -1) {
996       get_socket_error();
997       return RKTIO_POLL_ERROR;
998     } else if (sr)
999       return RKTIO_POLL_READY;
1000     else
1001       return 0;
1002   }
1003 #endif
1004 }
1005 
rktio_socket_poll_read_ready(rktio_t * rktio,rktio_fd_t * rfd)1006 int rktio_socket_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd)
1007 {
1008 #ifdef RKTIO_SYSTEM_UNIX
1009   return rktio_poll_read_ready(rktio, rfd);
1010 #endif
1011 #ifdef RKTIO_SYSTEM_WINDOWS
1012   {
1013     rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1014     DECL_SOCK_FDSET(readfds);
1015     DECL_SOCK_FDSET(exnfds);
1016     struct timeval time = {0, 0};
1017     int sr;
1018 
1019     INIT_DECL_SOCK_WR_FDSET(readfds);
1020     INIT_DECL_SOCK_ER_FDSET(exnfds);
1021 
1022     RKTIO_SOCK_FD_ZERO(readfds);
1023     RKTIO_SOCK_FD_SET(s, readfds);
1024     RKTIO_SOCK_FD_ZERO(exnfds);
1025     RKTIO_SOCK_FD_SET(s, exnfds);
1026 
1027     sr = select(RKTIO_SOCKS(s + 1), readfds, NULL, exnfds, &time);
1028 
1029     if (sr == -1) {
1030       get_socket_error();
1031       return RKTIO_POLL_ERROR;
1032     } else if (sr)
1033       return RKTIO_POLL_READY;
1034     else
1035       return 0;
1036   }
1037 #endif
1038 }
1039 
rktio_socket_dup(rktio_t * rktio,rktio_fd_t * rfd)1040 rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd)
1041 {
1042 #ifdef RKTIO_SYSTEM_UNIX
1043   return rktio_dup(rktio, rfd);
1044 #endif
1045 #ifdef RKTIO_SYSTEM_WINDOWS
1046   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1047   rktio_socket_t nsocket;
1048   intptr_t rc;
1049   WSAPROTOCOL_INFO protocolInfo;
1050   rc = WSADuplicateSocket(s, GetCurrentProcessId(), &protocolInfo);
1051   if (rc) {
1052     get_socket_error();
1053     return NULL;
1054   }
1055   nsocket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &protocolInfo, 0, WSA_FLAG_OVERLAPPED);
1056   if (nsocket == INVALID_SOCKET) {
1057     get_socket_error();
1058     return NULL;
1059   }
1060   return rktio_system_fd(rktio, nsocket, rktio_fd_modes(rktio, rfd) | RKTIO_OPEN_OWN);
1061 #endif
1062 }
1063 
rktio_socket_read(rktio_t * rktio,rktio_fd_t * rfd,char * buffer,intptr_t len)1064 intptr_t rktio_socket_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
1065 {
1066   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1067   int rn;
1068 
1069   len = LIMIT_REQUEST_SIZE(len);
1070 
1071   do {
1072     rn = recv(s, buffer, len, 0);
1073   } while ((rn == -1) && NOT_WINSOCK(errno == EINTR));
1074 
1075   if (rn > 0)
1076     return rn;
1077   else if (rn == 0)
1078     return RKTIO_READ_EOF;
1079   else {
1080     int err = SOCK_ERRNO();
1081     if (WAS_EAGAIN(err))
1082       return 0;
1083     else {
1084       get_socket_error();
1085       return RKTIO_READ_ERROR;
1086     }
1087   }
1088 }
1089 
do_socket_write(rktio_t * rktio,rktio_fd_t * rfd,const char * buffer,intptr_t len,rktio_addrinfo_t * addr)1090 static intptr_t do_socket_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr_t len,
1091                                 /* for UDP sendto: */
1092                                 rktio_addrinfo_t *addr)
1093 {
1094   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1095   intptr_t sent;
1096   int errid = 0;
1097 
1098 #ifdef RKTIO_SYSTEM_WINDOWS
1099 # define SEND_BAD_MSG_SIZE(e) (e == WSAEMSGSIZE)
1100 #else
1101 # ifdef SEND_IS_NEVER_TOO_BIG
1102 #  define SEND_BAD_MSG_SIZE(errid) 0
1103 # else
1104 #  define SEND_BAD_MSG_SIZE(errid) (errid == EMSGSIZE)
1105 # endif
1106 #endif
1107 
1108   while (1) {
1109     if (addr) {
1110       /* Use first address that doesn't result in a bad-address error: */
1111       for (; addr; addr = (rktio_addrinfo_t *)RKTIO_AS_ADDRINFO(addr)->ai_next) {
1112         do {
1113           sent = sendto(s, buffer, len, 0,
1114                         RKTIO_AS_ADDRINFO(addr)->ai_addr, RKTIO_AS_ADDRINFO(addr)->ai_addrlen);
1115         } while ((sent == -1) && NOT_WINSOCK(errno == EINTR));
1116         if (sent >= 0)
1117           break;
1118         errid = SOCK_ERRNO();
1119         if (!WAS_EBADADDRESS(errid))
1120           break;
1121       }
1122     } else {
1123       do {
1124         sent = send(s, buffer, len, 0);
1125       } while ((sent == -1) && NOT_WINSOCK(errno == EINTR));
1126 
1127       if (sent == -1)
1128         errid = SOCK_ERRNO();
1129     }
1130 
1131     if (sent >= 0)
1132       return sent;
1133 
1134     if (WAS_EAGAIN(errid))
1135       return 0;
1136     else if (SEND_BAD_MSG_SIZE(errid) && (len > 1)) {
1137       /* split the message and try again: */
1138       len >>= 1;
1139     } else {
1140       get_socket_error();
1141       return RKTIO_WRITE_ERROR;
1142     }
1143   }
1144 }
1145 
rktio_socket_write(rktio_t * rktio,rktio_fd_t * rfd,const char * buffer,intptr_t len)1146 intptr_t rktio_socket_write(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr_t len)
1147 {
1148   return do_socket_write(rktio, rfd, buffer, LIMIT_REQUEST_SIZE(len), NULL);
1149 }
1150 
1151 /*========================================================================*/
1152 /* TCP connect                                                            */
1153 /*========================================================================*/
1154 
1155 struct rktio_connect_t {
1156   int inprogress, failed;
1157   rktio_fd_t *trying_fd;
1158   rktio_addrinfo_t *dest, *src;
1159   rktio_addrinfo_t *addr; /* walking through dest */
1160 };
1161 
1162 static rktio_connect_t *try_connect(rktio_t *rktio, rktio_connect_t *conn);
1163 
rktio_start_connect(rktio_t * rktio,rktio_addrinfo_t * dest,rktio_addrinfo_t * src)1164 rktio_connect_t *rktio_start_connect(rktio_t *rktio, rktio_addrinfo_t *dest, rktio_addrinfo_t *src)
1165 {
1166   rktio_connect_t *conn;
1167 
1168   conn = malloc(sizeof(rktio_connect_t));
1169   conn->dest = dest;
1170   conn->src = src;
1171   conn->addr = dest;
1172 
1173   if (!try_connect(rktio, conn)) {
1174     free(conn);
1175     return NULL;
1176   }
1177 
1178   return conn;
1179 }
1180 
try_connect(rktio_t * rktio,rktio_connect_t * conn)1181 static rktio_connect_t *try_connect(rktio_t *rktio, rktio_connect_t *conn)
1182 {
1183   struct rktio_addrinfo_t *addr;
1184   rktio_socket_t s;
1185 
1186   addr = conn->addr;
1187   s = socket(RKTIO_AS_ADDRINFO(addr)->ai_family,
1188              RKTIO_AS_ADDRINFO(addr)->ai_socktype,
1189              RKTIO_AS_ADDRINFO(addr)->ai_protocol);
1190   if (s != INVALID_SOCKET) {
1191     int status, inprogress;
1192     if (!conn->src
1193         || !bind(s, RKTIO_AS_ADDRINFO(conn->src)->ai_addr, RKTIO_AS_ADDRINFO(conn->src)->ai_addrlen)) {
1194 #ifdef RKTIO_SYSTEM_WINDOWS
1195       unsigned long ioarg = 1;
1196       ioctlsocket(s, FIONBIO, &ioarg);
1197 #else
1198       RKTIO_WHEN_SET_SOCKBUF_SIZE(int size = TCP_SOCKSENDBUF_SIZE);
1199       fcntl(s, F_SETFL, RKTIO_NONBLOCKING);
1200       RKTIO_WHEN_SET_SOCKBUF_SIZE(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(int)));
1201 #endif
1202 
1203       status = connect(s, RKTIO_AS_ADDRINFO(addr)->ai_addr, RKTIO_AS_ADDRINFO(addr)->ai_addrlen);
1204 
1205 #ifdef RKTIO_SYSTEM_UNIX
1206       if (status)
1207         status = errno;
1208       if (status == EINTR)
1209         status = EINPROGRESS;
1210 
1211       inprogress = (status == EINPROGRESS);
1212 #endif
1213 #ifdef RKTIO_SYSTEM_WINDOWS
1214       if (status)
1215         status = WSAGetLastError();
1216 
1217       inprogress = (status == WSAEWOULDBLOCK);
1218 #endif
1219 
1220       conn->trying_fd = rktio_system_fd(rktio,
1221                                         (intptr_t)s,
1222                                         RKTIO_OPEN_SOCKET | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE | RKTIO_OPEN_OWN);
1223       conn->inprogress = inprogress;
1224       conn->failed = (inprogress ? 0 : status);
1225 
1226       return conn;
1227     }
1228   }
1229 
1230   get_socket_error();
1231   return NULL;
1232 }
1233 
rktio_poll_connect_ready(rktio_t * rktio,rktio_connect_t * conn)1234 int rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn)
1235 {
1236   if (conn->inprogress)
1237     return rktio_socket_poll_write_ready(rktio, conn->trying_fd);
1238   else
1239     return RKTIO_POLL_READY;
1240 }
1241 
rktio_poll_add_connect(rktio_t * rktio,rktio_connect_t * conn,rktio_poll_set_t * fds)1242 void rktio_poll_add_connect(rktio_t *rktio, rktio_connect_t *conn, rktio_poll_set_t *fds)
1243 {
1244   if (conn->inprogress)
1245     rktio_poll_add(rktio, conn->trying_fd, fds, RKTIO_POLL_WRITE);
1246   else
1247     rktio_poll_set_add_nosleep(rktio, fds);
1248 }
1249 
conn_free(rktio_connect_t * conn)1250 static void conn_free(rktio_connect_t *conn)
1251 {
1252   free(conn);
1253 }
1254 
rktio_connect_finish(rktio_t * rktio,rktio_connect_t * conn)1255 rktio_fd_t *rktio_connect_finish(rktio_t *rktio, rktio_connect_t *conn)
1256 {
1257   rktio_fd_t *rfd = conn->trying_fd;
1258 
1259   if (conn->inprogress || conn->failed) {
1260     /* Check whether connect succeeded, or get error: */
1261     int errid;
1262     if (conn->failed) {
1263       errid = conn->failed;
1264     } else {
1265       unsigned status;
1266       rktio_sockopt_len_t so_len = sizeof(status);
1267       rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1268       if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&status, &so_len) != 0) {
1269         errid = SOCK_ERRNO();
1270       } else
1271         errid = status;
1272 #ifdef RKTIO_SYSTEM_WINDOWS
1273       if (!rktio->windows_nt_or_later && !errid) {
1274         /* getsockopt() seems not to work in Windows 95, so use the
1275            result from select(), which seems to reliably detect an error condition */
1276         if (rktio_poll_connect_ready(rktio, conn) == RKTIO_POLL_ERROR) {
1277           errid = WSAECONNREFUSED; /* guess! */
1278         }
1279       }
1280 #endif
1281     }
1282 
1283     if (errid) {
1284       rktio_close(rktio, rfd);
1285       if (RKTIO_AS_ADDRINFO(conn->addr)->ai_next) {
1286         /* try the next one */
1287         conn->addr = (rktio_addrinfo_t *)RKTIO_AS_ADDRINFO(conn->addr)->ai_next;
1288         if (try_connect(rktio, conn)) {
1289           set_racket_error(RKTIO_ERROR_CONNECT_TRYING_NEXT);
1290           return NULL;
1291         } else {
1292           /* error was set by try_error() */
1293           conn_free(conn);
1294           return NULL;
1295         }
1296       } else {
1297         set_socket_error(errid);
1298         conn_free(conn);
1299         return NULL;
1300       }
1301     }
1302   }
1303 
1304   conn_free(conn);
1305 
1306   return rfd;
1307 }
1308 
rktio_connect_stop(rktio_t * rktio,rktio_connect_t * conn)1309 void rktio_connect_stop(rktio_t *rktio, rktio_connect_t *conn)
1310 {
1311   rktio_close(rktio, conn->trying_fd);
1312 
1313   conn_free(conn);
1314 }
1315 
rktio_connect_trying(rktio_t * rktio,rktio_connect_t * conn)1316 rktio_fd_t *rktio_connect_trying(rktio_t *rktio, rktio_connect_t *conn)
1317 {
1318   return conn->trying_fd;
1319 }
1320 
1321 /*========================================================================*/
1322 /* TCP listener and accept                                                */
1323 /*========================================================================*/
1324 
1325 struct rktio_listener_t {
1326   int count;
1327 # ifdef HAVE_POLL_SYSCALL
1328   struct pollfd *pfd;
1329 # endif
1330   rktio_socket_t s[];
1331 };
1332 
1333 static int get_no_portno(rktio_t *rktio, rktio_socket_t socket);
1334 
rktio_listen(rktio_t * rktio,rktio_addrinfo_t * src,int backlog,int reuse)1335 rktio_listener_t *rktio_listen(rktio_t *rktio, rktio_addrinfo_t *src, int backlog, int reuse)
1336 {
1337   {
1338     rktio_addrinfo_t *addr;
1339     int count = 0, pos = 0;
1340     rktio_listener_t *l = NULL;
1341 #ifdef RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
1342     int any_v4 = 0, any_v6 = 0;
1343 #endif
1344 
1345     for (addr = src; addr; addr = (rktio_addrinfo_t *)RKTIO_AS_ADDRINFO(addr)->ai_next) {
1346 #ifdef RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
1347       if (RKTIO_AS_ADDRINFO(addr)->ai_family == RKTIO_PF_INET)
1348 	any_v4 = 1;
1349       else if (RKTIO_AS_ADDRINFO(addr)->ai_family == PF_INET6)
1350 	any_v6 = 1;
1351 #endif
1352       count++;
1353     }
1354 
1355     {
1356       rktio_socket_t s;
1357 #ifdef RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
1358       /* Try IPv6 listeners first, so we can retry and use just IPv4 if
1359 	 IPv6 doesn't work right. */
1360       int v6_loop = (any_v6 && any_v4), skip_v6 = 0;
1361 #endif
1362       int first_time = 1;
1363       int first_was_zero = 0;
1364       unsigned short no_port = 0;
1365 
1366       for (addr = src; addr; ) {
1367 #ifdef RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
1368 	if ((v6_loop && (RKTIO_AS_ADDRINFO(addr)->ai_family != PF_INET6))
1369 	    || (skip_v6 && (RKTIO_AS_ADDRINFO(addr)->ai_family == PF_INET6))) {
1370 	  addr = (rktio_addrinfo_t *)RKTIO_AS_ADDRINFO(addr)->ai_next;
1371 	  if (v6_loop && !addr) {
1372 	    v6_loop = 0;
1373 	    skip_v6 = 1;
1374 	    addr = src;
1375 	  }
1376 	  continue;
1377 	}
1378 #endif
1379 
1380 	s = socket(RKTIO_AS_ADDRINFO(addr)->ai_family,
1381                    RKTIO_AS_ADDRINFO(addr)->ai_socktype,
1382                    RKTIO_AS_ADDRINFO(addr)->ai_protocol);
1383         if (s != INVALID_SOCKET)
1384           get_socket_error();
1385 
1386 #ifdef RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
1387 	if (s == INVALID_SOCKET) {
1388 	  /* Maybe it failed because IPv6 is not available: */
1389 	  if ((RKTIO_AS_ADDRINFO(addr)->ai_family == PF_INET6) && (errno == EAFNOSUPPORT)) {
1390 	    if (any_v4 && !pos) {
1391 	      /* Let client known that maybe we can make it work with just IPv4. */
1392 	      set_racket_error(RKTIO_ERROR_TRY_AGAIN_WITH_IPV4);
1393 	    }
1394 	  }
1395 	}
1396 	if (s != INVALID_SOCKET) {
1397 	  if (any_v4 && (RKTIO_AS_ADDRINFO(addr)->ai_family == PF_INET6)) {
1398 	    int ok;
1399 # ifdef IPV6_V6ONLY
1400 	    int on = 1;
1401 	    ok = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
1402 # else
1403 	    ok = -1;
1404 # endif
1405 	    if (ok) {
1406 	      if (!pos) {
1407 		/* IPV6_V6ONLY doesn't work */
1408                 set_racket_error(RKTIO_ERROR_TRY_AGAIN_WITH_IPV4);
1409                 s = INVALID_SOCKET;
1410 	      } else {
1411                 get_socket_error();
1412 		closesocket(s);
1413 		s = INVALID_SOCKET;
1414 	      }
1415 	    }
1416 	  }
1417 	}
1418 #endif
1419 
1420 	if (s != INVALID_SOCKET) {
1421 #ifdef RKTIO_SYSTEM_WINDOWS
1422 	  unsigned long ioarg = 1;
1423 	  ioctlsocket(s, FIONBIO, &ioarg);
1424 #else
1425 	  fcntl(s, F_SETFL, RKTIO_NONBLOCKING);
1426 #endif
1427 
1428 	  if (reuse) {
1429 	    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuse), sizeof(int));
1430 	  }
1431 
1432           if (first_was_zero) {
1433             ((struct sockaddr_in *)RKTIO_AS_ADDRINFO(addr)->ai_addr)->sin_port = no_port;
1434           }
1435 	  if (!bind(s, RKTIO_AS_ADDRINFO(addr)->ai_addr, RKTIO_AS_ADDRINFO(addr)->ai_addrlen)) {
1436             if (first_time) {
1437               if (((struct sockaddr_in *)RKTIO_AS_ADDRINFO(addr)->ai_addr)->sin_port == 0) {
1438                 no_port = get_no_portno(rktio, s);
1439                 first_was_zero = 1;
1440 		if (no_port < 0) {
1441 		  closesocket(s);
1442 		  break;
1443 		}
1444               }
1445               first_time = 0;
1446             }
1447 
1448 	    if (!listen(s, backlog)) {
1449 	      if (!pos) {
1450 		l = malloc(sizeof(rktio_listener_t) + (count * sizeof(rktio_socket_t)));
1451 		l->count = count;
1452 # ifdef HAVE_POLL_SYSCALL
1453                 {
1454                   struct pollfd *pfd;
1455                   pfd = malloc(sizeof(struct pollfd) * count);
1456                   l->pfd = pfd;
1457                 }
1458 # endif
1459 	      }
1460 # ifdef HAVE_POLL_SYSCALL
1461               l->pfd[pos].fd = s;
1462               l->pfd[pos].events = POLLIN;
1463 # endif
1464 	      l->s[pos++] = s;
1465 
1466 	      REGISTER_SOCKET(s);
1467 
1468 	      if (pos == count) {
1469 		return l;
1470 	      }
1471 	    } else {
1472               get_socket_error();
1473 	      closesocket(s);
1474 	      break;
1475 	    }
1476 	  } else {
1477             get_socket_error();
1478 	    closesocket(s);
1479 	    break;
1480 	  }
1481 	} else {
1482           break;
1483         }
1484 
1485 	addr = (rktio_addrinfo_t *)RKTIO_AS_ADDRINFO(addr)->ai_next;
1486 
1487 #ifdef RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
1488 	if (!addr && v6_loop) {
1489 	  v6_loop = 0;
1490 	  skip_v6 = 1;
1491 	  addr = src;
1492 	}
1493 #endif
1494       }
1495 
1496       if (l) {
1497         l->count = pos;
1498         rktio_listen_stop(rktio, l);
1499       }
1500 
1501       return NULL;
1502     }
1503   }
1504 }
1505 
get_no_portno(rktio_t * rktio,rktio_socket_t socket)1506 static int get_no_portno(rktio_t *rktio, rktio_socket_t socket)
1507 {
1508   char here[RKTIO_SOCK_NAME_MAX_LEN];
1509   struct sockaddr_in *addr_in;
1510   rktio_sockopt_len_t l = sizeof(here);
1511   unsigned short no_port;
1512 
1513   if (getsockname(socket, (struct sockaddr *)here, &l)) {
1514     get_socket_error();
1515     return -1;
1516   }
1517 
1518   /* don't use ntohs, since the result is put back into another sin_port: */
1519   addr_in = (struct sockaddr_in *)here;
1520   no_port = addr_in->sin_port;
1521   return no_port;
1522 }
1523 
rktio_listen_stop(rktio_t * rktio,rktio_listener_t * l)1524 void rktio_listen_stop(rktio_t *rktio, rktio_listener_t *l)
1525 {
1526   int i;
1527   rktio_socket_t s;
1528 
1529   for (i = 0; i < l->count; i++) {
1530     s = l->s[i];
1531     UNREGISTER_SOCKET(s);
1532     closesocket(s);
1533   }
1534 
1535 #ifdef HAVE_POLL_SYSCALL
1536   free(l->pfd);
1537 #endif
1538 
1539   free(l);
1540 }
1541 
do_poll_accept_ready(rktio_t * rktio,rktio_listener_t * listener,int report_which)1542 static int do_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener, int report_which)
1543 {
1544   int sr, i;
1545 
1546 #ifdef HAVE_POLL_SYSCALL
1547   do {
1548     sr = poll(listener->pfd, listener->count, 0);
1549   } while ((sr == -1) && (errno == EINTR));
1550 
1551   if (sr > 0) {
1552     if (report_which) {
1553       for (i = listener->count; i--; ) {
1554         if (listener->pfd[i].revents)
1555           return i + 1;
1556       }
1557     } else
1558       return RKTIO_POLL_READY;
1559   }
1560 
1561   if (sr == -1) {
1562     get_socket_error();
1563     return RKTIO_POLL_ERROR;
1564   } else
1565     return 0;
1566 #else
1567   rktio_socket_t s, mx;
1568   DECL_SOCK_FDSET(readfds);
1569   DECL_SOCK_FDSET(exnfds);
1570   struct timeval time = {0, 0};
1571 
1572   INIT_DECL_SOCK_RD_FDSET(readfds);
1573   INIT_DECL_SOCK_ER_FDSET(exnfds);
1574 
1575   RKTIO_SOCK_FD_ZERO(readfds);
1576   RKTIO_SOCK_FD_ZERO(exnfds);
1577 
1578   mx = 0;
1579   for (i = 0; i < listener->count; i++) {
1580     s = listener->s[i];
1581     RKTIO_SOCK_FD_SET(s, readfds);
1582     RKTIO_SOCK_FD_SET(s, exnfds);
1583     if (s > mx)
1584       mx = s;
1585   }
1586 
1587   do {
1588     sr = select(RKTIO_SOCKS(mx + 1), RKTIO_SOCK_FDS(readfds), NULL, RKTIO_SOCK_FDS(exnfds), &time);
1589   } while ((sr == -1) && NOT_WINSOCK(errno == EINTR));
1590 
1591   if (sr > 0) {
1592     if (report_which) {
1593       for (i = 0; i < listener->count; i++) {
1594         s = listener->s[i];
1595         if (RKTIO_SOCK_FD_ISSET(s, readfds)
1596             || RKTIO_SOCK_FD_ISSET(s, exnfds))
1597           return i + 1;
1598       }
1599     } else
1600       return RKTIO_POLL_READY;
1601   }
1602 
1603   if (sr == -1) {
1604     get_socket_error();
1605     return RKTIO_POLL_ERROR;
1606   } else
1607     return 0;
1608 #endif
1609 }
1610 
rktio_poll_accept_ready(rktio_t * rktio,rktio_listener_t * listener)1611 int rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener)
1612 {
1613   return do_poll_accept_ready(rktio, listener, 0);
1614 }
1615 
rktio_poll_add_accept(rktio_t * rktio,rktio_listener_t * listener,rktio_poll_set_t * fds)1616 void rktio_poll_add_accept(rktio_t *rktio, rktio_listener_t *listener, rktio_poll_set_t *fds)
1617 {
1618   int i;
1619   rktio_socket_t s;
1620   rktio_poll_set_t *fds2;
1621 
1622   fds2 = RKTIO_GET_FDSET(fds, 2);
1623 
1624   for (i = 0; i < listener->count; i++) {
1625     s = listener->s[i];
1626     RKTIO_FD_SET((intptr_t)s, fds);
1627     RKTIO_FD_SET((intptr_t)s, fds2);
1628   }
1629 }
1630 
rktio_accept(rktio_t * rktio,rktio_listener_t * listener)1631 rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener)
1632 {
1633   int
1634     ready_pos;
1635   rktio_socket_t s, ls;
1636   rktio_sockopt_len_t l;
1637   char tcp_accept_addr[RKTIO_SOCK_NAME_MAX_LEN];
1638 
1639   ready_pos = do_poll_accept_ready(rktio, listener, 1);
1640   if (!ready_pos) {
1641     set_racket_error(RKTIO_ERROR_ACCEPT_NOT_READY);
1642     return NULL;
1643   }
1644 
1645   ls = listener->s[ready_pos-1];
1646 
1647   l = sizeof(tcp_accept_addr);
1648 
1649   do {
1650     s = accept(ls, (struct sockaddr *)tcp_accept_addr, &l);
1651   } while ((s == -1) && NOT_WINSOCK(errno == EINTR));
1652 
1653   if (s != INVALID_SOCKET) {
1654 # ifdef RKTIO_SYSTEM_UNIX
1655     RKTIO_WHEN_SET_SOCKBUF_SIZE(int size = TCP_SOCKSENDBUF_SIZE);
1656     RKTIO_WHEN_SET_SOCKBUF_SIZE(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(int)));
1657 #  endif
1658 
1659     return rktio_system_fd(rktio, s, (RKTIO_OPEN_SOCKET | RKTIO_OPEN_INIT | RKTIO_OPEN_OWN
1660 				      | RKTIO_OPEN_READ | RKTIO_OPEN_WRITE));
1661   } else {
1662     get_socket_error();
1663     return NULL;
1664   }
1665 }
1666 
get_numeric_strings(rktio_t * rktio,void * sa,unsigned int salen)1667 static char **get_numeric_strings(rktio_t *rktio, void *sa, unsigned int salen)
1668 {
1669   char **r;
1670   int err;
1671 #ifdef HAVE_GETADDRINFO
1672   char host[NI_MAXHOST], serv[NI_MAXSERV];
1673 
1674   err = getnameinfo(sa, salen, host, sizeof(host), serv, sizeof(serv),
1675                     NI_NUMERICHOST | NI_NUMERICSERV);
1676 #else
1677   char host[128], serv[32];
1678   {
1679     unsigned char *b;
1680     b = (unsigned char *)&((struct sockaddr_in *)sa)->sin_addr;
1681     sprintf(host, "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
1682   }
1683   {
1684     int id;
1685     id = ntohs(((struct sockaddr_in *)sa)->sin_port);
1686     sprintf(serv, "%d", id);
1687   }
1688   err = 0;
1689 #endif
1690 
1691   if (!err) {
1692     r = malloc(sizeof(char*) * 2);
1693     r[0] = MSC_IZE(strdup)(host);
1694     r[1] = MSC_IZE(strdup)(serv);
1695     return r;
1696   } else {
1697     set_gai_error(err);
1698     return NULL;
1699   }
1700 }
1701 
rktio_socket_address(rktio_t * rktio,rktio_fd_t * rfd)1702 char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd)
1703 {
1704   char name[RKTIO_SOCK_NAME_MAX_LEN];
1705   rktio_sockopt_len_t name_len;
1706 
1707   name_len = sizeof(name);
1708   if (getsockname(rktio_fd_socket(rktio, rfd), (struct sockaddr *)name, &name_len)) {
1709     get_socket_error();
1710     return NULL;
1711   }
1712 
1713   return get_numeric_strings(rktio, name, name_len);
1714 }
1715 
rktio_socket_peer_address(rktio_t * rktio,rktio_fd_t * rfd)1716 char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd)
1717 {
1718   char name[RKTIO_SOCK_NAME_MAX_LEN];
1719   rktio_sockopt_len_t name_len;
1720 
1721   name_len = sizeof(name);
1722   if (getpeername(rktio_fd_socket(rktio, rfd), (struct sockaddr *)name, &name_len)) {
1723     get_socket_error();
1724     return NULL;
1725   }
1726 
1727   return get_numeric_strings(rktio, name, name_len);
1728 }
1729 
rktio_listener_address(rktio_t * rktio,rktio_listener_t * lnr)1730 char **rktio_listener_address(rktio_t *rktio, rktio_listener_t *lnr)
1731 {
1732   char name[RKTIO_SOCK_NAME_MAX_LEN];
1733   rktio_sockopt_len_t name_len;
1734 
1735   name_len = sizeof(name);
1736   if (getsockname(lnr->s[0], (struct sockaddr *)name, &name_len)) {
1737     get_socket_error();
1738     return NULL;
1739   }
1740 
1741   return get_numeric_strings(rktio, name, name_len);
1742 }
1743 
1744 /*========================================================================*/
1745 /* UDP                                                                    */
1746 /*========================================================================*/
1747 
rktio_udp_open(rktio_t * rktio,rktio_addrinfo_t * addr,int family)1748 rktio_fd_t *rktio_udp_open(rktio_t *rktio, rktio_addrinfo_t *addr, int family)
1749 {
1750   rktio_socket_t s;
1751 
1752   if (addr)
1753     s = socket(RKTIO_AS_ADDRINFO(addr)->ai_family,
1754                RKTIO_AS_ADDRINFO(addr)->ai_socktype,
1755                RKTIO_AS_ADDRINFO(addr)->ai_protocol);
1756   else
1757     s = socket(family, SOCK_DGRAM, 0);
1758 
1759   if (s == INVALID_SOCKET) {
1760     get_socket_error();
1761     return NULL;
1762   }
1763 
1764   return rktio_system_fd(rktio, s, RKTIO_OPEN_SOCKET | RKTIO_OPEN_UDP | RKTIO_OPEN_INIT);
1765 }
1766 
1767 #ifdef UDP_DISCONNECT_EADRNOTAVAIL_OK
1768 # define OK_DISCONNECT_ERROR(e) (((e) == RKTIO_AFNOSUPPORT) || ((e) == EADDRNOTAVAIL))
1769 #else
1770 # define OK_DISCONNECT_ERROR(e) ((e) == RKTIO_AFNOSUPPORT)
1771 #endif
1772 
rktio_udp_disconnect(rktio_t * rktio,rktio_fd_t * rfd)1773 int rktio_udp_disconnect(rktio_t *rktio, rktio_fd_t *rfd)
1774 {
1775   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1776   int err;
1777 
1778 #ifdef USE_NULL_TO_DISCONNECT_UDP
1779   err = connect(s, NULL, 0);
1780 #else
1781   rktio_unspec_address ua;
1782   ua.sin_family = AF_UNSPEC;
1783   ua.sin_port = 0;
1784   memset(&(ua.sin_addr), 0, sizeof(ua.sin_addr));
1785   memset(&(ua.sin_zero), 0, sizeof(ua.sin_zero));
1786   err = connect(s, (struct sockaddr *)&ua, sizeof(ua));
1787 #endif
1788 
1789   if (err) {
1790     err = SOCK_ERRNO();
1791     if (OK_DISCONNECT_ERROR(err))
1792       err = 0;
1793   }
1794 
1795   if (err) {
1796     get_socket_error();
1797     return 0;
1798   }
1799 
1800   return 1;
1801 }
1802 
rktio_udp_bind(rktio_t * rktio,rktio_fd_t * rfd,rktio_addrinfo_t * addr,rktio_bool_t reuse)1803 int rktio_udp_bind(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, rktio_bool_t reuse)
1804 {
1805   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1806   int err;
1807 
1808   if (reuse) {
1809     int one = 1;
1810     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one))) {
1811       get_socket_error();
1812       return 0;
1813     }
1814   }
1815 
1816   /* bind using first address that works: */
1817   for (; addr; addr = (rktio_addrinfo_t *)RKTIO_AS_ADDRINFO(addr)->ai_next) {
1818     err = bind(s, RKTIO_AS_ADDRINFO(addr)->ai_addr, RKTIO_AS_ADDRINFO(addr)->ai_addrlen);
1819     if (!err) {
1820       return 1;
1821     }
1822   }
1823 
1824   get_socket_error();
1825   return 0;
1826 }
1827 
rktio_udp_connect(rktio_t * rktio,rktio_fd_t * rfd,rktio_addrinfo_t * addr)1828 int rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr)
1829 {
1830   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1831   int err;
1832 
1833   /* connect using first address that works: */
1834   for (; addr; addr = (rktio_addrinfo_t *)RKTIO_AS_ADDRINFO(addr)->ai_next) {
1835     err = connect(s, RKTIO_AS_ADDRINFO(addr)->ai_addr, RKTIO_AS_ADDRINFO(addr)->ai_addrlen);
1836     if (!err) {
1837       return 1;
1838     }
1839   }
1840 
1841   get_socket_error();
1842   return 0;
1843 }
1844 
rktio_udp_sendto(rktio_t * rktio,rktio_fd_t * rfd,rktio_addrinfo_t * addr,const char * buffer,intptr_t len)1845 intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, const char *buffer, intptr_t len)
1846 {
1847   return do_socket_write(rktio, rfd, buffer, len, addr);
1848 }
1849 
rktio_udp_sendto_in(rktio_t * rktio,rktio_fd_t * rfd,rktio_addrinfo_t * addr,const char * buffer,intptr_t start,intptr_t end)1850 intptr_t rktio_udp_sendto_in(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, const char *buffer,
1851                              intptr_t start, intptr_t end)
1852 {
1853   return rktio_udp_sendto(rktio, rfd, addr, buffer + start, end - start);
1854 }
1855 
rktio_udp_recvfrom(rktio_t * rktio,rktio_fd_t * rfd,char * buffer,intptr_t len)1856 rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
1857 {
1858   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1859   rktio_length_and_addrinfo_t *r;
1860   int rn, errid;
1861   char src_addr[RKTIO_SOCK_NAME_MAX_LEN];
1862   rktio_sockopt_len_t asize = sizeof(src_addr);
1863 
1864   while (1) {
1865     if (!len) {
1866       /* recvfrom() doesn't necessarily wait if you pass a buffer size of 0;
1867          to be consistent with accepting a message but discarding bytes that
1868          don't fit, accept at least one byte and turn a `1` result into `0` */
1869       char buf[1];
1870       rn = recvfrom(s, buf, 1, 0, (struct sockaddr *)src_addr, &asize);
1871       if (rn == 1)
1872         rn = 0;
1873     } else
1874       rn = recvfrom(s, buffer, len, 0, (struct sockaddr *)src_addr, &asize);
1875 
1876     if (rn < 0) {
1877       errid = SOCK_ERRNO();
1878       if (WAS_ECONNREFUSED(errid)) {
1879         /* Delayed ICMP error. Client should ignore it and try again. */
1880         set_racket_error(RKTIO_ERROR_INFO_TRY_AGAIN);
1881         return NULL;
1882       } else if (WAS_WSAEMSGSIZE(errid)) {
1883         /* => data truncated on Windows, which counts as success on Unix */
1884         rn = len;
1885         break;
1886       } else if (NOT_WINSOCK(errid == EINTR)) {
1887         /* try again */
1888       } else if (WAS_EAGAIN(errid)) {
1889         /* no data available */
1890         set_racket_error(RKTIO_ERROR_TRY_AGAIN);
1891         return NULL;
1892       } else {
1893         get_socket_error();
1894         return NULL;
1895       }
1896     } else
1897       break;
1898   }
1899 
1900   r = malloc(sizeof(rktio_length_and_addrinfo_t));
1901   r->len = rn;
1902   r->address = get_numeric_strings(rktio, src_addr, asize);
1903 
1904   return r;
1905 }
1906 
rktio_udp_recvfrom_in(rktio_t * rktio,rktio_fd_t * rfd,char * buffer,intptr_t start,intptr_t end)1907 rktio_length_and_addrinfo_t *rktio_udp_recvfrom_in(rktio_t *rktio, rktio_fd_t *rfd,
1908                                                    char *buffer, intptr_t start, intptr_t end)
1909 {
1910   return rktio_udp_recvfrom(rktio, rfd, buffer + start, end - start);
1911 }
1912 
rktio_udp_set_receive_buffer_size(rktio_t * rktio,rktio_fd_t * rfd,int size)1913 int rktio_udp_set_receive_buffer_size(rktio_t *rktio, rktio_fd_t *rfd, int size)
1914 {
1915   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1916   int status;
1917 
1918   status = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void *)&size, sizeof(size));
1919 
1920   if (status) {
1921     get_socket_error();
1922     return 0;
1923   } else
1924     return 1;
1925 }
1926 
rktio_udp_get_multicast_loopback(rktio_t * rktio,rktio_fd_t * rfd)1927 int rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd)
1928 {
1929   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1930   u_char loop;
1931   rktio_sockopt_len_t loop_len = sizeof(loop);
1932   int status;
1933 
1934   status = getsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&loop, &loop_len);
1935 
1936   if (status) {
1937     get_socket_error();
1938     return RKTIO_PROP_ERROR;
1939   } else
1940     return (loop ? 1 : 0);
1941 }
1942 
rktio_udp_set_multicast_loopback(rktio_t * rktio,rktio_fd_t * rfd,int on)1943 int rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, int on)
1944 {
1945   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1946   u_char loop = (on ? 1 : 0);
1947   rktio_sockopt_len_t loop_len = sizeof(loop);
1948   int status;
1949 
1950   status = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&loop, loop_len);
1951 
1952   if (status) {
1953     get_socket_error();
1954     return 0;
1955   } else
1956     return 1;
1957 }
1958 
rktio_udp_get_ttl(rktio_t * rktio,rktio_fd_t * rfd)1959 int rktio_udp_get_ttl(rktio_t *rktio, rktio_fd_t *rfd)
1960 {
1961   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1962   int ttl;
1963   rktio_sockopt_len_t ttl_len = sizeof(ttl);
1964   int status;
1965 
1966   status = getsockopt(s, IPPROTO_IP, IP_TTL, (void *)&ttl, &ttl_len);
1967 
1968   if (status) {
1969     get_socket_error();
1970     return RKTIO_PROP_ERROR;
1971   } else
1972     return ttl;
1973 }
1974 
rktio_udp_set_ttl(rktio_t * rktio,rktio_fd_t * rfd,int ttl_val)1975 int rktio_udp_set_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val)
1976 {
1977   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1978   int ttl = ttl_val;
1979   rktio_sockopt_len_t ttl_len = sizeof(ttl);
1980   int status;
1981 
1982   status = setsockopt(s, IPPROTO_IP, IP_TTL, (void *)&ttl, ttl_len);
1983 
1984   if (status) {
1985     get_socket_error();
1986     return 0;
1987   } else
1988     return 1;
1989 }
1990 
rktio_udp_get_multicast_ttl(rktio_t * rktio,rktio_fd_t * rfd)1991 int rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd)
1992 {
1993   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
1994   u_char ttl;
1995   rktio_sockopt_len_t ttl_len = sizeof(ttl);
1996   int status;
1997 
1998   status = getsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, &ttl_len);
1999 
2000   if (status) {
2001     get_socket_error();
2002     return RKTIO_PROP_ERROR;
2003   } else
2004     return ttl;
2005 }
2006 
rktio_udp_set_multicast_ttl(rktio_t * rktio,rktio_fd_t * rfd,int ttl_val)2007 int rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val)
2008 {
2009   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
2010   u_char ttl = ttl_val;
2011   rktio_sockopt_len_t ttl_len = sizeof(ttl);
2012   int status;
2013 
2014   status = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, ttl_len);
2015 
2016   if (status) {
2017     get_socket_error();
2018     return 0;
2019   } else
2020     return 1;
2021 }
2022 
rktio_udp_multicast_interface(rktio_t * rktio,rktio_fd_t * rfd)2023 char *rktio_udp_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd)
2024 {
2025   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
2026   struct in_addr intf;
2027   rktio_sockopt_len_t intf_len = sizeof(intf);
2028   int status;
2029 
2030   status = getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (void *)&intf, &intf_len);
2031 
2032   if (status) {
2033     get_socket_error();
2034     return NULL;
2035   } else {
2036     char host_buf[RKTIO_SOCK_HOST_NAME_MAX_LEN];
2037     unsigned char *b = (unsigned char *) &intf; /* yes, this is in network order */
2038     sprintf(host_buf, "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
2039     return MSC_IZE(strdup)(host_buf);
2040   }
2041 }
2042 
rktio_udp_set_multicast_interface(rktio_t * rktio,rktio_fd_t * rfd,rktio_addrinfo_t * intf_addr)2043 int rktio_udp_set_multicast_interface(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *intf_addr)
2044 {
2045   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
2046   struct in_addr intf;
2047   rktio_sockopt_len_t intf_len = sizeof(intf);
2048   int status;
2049 
2050   if (!intf_addr) {
2051     intf.s_addr = INADDR_ANY;
2052   } else {
2053     intf = ((struct sockaddr_in *)RKTIO_AS_ADDRINFO(intf_addr)->ai_addr)->sin_addr;
2054   }
2055 
2056   status = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (void *)&intf, intf_len);
2057 
2058   if (status) {
2059     get_socket_error();
2060     return 0;
2061   } else
2062     return 1;
2063 }
2064 
rktio_udp_change_multicast_group(rktio_t * rktio,rktio_fd_t * rfd,rktio_addrinfo_t * group_addr,rktio_addrinfo_t * intf_addr,int action)2065 int rktio_udp_change_multicast_group(rktio_t *rktio, rktio_fd_t *rfd,
2066                                      rktio_addrinfo_t *group_addr,
2067                                      rktio_addrinfo_t *intf_addr,
2068                                      int action)
2069 {
2070   rktio_socket_t s = rktio_fd_socket(rktio, rfd);
2071   struct ip_mreq mreq;
2072   rktio_sockopt_len_t mreq_len = sizeof(mreq);
2073   int status;
2074   int optname;
2075 
2076   if (!intf_addr) {
2077     mreq.imr_interface.s_addr = INADDR_ANY;
2078   } else {
2079     mreq.imr_interface = ((struct sockaddr_in *)RKTIO_AS_ADDRINFO(intf_addr)->ai_addr)->sin_addr;
2080   }
2081 
2082   mreq.imr_multiaddr = ((struct sockaddr_in *)RKTIO_AS_ADDRINFO(group_addr)->ai_addr)->sin_addr;
2083 
2084   if (action == RKTIO_ADD_MEMBERSHIP)
2085     optname = IP_ADD_MEMBERSHIP;
2086   else
2087     optname = IP_DROP_MEMBERSHIP;
2088 
2089   status = setsockopt(s, IPPROTO_IP, optname, (void *) &mreq, mreq_len);
2090 
2091   if (status) {
2092     get_socket_error();
2093     return 0;
2094   } else
2095     return 1;
2096 }
2097