]> jfr.im git - solanum.git/blame - librb/src/commio.c
Fix Clang 6 compiler warnings
[solanum.git] / librb / src / commio.c
CommitLineData
db137867
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * commio.c: Network/file related functions
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 *
db137867 24 */
c056dba2 25
fe037171
EM
26#include <librb_config.h>
27#include <rb_lib.h>
db137867
AC
28#include <commio-int.h>
29#include <commio-ssl.h>
30#include <event-int.h>
31#ifdef HAVE_SYS_UIO_H
32#include <sys/uio.h>
33#endif
34#define HAVE_SSL 1
35
36#ifndef MSG_NOSIGNAL
37#define MSG_NOSIGNAL 0
38#endif
39
40
41struct timeout_data
42{
43 rb_fde_t *F;
44 rb_dlink_node node;
45 time_t timeout;
46 PF *timeout_handler;
47 void *timeout_data;
48};
49
50rb_dlink_list *rb_fd_table;
51static rb_bh *fd_heap;
52
53static rb_dlink_list timeout_list;
54static rb_dlink_list closed_list;
55
56static struct ev_entry *rb_timeout_ev;
57
58
59static const char *rb_err_str[] = { "Comm OK", "Error during bind()",
60 "Error during DNS lookup", "connect timeout",
61 "Error during connect()",
3cbcc111
JT
62 "Comm Error",
63 "Error with SSL"
db137867
AC
64};
65
66/* Highest FD and number of open FDs .. */
67static int number_fd = 0;
3202e249 68int rb_maxconnections = 0;
db137867
AC
69
70static PF rb_connect_timeout;
589dbf4d 71static PF rb_connect_outcome;
db137867 72static void mangle_mapped_sockaddr(struct sockaddr *in);
db137867
AC
73
74#ifndef HAVE_SOCKETPAIR
339150ec 75static int rb_inet_socketpair(int d, int type, int protocol, rb_platform_fd_t sv[2]);
3202e249 76static int rb_inet_socketpair_udp(rb_fde_t **newF1, rb_fde_t **newF2);
db137867
AC
77#endif
78
79static inline rb_fde_t *
dc7e6b42 80add_fd(rb_platform_fd_t fd)
db137867
AC
81{
82 rb_fde_t *F = rb_find_fd(fd);
db137867
AC
83
84 /* look up to see if we have it already */
85 if(F != NULL)
3202e249
VY
86 return F;
87
db137867
AC
88 F = rb_bh_alloc(fd_heap);
89 F->fd = fd;
a9fb3ed0 90 rb_dlinkAdd(F, &F->node, &rb_fd_table[rb_hash_fd(fd)]);
3202e249 91 return (F);
db137867
AC
92}
93
94static inline void
95remove_fd(rb_fde_t *F)
96{
db137867
AC
97 if(F == NULL || !IsFDOpen(F))
98 return;
3202e249 99
a9fb3ed0 100 rb_dlinkMoveNode(&F->node, &rb_fd_table[rb_hash_fd(F->fd)], &closed_list);
db137867
AC
101}
102
3202e249 103static void
db137867
AC
104free_fds(void)
105{
106 rb_fde_t *F;
107 rb_dlink_node *ptr, *next;
108 RB_DLINK_FOREACH_SAFE(ptr, next, closed_list.head)
109 {
110 F = ptr->data;
ff0414c8
SA
111
112 number_fd--;
113
114#ifdef _WIN32
115 if(F->type & (RB_FD_SOCKET | RB_FD_PIPE))
116 closesocket(F->fd);
117 else
118#endif
119 close(F->fd);
120
db137867
AC
121 rb_dlinkDelete(ptr, &closed_list);
122 rb_bh_free(fd_heap, F);
123 }
124}
125
126/* 32bit solaris is kinda slow and stdio only supports fds < 256
127 * so we got to do this crap below.
128 * (BTW Fuck you Sun, I hate your guts and I hope you go bankrupt soon)
129 */
130
131#if defined (__SVR4) && defined (__sun)
132static void
133rb_fd_hack(int *fd)
134{
135 int newfd;
136 if(*fd > 256 || *fd < 0)
137 return;
138 if((newfd = fcntl(*fd, F_DUPFD, 256)) != -1)
139 {
140 close(*fd);
141 *fd = newfd;
142 }
143 return;
144}
145#else
146#define rb_fd_hack(fd)
147#endif
148
149
150/* close_all_connections() can be used *before* the system come up! */
151
152static void
153rb_close_all(void)
154{
3202e249 155#ifndef _WIN32
db137867 156 int i;
db137867
AC
157
158 /* XXX someone tell me why we care about 4 fd's ? */
159 /* XXX btw, fd 3 is used for profiler ! */
3202e249 160 for(i = 3; i < rb_maxconnections; ++i)
db137867
AC
161 {
162 close(i);
163 }
db137867
AC
164#endif
165}
166
167/*
168 * get_sockerr - get the error value from the socket or the current errno
169 *
170 * Get the *real* error from the socket (well try to anyway..).
171 * This may only work when SO_DEBUG is enabled but its worth the
172 * gamble anyway.
173 */
174int
175rb_get_sockerr(rb_fde_t *F)
176{
177 int errtmp;
178 int err = 0;
179 rb_socklen_t len = sizeof(err);
180
181 if(!(F->type & RB_FD_SOCKET))
182 return errno;
183
184 rb_get_errno();
185 errtmp = errno;
186
187#ifdef SO_ERROR
3202e249
VY
188 if(F != NULL
189 && !getsockopt(rb_get_fd(F), SOL_SOCKET, SO_ERROR, (char *)&err, (rb_socklen_t *) & len))
db137867
AC
190 {
191 if(err)
192 errtmp = err;
193 }
194 errno = errtmp;
195#endif
196 return errtmp;
197}
198
199/*
200 * rb_getmaxconnect - return the max number of connections allowed
201 */
202int
203rb_getmaxconnect(void)
204{
3202e249 205 return (rb_maxconnections);
db137867
AC
206}
207
208/*
209 * set_sock_buffers - set send and receive buffers for socket
55abcbb2 210 *
db137867
AC
211 * inputs - fd file descriptor
212 * - size to set
213 * output - returns true (1) if successful, false (0) otherwise
214 * side effects -
215 */
216int
217rb_set_buffers(rb_fde_t *F, int size)
218{
219 if(F == NULL)
220 return 0;
221 if(setsockopt
3202e249
VY
222 (F->fd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size))
223 || setsockopt(F->fd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)))
db137867
AC
224 return 0;
225 return 1;
226}
227
228/*
55abcbb2 229 * set_non_blocking - Set the client connection into non-blocking mode.
db137867
AC
230 *
231 * inputs - fd to set into non blocking mode
232 * output - 1 if successful 0 if not
233 * side effects - use POSIX compliant non blocking and
234 * be done with it.
235 */
236int
237rb_set_nb(rb_fde_t *F)
238{
239 int nonb = 0;
240 int res;
dc7e6b42 241 rb_platform_fd_t fd;
db137867
AC
242 if(F == NULL)
243 return 0;
244 fd = F->fd;
3202e249 245
db137867
AC
246 if((res = rb_setup_fd(F)))
247 return res;
248#ifdef O_NONBLOCK
249 nonb |= O_NONBLOCK;
250 res = fcntl(fd, F_GETFL, 0);
251 if(-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1)
252 return 0;
253#else
254 nonb = 1;
255 res = 0;
256 if(ioctl(fd, FIONBIO, (char *)&nonb) == -1)
257 return 0;
258#endif
259
260 return 1;
261}
262
263/*
264 * rb_settimeout() - set the socket timeout
265 *
266 * Set the timeout for the fd
267 */
268void
269rb_settimeout(rb_fde_t *F, time_t timeout, PF * callback, void *cbdata)
270{
271 struct timeout_data *td;
272
273 if(F == NULL)
274 return;
275
276 lrb_assert(IsFDOpen(F));
277 td = F->timeout;
3202e249 278 if(callback == NULL) /* user wants to remove */
db137867
AC
279 {
280 if(td == NULL)
281 return;
282 rb_dlinkDelete(&td->node, &timeout_list);
283 rb_free(td);
284 F->timeout = NULL;
3202e249 285 if(rb_dlink_list_length(&timeout_list) == 0)
db137867
AC
286 {
287 rb_event_delete(rb_timeout_ev);
288 rb_timeout_ev = NULL;
289 }
290 return;
291 }
292
293 if(F->timeout == NULL)
3202e249
VY
294 td = F->timeout = rb_malloc(sizeof(struct timeout_data));
295
db137867
AC
296 td->F = F;
297 td->timeout = rb_current_time() + timeout;
298 td->timeout_handler = callback;
299 td->timeout_data = cbdata;
300 rb_dlinkAdd(td, &td->node, &timeout_list);
301 if(rb_timeout_ev == NULL)
302 {
3202e249 303 rb_timeout_ev = rb_event_add("rb_checktimeouts", rb_checktimeouts, NULL, 5);
db137867
AC
304 }
305}
306
307/*
308 * rb_checktimeouts() - check the socket timeouts
309 *
310 * All this routine does is call the given callback/cbdata, without closing
311 * down the file descriptor. When close handlers have been implemented,
312 * this will happen.
313 */
314void
8679c0fe 315rb_checktimeouts(void *notused __attribute__((unused)))
db137867
AC
316{
317 rb_dlink_node *ptr, *next;
318 struct timeout_data *td;
319 rb_fde_t *F;
320 PF *hdl;
321 void *data;
322
323 RB_DLINK_FOREACH_SAFE(ptr, next, timeout_list.head)
324 {
325 td = ptr->data;
326 F = td->F;
327 if(F == NULL || !IsFDOpen(F))
328 continue;
329
330 if(td->timeout < rb_current_time())
331 {
332 hdl = td->timeout_handler;
333 data = td->timeout_data;
334 rb_dlinkDelete(&td->node, &timeout_list);
335 F->timeout = NULL;
336 rb_free(td);
337 hdl(F, data);
3202e249 338 }
db137867
AC
339 }
340}
341
c6ad9b0c
SA
342static int
343rb_setsockopt_reuseaddr(rb_fde_t *F)
344{
345 int opt_one = 1;
346 int ret;
347
348 ret = setsockopt(F->fd, SOL_SOCKET, SO_REUSEADDR, &opt_one, sizeof(opt_one));
349 if (ret) {
350 rb_lib_log("rb_setsockopt_reuseaddr: Cannot set SO_REUSEADDR for FD %d: %s",
351 F->fd, strerror(rb_get_sockerr(F)));
352 return ret;
353 }
354
355 return 0;
356}
357
358#ifdef HAVE_LIBSCTP
359static int
360rb_setsockopt_sctp(rb_fde_t *F)
361{
362 int opt_zero = 0;
363 int opt_one = 1;
268044ea
SA
364 /* workaround for https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/sctp?id=299ee123e19889d511092347f5fc14db0f10e3a6 */
365 char *env_mapped = getenv("SCTP_I_WANT_MAPPED_V4_ADDR");
366 int opt_mapped = env_mapped != NULL ? atoi(env_mapped) : opt_zero;
c6ad9b0c
SA
367 int ret;
368 struct sctp_initmsg initmsg;
369 struct sctp_rtoinfo rtoinfo;
370 struct sctp_paddrparams paddrparams;
371 struct sctp_assocparams assocparams;
372
373 ret = setsockopt(F->fd, SOL_SCTP, SCTP_NODELAY, &opt_one, sizeof(opt_one));
374 if (ret) {
375 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_NODELAY for fd %d: %s",
376 F->fd, strerror(rb_get_sockerr(F)));
377 return ret;
378 }
379
268044ea 380 ret = setsockopt(F->fd, SOL_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &opt_mapped, sizeof(opt_mapped));
c6ad9b0c
SA
381 if (ret) {
382 rb_lib_log("rb_setsockopt_sctp: Cannot unset SCTP_I_WANT_MAPPED_V4_ADDR for fd %d: %s",
383 F->fd, strerror(rb_get_sockerr(F)));
384 return ret;
385 }
386
387 /* Configure INIT message to specify that we only want one stream */
388 memset(&initmsg, 0, sizeof(initmsg));
389 initmsg.sinit_num_ostreams = 1;
390 initmsg.sinit_max_instreams = 1;
391
392 ret = setsockopt(F->fd, SOL_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
393 if (ret) {
394 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_INITMSG for fd %d: %s",
395 F->fd, strerror(rb_get_sockerr(F)));
396 return ret;
397 }
398
399 /* Configure RTO values to reduce the maximum timeout */
400 memset(&rtoinfo, 0, sizeof(rtoinfo));
401 rtoinfo.srto_initial = 3000;
402 rtoinfo.srto_min = 1000;
403 rtoinfo.srto_max = 10000;
404
405 ret = setsockopt(F->fd, SOL_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo));
406 if (ret) {
407 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_RTOINFO for fd %d: %s",
408 F->fd, strerror(rb_get_sockerr(F)));
409 return ret;
410 }
411
412 /*
413 * Configure peer address parameters to ensure that we monitor the connection
414 * more often than the default and don't timeout retransmit attempts before
415 * the ping timeout does.
416 *
417 * Each peer address will timeout reachability in about 750s.
418 */
419 memset(&paddrparams, 0, sizeof(paddrparams));
420 paddrparams.spp_assoc_id = 0;
421 memcpy(&paddrparams.spp_address, &in6addr_any, sizeof(in6addr_any));
422 paddrparams.spp_pathmaxrxt = 50;
423 paddrparams.spp_hbinterval = 5000;
424 paddrparams.spp_flags |= SPP_HB_ENABLE;
425
426 ret = setsockopt(F->fd, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams));
427 if (ret) {
428 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_PEER_ADDR_PARAMS for fd %d: %s",
429 F->fd, strerror(rb_get_sockerr(F)));
430 return ret;
431 }
432
433 /* Configure association parameters for retransmit attempts as above */
434 memset(&assocparams, 0, sizeof(assocparams));
435 assocparams.sasoc_assoc_id = 0;
436 assocparams.sasoc_asocmaxrxt = 50;
437
438 ret = setsockopt(F->fd, SOL_SCTP, SCTP_ASSOCINFO, &assocparams, sizeof(assocparams));
439 if (ret) {
440 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_ASSOCINFO for fd %d: %s",
441 F->fd, strerror(rb_get_sockerr(F)));
442 return ret;
443 }
444
445 return 0;
446}
447#endif
448
449int
450rb_bind(rb_fde_t *F, struct sockaddr *addr)
451{
452 int ret;
453
454 ret = rb_setsockopt_reuseaddr(F);
455 if (ret)
456 return ret;
457
458 ret = bind(F->fd, addr, GET_SS_LEN(addr));
459 if (ret)
460 return ret;
461
462 return 0;
463}
464
6003ce76
SA
465#ifdef HAVE_LIBSCTP
466static int
467rb_sctp_bindx_only(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
468{
469 int ret;
470
471 for (size_t i = 0; i < len; i++) {
472 if (GET_SS_FAMILY(&addrs[i]) == AF_UNSPEC)
473 continue;
474
475 ret = sctp_bindx(F->fd, (struct sockaddr *)&addrs[i], 1, SCTP_BINDX_ADD_ADDR);
476 if (ret)
477 return ret;
478 }
479
480 return 0;
481}
482#endif
483
c6ad9b0c
SA
484int
485rb_sctp_bindx(rb_fde_t *F, struct sockaddr_storage *addrs, size_t len)
486{
487#ifdef HAVE_LIBSCTP
488 int ret;
489
490 if ((F->type & RB_FD_SCTP) == 0)
491 return -1;
492
493 ret = rb_setsockopt_reuseaddr(F);
494 if (ret)
495 return ret;
496
6003ce76
SA
497 ret = rb_sctp_bindx_only(F, addrs, len);
498 if (ret)
499 return ret;
c6ad9b0c
SA
500
501 return 0;
502#else
503 return -1;
504#endif
505}
506
507int
508rb_inet_get_proto(rb_fde_t *F)
db137867 509{
c6ad9b0c
SA
510#ifdef HAVE_LIBSCTP
511 if (F->type & RB_FD_SCTP)
512 return IPPROTO_SCTP;
513#endif
514 return IPPROTO_TCP;
515}
516
8679c0fe 517static void rb_accept_tryaccept(rb_fde_t *F, void *data __attribute__((unused))) {
db137867
AC
518 struct rb_sockaddr_storage st;
519 rb_fde_t *new_F;
b0adc7bf 520 rb_socklen_t addrlen;
db137867
AC
521 int new_fd;
522
523 while(1)
524 {
b0adc7bf
SA
525 memset(&st, 0, sizeof(st));
526 addrlen = sizeof(st);
527
db137867
AC
528 new_fd = accept(F->fd, (struct sockaddr *)&st, &addrlen);
529 rb_get_errno();
530 if(new_fd < 0)
531 {
532 rb_setselect(F, RB_SELECT_ACCEPT, rb_accept_tryaccept, NULL);
533 return;
534 }
535
536 rb_fd_hack(&new_fd);
537
c6ad9b0c 538 new_F = rb_open(new_fd, RB_FD_SOCKET | (F->type & RB_FD_INHERIT_TYPES), "Incoming Connection");
db137867 539
a9fb3ed0
VY
540 if(new_F == NULL)
541 {
3202e249 542 rb_lib_log
c6ad9b0c 543 ("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d",
3202e249 544 new_fd);
a9fb3ed0
VY
545 close(new_fd);
546 continue;
547 }
548
c2ac22cc 549 if(rb_unlikely(!rb_set_nb(new_F)))
db137867
AC
550 {
551 rb_get_errno();
552 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F->fd);
553 rb_close(new_F);
554 }
555
db137867 556 mangle_mapped_sockaddr((struct sockaddr *)&st);
3202e249 557
db137867
AC
558 if(F->accept->precb != NULL)
559 {
3202e249 560 if(!F->accept->precb(new_F, (struct sockaddr *)&st, addrlen, F->accept->data)) /* pre-callback decided to drop it */
db137867
AC
561 continue;
562 }
563#ifdef HAVE_SSL
564 if(F->type & RB_FD_SSL)
565 {
a9fb3ed0 566 rb_ssl_accept_setup(F, new_F, (struct sockaddr *)&st, addrlen);
3202e249 567 }
db137867 568 else
3202e249 569#endif /* HAVE_SSL */
db137867 570 {
3202e249
VY
571 F->accept->callback(new_F, RB_OK, (struct sockaddr *)&st, addrlen,
572 F->accept->data);
db137867
AC
573 }
574 }
575
576}
577
578/* try to accept a TCP connection */
579void
3202e249 580rb_accept_tcp(rb_fde_t *F, ACPRE * precb, ACCB * callback, void *data)
db137867
AC
581{
582 if(F == NULL)
583 return;
584 lrb_assert(callback);
585
586 F->accept = rb_malloc(sizeof(struct acceptdata));
587 F->accept->callback = callback;
588 F->accept->data = data;
589 F->accept->precb = precb;
590 rb_accept_tryaccept(F, NULL);
591}
592
593/*
dc7e6b42 594 * void rb_connect_tcp(rb_platform_fd_t fd, struct sockaddr *dest,
5ad62c80 595 * struct sockaddr *clocal,
db137867
AC
596 * CNCB *callback, void *data, int timeout)
597 * Input: An fd to connect with, a host and port to connect to,
5ad62c80 598 * a local sockaddr to connect from (or NULL to use the
db137867
AC
599 * default), a callback, the data to pass into the callback, the
600 * address family.
601 * Output: None.
602 * Side-effects: A non-blocking connection to the host is started, and
603 * if necessary, set up for selection. The callback given
604 * may be called now, or it may be called later.
605 */
606void
607rb_connect_tcp(rb_fde_t *F, struct sockaddr *dest,
5ad62c80 608 struct sockaddr *clocal, CNCB * callback, void *data, int timeout)
db137867 609{
589dbf4d
SA
610 int retval;
611
612 if (F == NULL)
db137867 613 return;
3202e249 614
db137867
AC
615 lrb_assert(callback);
616 F->connect = rb_malloc(sizeof(struct conndata));
617 F->connect->callback = callback;
618 F->connect->data = data;
619
620 memcpy(&F->connect->hostaddr, dest, sizeof(F->connect->hostaddr));
621
622 /* Note that we're using a passed sockaddr here. This is because
623 * generally you'll be bind()ing to a sockaddr grabbed from
624 * getsockname(), so this makes things easier.
625 * XXX If NULL is passed as local, we should later on bind() to the
626 * virtual host IP, for completeness.
627 * -- adrian
628 */
5ad62c80 629 if((clocal != NULL) && (bind(F->fd, clocal, GET_SS_LEN(clocal)) < 0))
db137867
AC
630 {
631 /* Failure, call the callback with RB_ERR_BIND */
632 rb_connect_callback(F, RB_ERR_BIND);
633 /* ... and quit */
634 return;
635 }
636
637 /* We have a valid IP, so we just call tryconnect */
638 /* Make sure we actually set the timeout here .. */
639 rb_settimeout(F, timeout, rb_connect_timeout, NULL);
db137867 640
589dbf4d
SA
641 retval = connect(F->fd,
642 (struct sockaddr *)&F->connect->hostaddr,
643 GET_SS_LEN(&F->connect->hostaddr));
644 /* Error? */
645 if (retval < 0) {
646 /*
647 * If we get EISCONN, then we've already connect()ed the socket,
648 * which is a good thing.
649 * -- adrian
650 */
651 rb_get_errno();
652 if (errno == EISCONN) {
653 rb_connect_callback(F, RB_OK);
654 } else if (rb_ignore_errno(errno)) {
655 /* Ignore error? Reschedule */
656 rb_setselect(F, RB_SELECT_CONNECT, rb_connect_outcome, NULL);
657 } else {
658 /* Error? Fail with RB_ERR_CONNECT */
659 rb_connect_callback(F, RB_ERR_CONNECT);
660 }
661 return;
662 }
663 /* If we get here, we've succeeded, so call with RB_OK */
664 rb_connect_callback(F, RB_OK);
665}
db137867 666
6003ce76
SA
667void
668rb_connect_sctp(rb_fde_t *F, struct sockaddr_storage *dest, size_t dest_len,
669 struct sockaddr_storage *clocal, size_t clocal_len,
670 CNCB *callback, void *data, int timeout)
671{
672#ifdef HAVE_LIBSCTP
673 uint8_t packed_dest[sizeof(struct sockaddr_storage) * dest_len];
674 uint8_t *p = &packed_dest[0];
675 size_t n = 0;
676 int retval;
677
678 if (F == NULL)
679 return;
680
681 lrb_assert(callback);
682 F->connect = rb_malloc(sizeof(struct conndata));
683 F->connect->callback = callback;
684 F->connect->data = data;
685
686 if ((F->type & RB_FD_SCTP) == 0) {
687 rb_connect_callback(F, RB_ERR_CONNECT);
688 return;
689 }
690
691 for (size_t i = 0; i < dest_len; i++) {
692 if (GET_SS_FAMILY(&dest[i]) == AF_INET6) {
693 memcpy(p, &dest[i], sizeof(struct sockaddr_in6));
694 n++;
695 p += sizeof(struct sockaddr_in6);
696 } else if (GET_SS_FAMILY(&dest[i]) == AF_INET) {
697 memcpy(p, &dest[i], sizeof(struct sockaddr_in));
698 n++;
699 p += sizeof(struct sockaddr_in);
700 }
701 }
702 dest_len = n;
703
704 memcpy(&F->connect->hostaddr, &dest[0], sizeof(F->connect->hostaddr));
705
706 if ((clocal_len > 0) && (rb_sctp_bindx_only(F, clocal, clocal_len) < 0)) {
707 /* Failure, call the callback with RB_ERR_BIND */
708 rb_connect_callback(F, RB_ERR_BIND);
709 /* ... and quit */
710 return;
711 }
712
713 rb_settimeout(F, timeout, rb_connect_timeout, NULL);
714
715 retval = sctp_connectx(F->fd, (struct sockaddr *)packed_dest, dest_len, NULL);
716 /* Error? */
717 if (retval < 0) {
718 /*
719 * If we get EISCONN, then we've already connect()ed the socket,
720 * which is a good thing.
721 * -- adrian
722 */
723 rb_get_errno();
724 if (errno == EISCONN) {
725 rb_connect_callback(F, RB_OK);
726 } else if (rb_ignore_errno(errno)) {
727 /* Ignore error? Reschedule */
728 rb_setselect(F, RB_SELECT_CONNECT, rb_connect_outcome, NULL);
729 } else {
730 /* Error? Fail with RB_ERR_CONNECT */
731 rb_connect_callback(F, RB_ERR_CONNECT);
732 }
733 return;
734 }
735 /* If we get here, we've succeeded, so call with RB_OK */
736 rb_connect_callback(F, RB_OK);
737#else
738 rb_connect_callback(F, RB_ERR_CONNECT);
739#endif
740}
741
db137867
AC
742/*
743 * rb_connect_callback() - call the callback, and continue with life
744 */
745void
746rb_connect_callback(rb_fde_t *F, int status)
747{
748 CNCB *hdl;
749 void *data;
3202e249 750 int errtmp = errno; /* save errno as rb_settimeout clobbers it sometimes */
db137867
AC
751
752 /* This check is gross..but probably necessary */
753 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
754 return;
755 /* Clear the connect flag + handler */
756 hdl = F->connect->callback;
757 data = F->connect->data;
758 F->connect->callback = NULL;
759
aec4c3cb 760
db137867
AC
761 /* Clear the timeout handler */
762 rb_settimeout(F, 0, NULL, NULL);
3202e249 763 errno = errtmp;
db137867
AC
764 /* Call the handler */
765 hdl(F, status, data);
766}
767
768
769/*
770 * rb_connect_timeout() - this gets called when the socket connection
771 * times out. This *only* can be called once connect() is initially
772 * called ..
773 */
774static void
8679c0fe 775rb_connect_timeout(rb_fde_t *F, void *notused __attribute__((unused)))
db137867
AC
776{
777 /* error! */
778 rb_connect_callback(F, RB_ERR_TIMEOUT);
779}
780
db137867 781static void
8679c0fe 782rb_connect_outcome(rb_fde_t *F, void *notused __attribute__((unused)))
db137867
AC
783{
784 int retval;
589dbf4d
SA
785 int err = 0;
786 socklen_t len = sizeof(err);
db137867
AC
787
788 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
789 return;
589dbf4d
SA
790 retval = getsockopt(F->fd, SOL_SOCKET, SO_ERROR, &err, &len);
791 if (retval < 0) {
db137867 792 rb_get_errno();
589dbf4d
SA
793 } else if (err != 0) {
794 errno = err;
795 retval = -1;
796 }
797 if (retval < 0) {
798 /* Error? Fail with RB_ERR_CONNECT */
799 rb_connect_callback(F, RB_ERR_CONNECT);
db137867
AC
800 return;
801 }
589dbf4d 802 /* If we get here, we've succeeded, so call with RB_OK */
db137867
AC
803 rb_connect_callback(F, RB_OK);
804}
805
806
807int
808rb_connect_sockaddr(rb_fde_t *F, struct sockaddr *addr, int len)
809{
810 if(F == NULL)
811 return 0;
812
813 memcpy(addr, &F->connect->hostaddr, len);
814 return 1;
815}
816
817/*
818 * rb_error_str() - return an error string for the given error condition
819 */
820const char *
821rb_errstr(int error)
822{
823 if(error < 0 || error >= RB_ERR_MAX)
824 return "Invalid error number!";
825 return rb_err_str[error];
826}
827
828
829int
830rb_socketpair(int family, int sock_type, int proto, rb_fde_t **F1, rb_fde_t **F2, const char *note)
831{
e49147e5 832 rb_platform_fd_t nfd[2];
db137867
AC
833 if(number_fd >= rb_maxconnections)
834 {
835 errno = ENFILE;
836 return -1;
837 }
838
3202e249 839#ifdef HAVE_SOCKETPAIR
db137867
AC
840 if(socketpair(family, sock_type, proto, nfd))
841#else
3202e249
VY
842 if(sock_type == SOCK_DGRAM)
843 {
844 return rb_inet_socketpair_udp(F1, F2);
845 }
846
847 if(rb_inet_socketpair(AF_INET, sock_type, proto, nfd))
db137867
AC
848#endif
849 return -1;
850
851 rb_fd_hack(&nfd[0]);
852 rb_fd_hack(&nfd[1]);
853
854 *F1 = rb_open(nfd[0], RB_FD_SOCKET, note);
855 *F2 = rb_open(nfd[1], RB_FD_SOCKET, note);
856
857 if(*F1 == NULL)
858 {
859 if(*F2 != NULL)
860 rb_close(*F2);
861 return -1;
862 }
863
864 if(*F2 == NULL)
865 {
866 rb_close(*F1);
867 return -1;
868 }
869
870 /* Set the socket non-blocking, and other wonderful bits */
c2ac22cc 871 if(rb_unlikely(!rb_set_nb(*F1)))
db137867
AC
872 {
873 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[0], strerror(errno));
874 rb_close(*F1);
875 rb_close(*F2);
876 return -1;
877 }
878
c2ac22cc 879 if(rb_unlikely(!rb_set_nb(*F2)))
db137867
AC
880 {
881 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[1], strerror(errno));
882 rb_close(*F1);
883 rb_close(*F2);
884 return -1;
885 }
886
887 return 0;
888}
889
890
891int
892rb_pipe(rb_fde_t **F1, rb_fde_t **F2, const char *desc)
893{
3202e249 894#ifndef _WIN32
dc7e6b42 895 rb_platform_fd_t fd[2];
db137867
AC
896 if(number_fd >= rb_maxconnections)
897 {
898 errno = ENFILE;
899 return -1;
900 }
901 if(pipe(fd) == -1)
902 return -1;
903 rb_fd_hack(&fd[0]);
904 rb_fd_hack(&fd[1]);
905 *F1 = rb_open(fd[0], RB_FD_PIPE, desc);
906 *F2 = rb_open(fd[1], RB_FD_PIPE, desc);
907
c2ac22cc 908 if(rb_unlikely(!rb_set_nb(*F1)))
db137867
AC
909 {
910 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[0], strerror(errno));
911 rb_close(*F1);
912 rb_close(*F2);
913 return -1;
914 }
915
c2ac22cc 916 if(rb_unlikely(!rb_set_nb(*F2)))
db137867
AC
917 {
918 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[1], strerror(errno));
919 rb_close(*F1);
920 rb_close(*F2);
921 return -1;
922 }
923
924
925 return 0;
926#else
927 /* Its not a pipe..but its selectable. I'll take dirty hacks
928 * for $500 Alex.
929 */
3202e249 930 return rb_socketpair(AF_INET, SOCK_STREAM, 0, F1, F2, desc);
db137867
AC
931#endif
932}
933
934/*
935 * rb_socket() - open a socket
936 *
937 * This is a highly highly cut down version of squid's rb_open() which
938 * for the most part emulates socket(), *EXCEPT* it fails if we're about
939 * to run out of file descriptors.
940 */
941rb_fde_t *
942rb_socket(int family, int sock_type, int proto, const char *note)
943{
944 rb_fde_t *F;
dc7e6b42 945 rb_platform_fd_t fd;
db137867 946 /* First, make sure we aren't going to run out of file descriptors */
c2ac22cc 947 if(rb_unlikely(number_fd >= rb_maxconnections))
db137867
AC
948 {
949 errno = ENFILE;
950 return NULL;
951 }
952
953 /*
954 * Next, we try to open the socket. We *should* drop the reserved FD
955 * limit if/when we get an error, but we can deal with that later.
956 * XXX !!! -- adrian
957 */
958 fd = socket(family, sock_type, proto);
959 rb_fd_hack(&fd);
c2ac22cc 960 if(rb_unlikely(fd < 0))
db137867
AC
961 return NULL; /* errno will be passed through, yay.. */
962
55abcbb2 963 /*
db137867 964 * Make sure we can take both IPv4 and IPv6 connections
c6ad9b0c 965 * on an AF_INET6 SCTP socket, otherwise keep them separate
db137867
AC
966 */
967 if(family == AF_INET6)
968 {
c6ad9b0c
SA
969#ifdef HAVE_LIBSCTP
970 int v6only = (proto == IPPROTO_SCTP) ? 0 : 1;
971#else
972 int v6only = 1;
973#endif
974 if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only)) == -1)
db137867 975 {
c6ad9b0c
SA
976 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to %d on FD %d: %s",
977 v6only, fd, strerror(errno));
db137867
AC
978 close(fd);
979 return NULL;
980 }
981 }
db137867
AC
982
983 F = rb_open(fd, RB_FD_SOCKET, note);
984 if(F == NULL)
a9fb3ed0 985 {
3202e249
VY
986 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd,
987 strerror(errno));
a9fb3ed0 988 close(fd);
db137867 989 return NULL;
a9fb3ed0 990 }
c6ad9b0c
SA
991
992#ifdef HAVE_LIBSCTP
993 if (proto == IPPROTO_SCTP) {
994 F->type |= RB_FD_SCTP;
995
996 if (rb_setsockopt_sctp(F)) {
997 rb_lib_log("rb_socket: Could not set SCTP socket options on FD %d: %s",
998 fd, strerror(errno));
999 close(fd);
1000 return NULL;
1001 }
1002 }
1003#endif
1004
db137867 1005 /* Set the socket non-blocking, and other wonderful bits */
c2ac22cc 1006 if(rb_unlikely(!rb_set_nb(F)))
db137867
AC
1007 {
1008 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd, strerror(errno));
1009 rb_close(F);
1010 return NULL;
1011 }
1012
1013 return F;
1014}
1015
1016/*
1017 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
1018 * socket manged the sockaddr.
1019 */
db137867
AC
1020static void
1021mangle_mapped_sockaddr(struct sockaddr *in)
1022{
3202e249 1023 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in;
db137867 1024
db137867
AC
1025 if(in->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr))
1026 {
1027 struct sockaddr_in in4;
1028 memset(&in4, 0, sizeof(struct sockaddr_in));
1029 in4.sin_family = AF_INET;
1030 in4.sin_port = in6->sin6_port;
3202e249 1031 in4.sin_addr.s_addr = ((uint32_t *)&in6->sin6_addr)[3];
db137867
AC
1032 memcpy(in, &in4, sizeof(struct sockaddr_in));
1033 }
db137867 1034}
db137867
AC
1035
1036/*
1037 * rb_listen() - listen on a port
1038 */
1039int
aa4737a0 1040rb_listen(rb_fde_t *F, int backlog, int defer_accept)
db137867 1041{
77cb59b3
AC
1042 int result;
1043
c6ad9b0c 1044 F->type = RB_FD_SOCKET | RB_FD_LISTEN | (F->type & RB_FD_INHERIT_TYPES);
77cb59b3
AC
1045 result = listen(F->fd, backlog);
1046
1047#ifdef TCP_DEFER_ACCEPT
aa4737a0 1048 if (defer_accept && !result)
77cb59b3 1049 {
e053adc8 1050 (void)setsockopt(F->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &backlog, sizeof(int));
77cb59b3
AC
1051 }
1052#endif
797a29f3
JT
1053#ifdef SO_ACCEPTFILTER
1054 if (defer_accept && !result)
1055 {
1056 struct accept_filter_arg afa;
1057
1058 memset(&afa, '\0', sizeof afa);
1059 rb_strlcpy(afa.af_name, "dataready", sizeof afa.af_name);
1060 (void)setsockopt(F->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa,
1061 sizeof afa);
1062 }
1063#endif
77cb59b3
AC
1064
1065 return result;
db137867
AC
1066}
1067
1068void
1069rb_fdlist_init(int closeall, int maxfds, size_t heapsize)
1070{
1071 static int initialized = 0;
3202e249 1072#ifdef _WIN32
db137867
AC
1073 WSADATA wsaData;
1074 int err;
1075 int vers = MAKEWORD(2, 0);
3202e249 1076
db137867
AC
1077 err = WSAStartup(vers, &wsaData);
1078 if(err != 0)
1079 {
1080 rb_lib_die("WSAStartup failed");
1081 }
1082
1083#endif
1084 if(!initialized)
1085 {
1086 rb_maxconnections = maxfds;
1087 if(closeall)
1088 rb_close_all();
1089 /* Since we're doing this once .. */
1090 initialized = 1;
1091 }
1092 fd_heap = rb_bh_create(sizeof(rb_fde_t), heapsize, "librb_fd_heap");
1093
1094}
1095
1096
1097/* Called to open a given filedescriptor */
1098rb_fde_t *
dc7e6b42 1099rb_open(rb_platform_fd_t fd, uint8_t type, const char *desc)
db137867 1100{
a9fb3ed0 1101 rb_fde_t *F;
db137867
AC
1102 lrb_assert(fd >= 0);
1103
a9fb3ed0
VY
1104 F = add_fd(fd);
1105
1106 lrb_assert(!IsFDOpen(F));
c2ac22cc 1107 if(rb_unlikely(IsFDOpen(F)))
db137867 1108 {
a9fb3ed0
VY
1109 const char *fdesc;
1110 if(F != NULL && F->desc != NULL)
1111 fdesc = F->desc;
1112 else
1113 fdesc = "NULL";
3202e249 1114 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd, fdesc);
db137867
AC
1115 return NULL;
1116 }
db137867
AC
1117 F->fd = fd;
1118 F->type = type;
1119 SetFDOpen(F);
1120
1121 if(desc != NULL)
1122 F->desc = rb_strndup(desc, FD_DESC_SZ);
1123 number_fd++;
1124 return F;
1125}
1126
1127
1128/* Called to close a given filedescriptor */
1129void
1130rb_close(rb_fde_t *F)
1131{
1132 int type, fd;
3202e249 1133
db137867
AC
1134 if(F == NULL)
1135 return;
1136
1137 fd = F->fd;
3202e249 1138 type = F->type;
db137867
AC
1139 lrb_assert(IsFDOpen(F));
1140
1141 lrb_assert(!(type & RB_FD_FILE));
c2ac22cc 1142 if(rb_unlikely(type & RB_FD_FILE))
db137867
AC
1143 {
1144 lrb_assert(F->read_handler == NULL);
1145 lrb_assert(F->write_handler == NULL);
1146 }
c6ad9b0c
SA
1147
1148 if (type & RB_FD_LISTEN) {
1149 listen(F->fd, 0);
1150 }
1151
db137867
AC
1152 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
1153 rb_settimeout(F, 0, NULL, NULL);
1154 rb_free(F->accept);
1155 rb_free(F->connect);
1156 rb_free(F->desc);
1157#ifdef HAVE_SSL
1158 if(type & RB_FD_SSL)
1159 {
1160 rb_ssl_shutdown(F);
1161 }
1162#endif /* HAVE_SSL */
1163 if(IsFDOpen(F))
1164 {
1165 remove_fd(F);
1166 ClearFDOpen(F);
1167 }
8a29e7cd
SA
1168
1169 if(type & RB_FD_LISTEN)
1170 shutdown(fd, SHUT_RDWR);
db137867
AC
1171}
1172
1173
1174/*
1175 * rb_dump_fd() - dump the list of active filedescriptors
1176 */
1177void
1178rb_dump_fd(DUMPCB * cb, void *data)
1179{
1180 static const char *empty = "";
1181 rb_dlink_node *ptr;
1182 rb_dlink_list *bucket;
1183 rb_fde_t *F;
1184 unsigned int i;
1185
1186 for(i = 0; i < RB_FD_HASH_SIZE; i++)
1187 {
1188 bucket = &rb_fd_table[i];
1189
1190 if(rb_dlink_list_length(bucket) <= 0)
1191 continue;
1192
1193 RB_DLINK_FOREACH(ptr, bucket->head)
1194 {
1195 F = ptr->data;
1196 if(F == NULL || !IsFDOpen(F))
1197 continue;
1198
1199 cb(F->fd, F->desc ? F->desc : empty, data);
1200 }
1201 }
1202}
1203
1204/*
1205 * rb_note() - set the fd note
1206 *
1207 * Note: must be careful not to overflow rb_fd_table[fd].desc when
1208 * calling.
1209 */
1210void
1211rb_note(rb_fde_t *F, const char *string)
1212{
1213 if(F == NULL)
1214 return;
1215
1216 rb_free(F->desc);
1217 F->desc = rb_strndup(string, FD_DESC_SZ);
1218}
1219
1220void
a9fb3ed0 1221rb_set_type(rb_fde_t *F, uint8_t type)
db137867
AC
1222{
1223 /* if the caller is calling this, lets assume they have a clue */
1224 F->type = type;
1225 return;
1226}
1227
a9fb3ed0 1228uint8_t
db137867
AC
1229rb_get_type(rb_fde_t *F)
1230{
1231 return F->type;
1232}
1233
3202e249 1234int
db137867
AC
1235rb_fd_ssl(rb_fde_t *F)
1236{
1237 if(F == NULL)
1238 return 0;
1239 if(F->type & RB_FD_SSL)
1240 return 1;
1241 return 0;
1242}
1243
b1f7e409 1244rb_platform_fd_t
db137867
AC
1245rb_get_fd(rb_fde_t *F)
1246{
1247 if(F == NULL)
1248 return -1;
3202e249 1249 return (F->fd);
db137867
AC
1250}
1251
1252rb_fde_t *
dc7e6b42 1253rb_get_fde(rb_platform_fd_t fd)
db137867
AC
1254{
1255 return rb_find_fd(fd);
1256}
1257
1258ssize_t
1259rb_read(rb_fde_t *F, void *buf, int count)
1260{
ba1721d1 1261 ssize_t ret;
db137867
AC
1262 if(F == NULL)
1263 return 0;
3202e249 1264
55abcbb2
KB
1265 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
1266 * an SSL socket as a regular socket
db137867
AC
1267 */
1268#ifdef HAVE_SSL
1269 if(F->type & RB_FD_SSL)
1270 {
1271 return rb_ssl_read(F, buf, count);
3202e249 1272 }
db137867
AC
1273#endif
1274 if(F->type & RB_FD_SOCKET)
1275 {
1276 ret = recv(F->fd, buf, count, 0);
1277 if(ret < 0)
1278 {
1279 rb_get_errno();
1280 }
1281 return ret;
1282 }
1283
1284
1285 /* default case */
1286 return read(F->fd, buf, count);
1287}
1288
1289
1290ssize_t
1291rb_write(rb_fde_t *F, const void *buf, int count)
1292{
ba1721d1 1293 ssize_t ret;
db137867
AC
1294 if(F == NULL)
1295 return 0;
1296
1297#ifdef HAVE_SSL
1298 if(F->type & RB_FD_SSL)
1299 {
1300 return rb_ssl_write(F, buf, count);
3202e249 1301 }
db137867
AC
1302#endif
1303 if(F->type & RB_FD_SOCKET)
1304 {
1305 ret = send(F->fd, buf, count, MSG_NOSIGNAL);
3202e249
VY
1306 if(ret < 0)
1307 {
db137867
AC
1308 rb_get_errno();
1309 }
1310 return ret;
1311 }
1312
1313 return write(F->fd, buf, count);
1314}
1315
1316#if defined(HAVE_SSL) || defined(WIN32) || !defined(HAVE_WRITEV)
1317static ssize_t
1318rb_fake_writev(rb_fde_t *F, const struct rb_iovec *vp, size_t vpcount)
1319{
ba1721d1 1320 ssize_t count = 0;
db137867 1321
3202e249 1322 while(vpcount-- > 0)
db137867 1323 {
ba1721d1 1324 ssize_t written = rb_write(F, vp->iov_base, vp->iov_len);
db137867 1325
3202e249 1326 if(written <= 0)
db137867
AC
1327 {
1328 if(count > 0)
1329 return count;
1330 else
1331 return written;
1332 }
1333 count += written;
1334 vp++;
1335 }
1336 return (count);
1337}
1338#endif
1339
1340#if defined(WIN32) || !defined(HAVE_WRITEV)
1341ssize_t
3202e249 1342rb_writev(rb_fde_t *F, struct rb_iovec * vecount, int count)
db137867
AC
1343{
1344 return rb_fake_writev(F, vecount, count);
1345}
1346
1347#else
1348ssize_t
3202e249 1349rb_writev(rb_fde_t *F, struct rb_iovec * vector, int count)
db137867 1350{
3202e249
VY
1351 if(F == NULL)
1352 {
db137867
AC
1353 errno = EBADF;
1354 return -1;
1355 }
1356#ifdef HAVE_SSL
1357 if(F->type & RB_FD_SSL)
1358 {
3202e249 1359 return rb_fake_writev(F, vector, count);
db137867
AC
1360 }
1361#endif /* HAVE_SSL */
1362#ifdef HAVE_SENDMSG
1363 if(F->type & RB_FD_SOCKET)
1364 {
1365 struct msghdr msg;
1366 memset(&msg, 0, sizeof(msg));
1367 msg.msg_iov = (struct iovec *)vector;
1368 msg.msg_iovlen = count;
1369 return sendmsg(F->fd, &msg, MSG_NOSIGNAL);
3202e249 1370 }
db137867
AC
1371#endif /* HAVE_SENDMSG */
1372 return writev(F->fd, (struct iovec *)vector, count);
1373
1374}
3202e249 1375#endif
db137867
AC
1376
1377
55abcbb2 1378/*
db137867
AC
1379 * From: Thomas Helvey <tomh@inxpress.net>
1380 */
1381static const char *IpQuadTab[] = {
1382 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1383 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1384 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1385 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1386 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1387 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1388 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1389 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1390 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1391 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1392 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1393 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1394 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1395 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1396 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1397 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1398 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1399 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1400 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1401 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1402 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1403 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1404 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1405 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1406 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1407 "250", "251", "252", "253", "254", "255"
1408};
1409
1410/*
1411 * inetntoa - in_addr to string
1412 * changed name to remove collision possibility and
1413 * so behaviour is guaranteed to take a pointer arg.
1414 * -avalon 23/11/92
1415 * inet_ntoa -- returned the dotted notation of a given
1416 * internet number
1417 * argv 11/90).
1418 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1419 */
1420
1421static const char *
1422inetntoa(const char *in)
1423{
1424 static char buf[16];
1425 char *bufptr = buf;
3202e249 1426 const unsigned char *a = (const unsigned char *)in;
db137867
AC
1427 const char *n;
1428
1429 n = IpQuadTab[*a++];
3202e249 1430 while(*n)
db137867
AC
1431 *bufptr++ = *n++;
1432 *bufptr++ = '.';
1433 n = IpQuadTab[*a++];
3202e249 1434 while(*n)
db137867
AC
1435 *bufptr++ = *n++;
1436 *bufptr++ = '.';
1437 n = IpQuadTab[*a++];
3202e249 1438 while(*n)
db137867
AC
1439 *bufptr++ = *n++;
1440 *bufptr++ = '.';
1441 n = IpQuadTab[*a];
3202e249 1442 while(*n)
db137867
AC
1443 *bufptr++ = *n++;
1444 *bufptr = '\0';
1445 return buf;
1446}
1447
db137867
AC
1448/*
1449 * WARNING: Don't even consider trying to compile this on a system where
1450 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1451 */
1452
3202e249 1453static const char *inet_ntop4(const unsigned char *src, char *dst, unsigned int size);
3202e249 1454static const char *inet_ntop6(const unsigned char *src, char *dst, unsigned int size);
db137867
AC
1455
1456/* const char *
1457 * inet_ntop4(src, dst, size)
1458 * format an IPv4 address
1459 * return:
1460 * `dst' (as a const)
1461 * notes:
1462 * (1) uses no statics
1463 * (2) takes a unsigned char* not an in_addr as input
1464 * author:
1465 * Paul Vixie, 1996.
1466 */
1467static const char *
1468inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
1469{
1470 if(size < 16)
1471 return NULL;
86510a73 1472 return strcpy(dst, inetntoa((const char *)src));
db137867
AC
1473}
1474
1475/* const char *
1476 * inet_ntop6(src, dst, size)
1477 * convert IPv6 binary address into presentation (printable) format
1478 * author:
1479 * Paul Vixie, 1996.
1480 */
db137867
AC
1481static const char *
1482inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
1483{
1484 /*
1485 * Note that int32_t and int16_t need only be "at least" large enough
1486 * to contain a value of the specified size. On some systems, like
1487 * Crays, there is no such thing as an integer variable with 16 bits.
1488 * Keep this in mind if you think this function should have been coded
1489 * to use pointer overlays. All the world's not a VAX.
1490 */
1491 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
1492 struct
1493 {
1494 int base, len;
1495 }
1496 best, cur;
1497 unsigned int words[IN6ADDRSZ / INT16SZ];
1498 int i;
1499
1500 /*
1501 * Preprocess:
1502 * Copy the input (bytewise) array into a wordwise array.
1503 * Find the longest run of 0x00's in src[] for :: shorthanding.
1504 */
1505 memset(words, '\0', sizeof words);
3202e249 1506 for(i = 0; i < IN6ADDRSZ; i += 2)
db137867
AC
1507 words[i / 2] = (src[i] << 8) | src[i + 1];
1508 best.base = -1;
1509 best.len = 0;
1510 cur.base = -1;
1511 cur.len = 0;
3202e249 1512 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1513 {
1514 if(words[i] == 0)
1515 {
1516 if(cur.base == -1)
1517 cur.base = i, cur.len = 1;
1518 else
1519 cur.len++;
1520 }
1521 else
1522 {
1523 if(cur.base != -1)
1524 {
1525 if(best.base == -1 || cur.len > best.len)
1526 best = cur;
1527 cur.base = -1;
1528 }
1529 }
1530 }
1531 if(cur.base != -1)
1532 {
1533 if(best.base == -1 || cur.len > best.len)
1534 best = cur;
1535 }
1536 if(best.base != -1 && best.len < 2)
1537 best.base = -1;
1538
1539 /*
1540 * Format the result.
1541 */
1542 tp = tmp;
3202e249 1543 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1544 {
1545 /* Are we inside the best run of 0x00's? */
1546 if(best.base != -1 && i >= best.base && i < (best.base + best.len))
1547 {
1548 if(i == best.base)
1549 {
1550 if(i == 0)
1551 *tp++ = '0';
1552 *tp++ = ':';
1553 }
1554 continue;
1555 }
1556 /* Are we following an initial run of 0x00s or any real hex? */
1557 if(i != 0)
1558 *tp++ = ':';
1559 /* Is this address an encapsulated IPv4? */
1560 if(i == 6 && best.base == 0 &&
1561 (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
1562 {
1563 if(!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
1564 return (NULL);
1565 tp += strlen(tp);
1566 break;
1567 }
5203cba5 1568 tp += sprintf(tp, "%x", words[i]);
db137867
AC
1569 }
1570 /* Was it a trailing run of 0x00's? */
1571 if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
1572 *tp++ = ':';
1573 *tp++ = '\0';
1574
1575 /*
1576 * Check for overflow, copy, and we're done.
1577 */
1578
3202e249 1579 if((unsigned int)(tp - tmp) > size)
db137867
AC
1580 {
1581 return (NULL);
1582 }
86510a73 1583 return memcpy(dst, tmp, tp - tmp);
db137867 1584}
db137867
AC
1585
1586int
17809d2d 1587rb_inet_pton_sock(const char *src, struct sockaddr_storage *dst)
db137867 1588{
9caecc93 1589 memset(dst, 0, sizeof(*dst));
3202e249 1590 if(rb_inet_pton(AF_INET, src, &((struct sockaddr_in *)dst)->sin_addr))
db137867 1591 {
d86692fa 1592 SET_SS_FAMILY(dst, AF_INET);
1315fd59 1593 SET_SS_PORT(dst, 0);
db137867
AC
1594 SET_SS_LEN(dst, sizeof(struct sockaddr_in));
1595 return 1;
1596 }
3202e249 1597 else if(rb_inet_pton(AF_INET6, src, &((struct sockaddr_in6 *)dst)->sin6_addr))
db137867 1598 {
d86692fa 1599 SET_SS_FAMILY(dst, AF_INET6);
1315fd59 1600 SET_SS_PORT(dst, 0);
db137867
AC
1601 SET_SS_LEN(dst, sizeof(struct sockaddr_in6));
1602 return 1;
1603 }
db137867
AC
1604 return 0;
1605}
1606
1607const char *
1608rb_inet_ntop_sock(struct sockaddr *src, char *dst, unsigned int size)
1609{
1610 switch (src->sa_family)
1611 {
1612 case AF_INET:
3202e249 1613 return (rb_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, dst, size));
db137867 1614 case AF_INET6:
3202e249
VY
1615 return (rb_inet_ntop
1616 (AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr, dst, size));
db137867
AC
1617 default:
1618 return NULL;
db137867
AC
1619 }
1620}
1621
1622/* char *
1623 * rb_inet_ntop(af, src, dst, size)
1624 * convert a network format address to presentation format.
1625 * return:
1626 * pointer to presentation format address (`dst'), or NULL (see errno).
1627 * author:
1628 * Paul Vixie, 1996.
1629 */
1630const char *
1631rb_inet_ntop(int af, const void *src, char *dst, unsigned int size)
1632{
1633 switch (af)
1634 {
1635 case AF_INET:
1636 return (inet_ntop4(src, dst, size));
db137867 1637 case AF_INET6:
3202e249
VY
1638 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) ||
1639 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src))
db137867 1640 return (inet_ntop4
3202e249
VY
1641 ((const unsigned char *)&((const struct in6_addr *)src)->
1642 s6_addr[12], dst, size));
db137867
AC
1643 else
1644 return (inet_ntop6(src, dst, size));
db137867
AC
1645 default:
1646 return (NULL);
1647 }
1648 /* NOTREACHED */
1649}
1650
1651/*
1652 * WARNING: Don't even consider trying to compile this on a system where
1653 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1654 */
1655
1656/* int
1657 * rb_inet_pton(af, src, dst)
1658 * convert from presentation format (which usually means ASCII printable)
1659 * to network format (which is usually some kind of binary format).
1660 * return:
1661 * 1 if the address was valid for the specified address family
1662 * 0 if the address wasn't valid (`dst' is untouched in this case)
1663 * -1 if some other error occurred (`dst' is untouched in this case, too)
1664 * author:
1665 * Paul Vixie, 1996.
1666 */
1667
1668/* int
1669 * inet_pton4(src, dst)
1670 * like inet_aton() but without all the hexadecimal and shorthand.
1671 * return:
1672 * 1 if `src' is a valid dotted quad, else 0.
1673 * notice:
1674 * does not touch `dst' unless it's returning 1.
1675 * author:
1676 * Paul Vixie, 1996.
1677 */
1678static int
1679inet_pton4(const char *src, unsigned char *dst)
1680{
1681 int saw_digit, octets, ch;
1682 unsigned char tmp[INADDRSZ], *tp;
1683
1684 saw_digit = 0;
1685 octets = 0;
1686 *(tp = tmp) = 0;
3202e249 1687 while((ch = *src++) != '\0')
db137867
AC
1688 {
1689
1690 if(ch >= '0' && ch <= '9')
1691 {
1692 unsigned int new = *tp * 10 + (ch - '0');
1693
1694 if(new > 255)
1695 return (0);
1696 *tp = new;
1697 if(!saw_digit)
1698 {
1699 if(++octets > 4)
1700 return (0);
1701 saw_digit = 1;
1702 }
1703 }
1704 else if(ch == '.' && saw_digit)
1705 {
1706 if(octets == 4)
1707 return (0);
1708 *++tp = 0;
1709 saw_digit = 0;
1710 }
1711 else
1712 return (0);
1713 }
1714 if(octets < 4)
1715 return (0);
1716 memcpy(dst, tmp, INADDRSZ);
1717 return (1);
1718}
1719
db137867
AC
1720/* int
1721 * inet_pton6(src, dst)
1722 * convert presentation level address to network order binary form.
1723 * return:
1724 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1725 * notice:
1726 * (1) does not touch `dst' unless it's returning 1.
1727 * (2) :: in a full address is silently ignored.
1728 * credit:
1729 * inspired by Mark Andrews.
1730 * author:
1731 * Paul Vixie, 1996.
1732 */
1733
1734static int
1735inet_pton6(const char *src, unsigned char *dst)
1736{
1737 static const char xdigits[] = "0123456789abcdef";
1738 unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
1739 const char *curtok;
1740 int ch, saw_xdigit;
1741 unsigned int val;
1742
1743 tp = memset(tmp, '\0', IN6ADDRSZ);
1744 endp = tp + IN6ADDRSZ;
1745 colonp = NULL;
1746 /* Leading :: requires some special handling. */
1747 if(*src == ':')
1748 if(*++src != ':')
1749 return (0);
1750 curtok = src;
1751 saw_xdigit = 0;
1752 val = 0;
29c92cf9 1753 while((ch = tolower((unsigned char)*src++)) != '\0')
db137867
AC
1754 {
1755 const char *pch;
1756
1757 pch = strchr(xdigits, ch);
1758 if(pch != NULL)
1759 {
1760 val <<= 4;
1761 val |= (pch - xdigits);
1762 if(val > 0xffff)
1763 return (0);
1764 saw_xdigit = 1;
1765 continue;
1766 }
1767 if(ch == ':')
1768 {
1769 curtok = src;
1770 if(!saw_xdigit)
1771 {
1772 if(colonp)
1773 return (0);
1774 colonp = tp;
1775 continue;
1776 }
1777 else if(*src == '\0')
1778 {
1779 return (0);
1780 }
1781 if(tp + INT16SZ > endp)
1782 return (0);
3202e249
VY
1783 *tp++ = (unsigned char)(val >> 8) & 0xff;
1784 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1785 saw_xdigit = 0;
1786 val = 0;
1787 continue;
1788 }
1789 if(*src != '\0' && ch == '.')
1790 {
1791 if(((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
1792 {
1793 tp += INADDRSZ;
1794 saw_xdigit = 0;
1795 break; /* '\0' was seen by inet_pton4(). */
1796 }
1797 }
1798 else
1799 continue;
1800 return (0);
1801 }
1802 if(saw_xdigit)
1803 {
1804 if(tp + INT16SZ > endp)
1805 return (0);
3202e249
VY
1806 *tp++ = (unsigned char)(val >> 8) & 0xff;
1807 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1808 }
1809 if(colonp != NULL)
1810 {
1811 /*
1812 * Since some memmove()'s erroneously fail to handle
1813 * overlapping regions, we'll do the shift by hand.
1814 */
1815 const int n = tp - colonp;
1816 int i;
1817
1818 if(tp == endp)
1819 return (0);
3202e249 1820 for(i = 1; i <= n; i++)
db137867
AC
1821 {
1822 endp[-i] = colonp[n - i];
1823 colonp[n - i] = 0;
1824 }
1825 tp = endp;
1826 }
1827 if(tp != endp)
1828 return (0);
1829 memcpy(dst, tmp, IN6ADDRSZ);
1830 return (1);
1831}
de293496 1832
db137867
AC
1833int
1834rb_inet_pton(int af, const char *src, void *dst)
1835{
1836 switch (af)
1837 {
1838 case AF_INET:
1839 return (inet_pton4(src, dst));
db137867
AC
1840 case AF_INET6:
1841 /* Somebody might have passed as an IPv4 address this is sick but it works */
1842 if(inet_pton4(src, dst))
1843 {
1844 char tmp[HOSTIPLEN];
5203cba5 1845 sprintf(tmp, "::ffff:%s", src);
db137867
AC
1846 return (inet_pton6(tmp, dst));
1847 }
1848 else
1849 return (inet_pton6(src, dst));
db137867
AC
1850 default:
1851 return (-1);
1852 }
1853 /* NOTREACHED */
1854}
1855
1856
1857#ifndef HAVE_SOCKETPAIR
3202e249
VY
1858
1859/* mostly based on perl's emulation of socketpair udp */
1860static int
1861rb_inet_socketpair_udp(rb_fde_t **newF1, rb_fde_t **newF2)
1862{
1863 struct sockaddr_in addr[2];
1864 rb_socklen_t size = sizeof(struct sockaddr_in);
1865 rb_fde_t *F[2];
7dbf237f 1866 rb_platform_fd_t fd[2];
3202e249
VY
1867 int i, got;
1868 unsigned short port;
030272f3
VY
1869 struct timeval wait = { 0, 100000 };
1870 int max;
1871 fd_set rset;
1872 struct sockaddr_in readfrom;
1873 unsigned short buf[2];
1874 int o_errno;
3202e249
VY
1875
1876 memset(&addr, 0, sizeof(addr));
1877
1878 for(i = 0; i < 2; i++)
1879 {
1880 F[i] = rb_socket(AF_INET, SOCK_DGRAM, 0, "udp socketpair");
1881 if(F[i] == NULL)
1882 goto failed;
1883 addr[i].sin_family = AF_INET;
1884 addr[i].sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1885 addr[i].sin_port = 0;
1886 if(bind(rb_get_fd(F[i]), (struct sockaddr *)&addr[i], sizeof(struct sockaddr_in)))
1887 goto failed;
1888 fd[i] = rb_get_fd(F[i]);
1889 }
1890
1891 for(i = 0; i < 2; i++)
1892 {
1893 if(getsockname(fd[i], (struct sockaddr *)&addr[i], &size))
1894 goto failed;
1895 if(size != sizeof(struct sockaddr_in))
1896 goto failed;
1897 if(connect(fd[!i], (struct sockaddr *)&addr[i], sizeof(struct sockaddr_in)) == -1)
1898 goto failed;
1899 }
1900
1901 for(i = 0; i < 2; i++)
1902 {
1903 port = addr[i].sin_port;
1904 got = rb_write(F[i], &port, sizeof(port));
1905 if(got != sizeof(port))
1906 {
1907 if(got == -1)
1908 goto failed;
1909 goto abort_failed;
1910 }
1911 }
1912
030272f3 1913 max = fd[1] > fd[0] ? fd[1] : fd[0];
3202e249
VY
1914 FD_ZERO(&rset);
1915 FD_SET(fd[0], &rset);
1916 FD_SET(fd[1], &rset);
1917 got = select(max + 1, &rset, NULL, NULL, &wait);
1918 if(got != 2 || !FD_ISSET(fd[0], &rset) || !FD_ISSET(fd[1], &rset))
1919 {
1920 if(got == -1)
1921 goto failed;
1922 goto abort_failed;
1923 }
1924
3202e249
VY
1925 for(i = 0; i < 2; i++)
1926 {
1927#ifdef MSG_DONTWAIT
1928 int flag = MSG_DONTWAIT
1929#else
1930 int flag = 0;
1931#endif
1932 got = recvfrom(rb_get_fd(F[i]), (char *)&buf, sizeof(buf), flag,
1933 (struct sockaddr *)&readfrom, &size);
1934 if(got == -1)
1935 goto failed;
1936 if(got != sizeof(port)
1937 || size != sizeof(struct sockaddr_in)
1938 || buf[0] != (unsigned short)addr[!i].sin_port
1939 || readfrom.sin_family != addr[!i].sin_family
1940 || readfrom.sin_addr.s_addr != addr[!i].sin_addr.s_addr
1941 || readfrom.sin_port != addr[!i].sin_port)
1942 goto abort_failed;
1943 }
1944
1945 *newF1 = F[0];
1946 *newF2 = F[1];
1947 return 0;
1948
1949#ifdef _WIN32
7dbf237f 1950#ifndef ECONNABORTED
3202e249 1951#define ECONNABORTED WSAECONNABORTED
7dbf237f 1952#endif
3202e249
VY
1953#endif
1954
1955 abort_failed:
1956 rb_get_errno();
1957 errno = ECONNABORTED;
1958 failed:
1959 if(errno != ECONNABORTED)
1960 rb_get_errno();
030272f3 1961 o_errno = errno;
3202e249
VY
1962 if(F[0] != NULL)
1963 rb_close(F[0]);
1964 if(F[1] != NULL)
1965 rb_close(F[1]);
1966 errno = o_errno;
1967 return -1;
1968}
1969
1970
db137867 1971int
dc7e6b42 1972rb_inet_socketpair(int family, int type, int protocol, rb_platform_fd_t fd[2])
db137867
AC
1973{
1974 int listener = -1;
1975 int connector = -1;
1976 int acceptor = -1;
1977 struct sockaddr_in listen_addr;
1978 struct sockaddr_in connect_addr;
3202e249 1979 rb_socklen_t size;
db137867
AC
1980
1981 if(protocol || family != AF_INET)
1982 {
1983 errno = EAFNOSUPPORT;
1984 return -1;
1985 }
1986 if(!fd)
1987 {
1988 errno = EINVAL;
1989 return -1;
1990 }
1991
1992 listener = socket(AF_INET, type, 0);
1993 if(listener == -1)
1994 return -1;
1995 memset(&listen_addr, 0, sizeof(listen_addr));
1996 listen_addr.sin_family = AF_INET;
1997 listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1998 listen_addr.sin_port = 0; /* kernel choses port. */
3202e249 1999 if(bind(listener, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) == -1)
db137867
AC
2000 goto tidy_up_and_fail;
2001 if(listen(listener, 1) == -1)
2002 goto tidy_up_and_fail;
2003
2004 connector = socket(AF_INET, type, 0);
2005 if(connector == -1)
2006 goto tidy_up_and_fail;
2007 /* We want to find out the port number to connect to. */
2008 size = sizeof(connect_addr);
3202e249 2009 if(getsockname(listener, (struct sockaddr *)&connect_addr, &size) == -1)
db137867
AC
2010 goto tidy_up_and_fail;
2011 if(size != sizeof(connect_addr))
2012 goto abort_tidy_up_and_fail;
3202e249 2013 if(connect(connector, (struct sockaddr *)&connect_addr, sizeof(connect_addr)) == -1)
db137867
AC
2014 goto tidy_up_and_fail;
2015
2016 size = sizeof(listen_addr);
3202e249 2017 acceptor = accept(listener, (struct sockaddr *)&listen_addr, &size);
db137867
AC
2018 if(acceptor == -1)
2019 goto tidy_up_and_fail;
2020 if(size != sizeof(listen_addr))
2021 goto abort_tidy_up_and_fail;
2022 close(listener);
2023 /* Now check we are talking to ourself by matching port and host on the
2024 two sockets. */
3202e249 2025 if(getsockname(connector, (struct sockaddr *)&connect_addr, &size) == -1)
db137867
AC
2026 goto tidy_up_and_fail;
2027 if(size != sizeof(connect_addr)
2028 || listen_addr.sin_family != connect_addr.sin_family
2029 || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
2030 || listen_addr.sin_port != connect_addr.sin_port)
2031 {
2032 goto abort_tidy_up_and_fail;
2033 }
2034 fd[0] = connector;
2035 fd[1] = acceptor;
2036 return 0;
2037
2038 abort_tidy_up_and_fail:
2039 errno = EINVAL; /* I hope this is portable and appropriate. */
2040
2041 tidy_up_and_fail:
2042 {
2043 int save_errno = errno;
2044 if(listener != -1)
2045 close(listener);
2046 if(connector != -1)
2047 close(connector);
2048 if(acceptor != -1)
2049 close(acceptor);
2050 errno = save_errno;
2051 return -1;
2052 }
2053}
2054
2055#endif
2056
2057
2058static void (*setselect_handler) (rb_fde_t *, unsigned int, PF *, void *);
2059static int (*select_handler) (long);
2060static int (*setup_fd_handler) (rb_fde_t *);
2061static int (*io_sched_event) (struct ev_entry *, int);
2062static void (*io_unsched_event) (struct ev_entry *);
2063static int (*io_supports_event) (void);
2064static void (*io_init_event) (void);
2065static char iotype[25];
2066
2067const char *
2068rb_get_iotype(void)
2069{
2070 return iotype;
2071}
2072
2073static int
2074rb_unsupported_event(void)
2075{
2076 return 0;
2077}
2078
2079static int
2080try_kqueue(void)
2081{
2082 if(!rb_init_netio_kqueue())
2083 {
2084 setselect_handler = rb_setselect_kqueue;
2085 select_handler = rb_select_kqueue;
2086 setup_fd_handler = rb_setup_fd_kqueue;
2087 io_sched_event = rb_kqueue_sched_event;
2088 io_unsched_event = rb_kqueue_unsched_event;
2089 io_init_event = rb_kqueue_init_event;
2090 io_supports_event = rb_kqueue_supports_event;
2091 rb_strlcpy(iotype, "kqueue", sizeof(iotype));
2092 return 0;
2093 }
3202e249 2094 return -1;
db137867
AC
2095}
2096
2097static int
2098try_epoll(void)
2099{
2100 if(!rb_init_netio_epoll())
2101 {
2102 setselect_handler = rb_setselect_epoll;
2103 select_handler = rb_select_epoll;
2104 setup_fd_handler = rb_setup_fd_epoll;
2105 io_sched_event = rb_epoll_sched_event;
2106 io_unsched_event = rb_epoll_unsched_event;
2107 io_supports_event = rb_epoll_supports_event;
2108 io_init_event = rb_epoll_init_event;
2109 rb_strlcpy(iotype, "epoll", sizeof(iotype));
2110 return 0;
2111 }
2112 return -1;
2113}
2114
2115static int
2116try_ports(void)
2117{
2118 if(!rb_init_netio_ports())
2119 {
2120 setselect_handler = rb_setselect_ports;
2121 select_handler = rb_select_ports;
3202e249 2122 setup_fd_handler = rb_setup_fd_ports;
030272f3
VY
2123 io_sched_event = rb_ports_sched_event;
2124 io_unsched_event = rb_ports_unsched_event;
2125 io_init_event = rb_ports_init_event;
2126 io_supports_event = rb_ports_supports_event;
db137867
AC
2127 rb_strlcpy(iotype, "ports", sizeof(iotype));
2128 return 0;
2129 }
2130 return -1;
2131}
2132
2133static int
2134try_devpoll(void)
2135{
2136 if(!rb_init_netio_devpoll())
2137 {
2138 setselect_handler = rb_setselect_devpoll;
2139 select_handler = rb_select_devpoll;
3202e249 2140 setup_fd_handler = rb_setup_fd_devpoll;
db137867
AC
2141 io_sched_event = NULL;
2142 io_unsched_event = NULL;
2143 io_init_event = NULL;
2144 io_supports_event = rb_unsupported_event;
2145 rb_strlcpy(iotype, "devpoll", sizeof(iotype));
2146 return 0;
2147 }
2148 return -1;
2149}
2150
2151static int
2152try_sigio(void)
2153{
2154 if(!rb_init_netio_sigio())
2155 {
2156 setselect_handler = rb_setselect_sigio;
2157 select_handler = rb_select_sigio;
3202e249 2158 setup_fd_handler = rb_setup_fd_sigio;
db137867 2159 io_sched_event = rb_sigio_sched_event;
3202e249
VY
2160 io_unsched_event = rb_sigio_unsched_event;
2161 io_supports_event = rb_sigio_supports_event;
2162 io_init_event = rb_sigio_init_event;
2163
db137867
AC
2164 rb_strlcpy(iotype, "sigio", sizeof(iotype));
2165 return 0;
2166 }
2167 return -1;
2168}
2169
3202e249 2170static int
db137867
AC
2171try_poll(void)
2172{
2173 if(!rb_init_netio_poll())
2174 {
2175 setselect_handler = rb_setselect_poll;
2176 select_handler = rb_select_poll;
3202e249 2177 setup_fd_handler = rb_setup_fd_poll;
db137867
AC
2178 io_sched_event = NULL;
2179 io_unsched_event = NULL;
2180 io_init_event = NULL;
2181 io_supports_event = rb_unsupported_event;
2182 rb_strlcpy(iotype, "poll", sizeof(iotype));
2183 return 0;
2184 }
2185 return -1;
2186}
2187
2188static int
2189try_win32(void)
2190{
2191 if(!rb_init_netio_win32())
2192 {
2193 setselect_handler = rb_setselect_win32;
2194 select_handler = rb_select_win32;
3202e249 2195 setup_fd_handler = rb_setup_fd_win32;
db137867
AC
2196 io_sched_event = NULL;
2197 io_unsched_event = NULL;
2198 io_init_event = NULL;
2199 io_supports_event = rb_unsupported_event;
2200 rb_strlcpy(iotype, "win32", sizeof(iotype));
2201 return 0;
2202 }
2203 return -1;
2204}
2205
2206static int
2207try_select(void)
3202e249 2208{
db137867
AC
2209 if(!rb_init_netio_select())
2210 {
2211 setselect_handler = rb_setselect_select;
2212 select_handler = rb_select_select;
3202e249 2213 setup_fd_handler = rb_setup_fd_select;
db137867
AC
2214 io_sched_event = NULL;
2215 io_unsched_event = NULL;
2216 io_init_event = NULL;
2217 io_supports_event = rb_unsupported_event;
2218 rb_strlcpy(iotype, "select", sizeof(iotype));
2219 return 0;
2220 }
2221 return -1;
2222}
2223
2224
2225int
2226rb_io_sched_event(struct ev_entry *ev, int when)
2227{
3202e249
VY
2228 if(ev == NULL || io_supports_event == NULL || io_sched_event == NULL
2229 || !io_supports_event())
db137867
AC
2230 return 0;
2231 return io_sched_event(ev, when);
2232}
2233
2234void
2235rb_io_unsched_event(struct ev_entry *ev)
2236{
3202e249
VY
2237 if(ev == NULL || io_supports_event == NULL || io_unsched_event == NULL
2238 || !io_supports_event())
db137867 2239 return;
3202e249 2240 io_unsched_event(ev);
db137867 2241}
3202e249 2242
db137867
AC
2243int
2244rb_io_supports_event(void)
2245{
2246 if(io_supports_event == NULL)
2247 return 0;
2248 return io_supports_event();
2249}
2250
2251void
2252rb_io_init_event(void)
2253{
2254 io_init_event();
2255 rb_event_io_register_all();
2256}
2257
2258void
2259rb_init_netio(void)
2260{
2261 char *ioenv = getenv("LIBRB_USE_IOTYPE");
2262 rb_fd_table = rb_malloc(RB_FD_HASH_SIZE * sizeof(rb_dlink_list));
2263 rb_init_ssl();
3202e249 2264
db137867
AC
2265 if(ioenv != NULL)
2266 {
2267 if(!strcmp("epoll", ioenv))
2268 {
2269 if(!try_epoll())
2270 return;
3202e249
VY
2271 }
2272 else if(!strcmp("kqueue", ioenv))
db137867
AC
2273 {
2274 if(!try_kqueue())
2275 return;
3202e249
VY
2276 }
2277 else if(!strcmp("ports", ioenv))
db137867
AC
2278 {
2279 if(!try_ports())
2280 return;
3202e249
VY
2281 }
2282 else if(!strcmp("poll", ioenv))
db137867
AC
2283 {
2284 if(!try_poll())
2285 return;
3202e249
VY
2286 }
2287 else if(!strcmp("devpoll", ioenv))
db137867
AC
2288 {
2289 if(!try_devpoll())
2290 return;
3202e249
VY
2291 }
2292 else if(!strcmp("sigio", ioenv))
db137867
AC
2293 {
2294 if(!try_sigio())
2295 return;
3202e249
VY
2296 }
2297 else if(!strcmp("select", ioenv))
db137867 2298 {
3202e249 2299 if(!try_select())
db137867
AC
2300 return;
2301 }
3202e249 2302 if(!strcmp("win32", ioenv))
db137867 2303 {
3202e249 2304 if(!try_win32())
db137867
AC
2305 return;
2306 }
3202e249 2307
db137867
AC
2308 }
2309
2310 if(!try_kqueue())
2311 return;
2312 if(!try_epoll())
2313 return;
2314 if(!try_ports())
2315 return;
2316 if(!try_devpoll())
2317 return;
2318 if(!try_sigio())
2319 return;
2320 if(!try_poll())
2321 return;
2322 if(!try_win32())
2323 return;
2324 if(!try_select())
2325 return;
2326
2327 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
2328
2329 abort();
2330}
2331
3202e249 2332void
db137867
AC
2333rb_setselect(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
2334{
2335 setselect_handler(F, type, handler, client_data);
2336}
2337
3202e249 2338int
db137867
AC
2339rb_select(unsigned long timeout)
2340{
2341 int ret = select_handler(timeout);
2342 free_fds();
2343 return ret;
2344}
2345
3202e249 2346int
db137867
AC
2347rb_setup_fd(rb_fde_t *F)
2348{
2349 return setup_fd_handler(F);
2350}
2351
2352
db137867
AC
2353int
2354rb_ignore_errno(int error)
2355{
3202e249 2356 switch (error)
db137867
AC
2357 {
2358#ifdef EINPROGRESS
3202e249 2359 case EINPROGRESS:
db137867
AC
2360#endif
2361#if defined EWOULDBLOCK
3202e249 2362 case EWOULDBLOCK:
db137867
AC
2363#endif
2364#if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
3202e249 2365 case EAGAIN:
db137867
AC
2366#endif
2367#ifdef EINTR
3202e249 2368 case EINTR:
db137867
AC
2369#endif
2370#ifdef ERESTART
3202e249 2371 case ERESTART:
db137867
AC
2372#endif
2373#ifdef ENOBUFS
3202e249
VY
2374 case ENOBUFS:
2375#endif
2376 return 1;
2377 default:
2378 break;
2379 }
db137867
AC
2380 return 0;
2381}
2382
2383
3202e249 2384#if defined(HAVE_SENDMSG) && !defined(WIN32)
db137867
AC
2385int
2386rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2387{
2388 struct msghdr msg;
2389 struct cmsghdr *cmsg;
2390 struct iovec iov[1];
2391 struct stat st;
a9fb3ed0 2392 uint8_t stype = RB_FD_UNKNOWN;
db137867 2393 const char *desc;
dc7e6b42 2394 rb_platform_fd_t fd, len, x, rfds;
db137867
AC
2395
2396 int control_len = CMSG_SPACE(sizeof(int) * nfds);
2397
2398 iov[0].iov_base = data;
2399 iov[0].iov_len = datasize;
3202e249 2400
db137867
AC
2401 msg.msg_name = NULL;
2402 msg.msg_namelen = 0;
2403 msg.msg_iov = iov;
2404 msg.msg_iovlen = 1;
2405 msg.msg_flags = 0;
2406 cmsg = alloca(control_len);
2407 msg.msg_control = cmsg;
2408 msg.msg_controllen = control_len;
2409
2410 if((len = recvmsg(rb_get_fd(F), &msg, 0)) <= 0)
2411 return len;
2412
3202e249
VY
2413 if(msg.msg_controllen > 0 && msg.msg_control != NULL
2414 && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL)
db137867 2415 {
90e960f0 2416 rfds = ((unsigned char *)cmsg + cmsg->cmsg_len - CMSG_DATA(cmsg)) / sizeof(int);
db137867
AC
2417
2418 for(x = 0; x < nfds && x < rfds; x++)
2419 {
2420 fd = ((int *)CMSG_DATA(cmsg))[x];
2421 stype = RB_FD_UNKNOWN;
2422 desc = "remote unknown";
2423 if(!fstat(fd, &st))
2424 {
2425 if(S_ISSOCK(st.st_mode))
2426 {
2427 stype = RB_FD_SOCKET;
2428 desc = "remote socket";
2429 }
2430 else if(S_ISFIFO(st.st_mode))
2431 {
2432 stype = RB_FD_PIPE;
2433 desc = "remote pipe";
2434 }
2435 else if(S_ISREG(st.st_mode))
2436 {
2437 stype = RB_FD_FILE;
2438 desc = "remote file";
2439 }
2440 }
2441 xF[x] = rb_open(fd, stype, desc);
2442 }
3202e249
VY
2443 }
2444 else
db137867 2445 *xF = NULL;
3202e249 2446 return len;
db137867
AC
2447}
2448
2449
2450int
8679c0fe 2451rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid __attribute__((unused)))
db137867 2452{
db137867
AC
2453 struct msghdr msg;
2454 struct cmsghdr *cmsg;
2455 struct iovec iov[1];
2456 char empty = '0';
db137867 2457
5cc7ba25 2458 memset(&msg, 0, sizeof(msg));
db137867
AC
2459 if(datasize == 0)
2460 {
2461 iov[0].iov_base = &empty;
3202e249
VY
2462 iov[0].iov_len = 1;
2463 }
2464 else
2465 {
db137867
AC
2466 iov[0].iov_base = data;
2467 iov[0].iov_len = datasize;
2468 }
2469 msg.msg_iov = iov;
2470 msg.msg_iovlen = 1;
2471 msg.msg_name = NULL;
2472 msg.msg_namelen = 0;
2473 msg.msg_flags = 0;
2474 msg.msg_control = NULL;
2475 msg.msg_controllen = 0;
2476
2477 if(count > 0)
2478 {
e23126c8 2479 size_t ucount = (size_t)count;
db137867 2480 int len = CMSG_SPACE(sizeof(int) * count);
5cc7ba25 2481 char buf[len];
db137867
AC
2482
2483 msg.msg_control = buf;
2484 msg.msg_controllen = len;
2485 cmsg = CMSG_FIRSTHDR(&msg);
2486 cmsg->cmsg_level = SOL_SOCKET;
2487 cmsg->cmsg_type = SCM_RIGHTS;
2488 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * count);
2489
e23126c8 2490 for(size_t i = 0; i < ucount; i++)
3202e249
VY
2491 {
2492 ((int *)CMSG_DATA(cmsg))[i] = rb_get_fd(F[i]);
db137867
AC
2493 }
2494 msg.msg_controllen = cmsg->cmsg_len;
5cc7ba25 2495 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
db137867 2496 }
5cc7ba25 2497 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
db137867 2498}
4eafa9e6 2499#else /* defined(HAVE_SENDMSG) && !defined(WIN32) */
3202e249
VY
2500#ifndef _WIN32
2501int
2502rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2503{
2504 errno = ENOSYS;
2505 return -1;
2506}
db137867 2507
3202e249
VY
2508int
2509rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid)
2510{
2511 errno = ENOSYS;
2512 return -1;
2513}
4eafa9e6
EM
2514#endif /* _WIN32 */
2515#endif /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2516
4eafa9e6
EM
2517int
2518rb_ipv4_from_ipv6(const struct sockaddr_in6 *restrict ip6, struct sockaddr_in *restrict ip4)
2519{
2520 int i;
2521
2522 if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x02", 2))
2523 {
2524 /* 6to4 and similar */
2525 memcpy(&ip4->sin_addr, ip6->sin6_addr.s6_addr + 2, 4);
2526 }
2527 else if (!memcmp(ip6->sin6_addr.s6_addr, "\x20\x01\x00\x00", 4))
2528 {
2529 /* Teredo */
2530 for (i = 0; i < 4; i++)
2531 ((uint8_t *)&ip4->sin_addr)[i] = 0xFF ^
2532 ip6->sin6_addr.s6_addr[12 + i];
2533 }
2534 else
2535 return 0;
2536 SET_SS_LEN(ip4, sizeof(struct sockaddr_in));
2537 ip4->sin_family = AF_INET;
2538 ip4->sin_port = 0;
2539 return 1;
2540}