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