]> jfr.im git - solanum.git/blob - librb/src/commio.c
Merge pull request #278 from edk0/override
[solanum.git] / librb / src / commio.c
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 *
24 */
25
26 #include <librb_config.h>
27 #include <rb_lib.h>
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
41 struct 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
50 rb_dlink_list *rb_fd_table;
51 static rb_bh *fd_heap;
52
53 static rb_dlink_list timeout_list;
54 static rb_dlink_list closed_list;
55
56 static struct ev_entry *rb_timeout_ev;
57
58
59 static const char *rb_err_str[] = { "Comm OK", "Error during bind()",
60 "Error during DNS lookup", "connect timeout",
61 "Error during connect()",
62 "Comm Error",
63 "Error with SSL"
64 };
65
66 /* Highest FD and number of open FDs .. */
67 static int number_fd = 0;
68 int rb_maxconnections = 0;
69
70 static PF rb_connect_timeout;
71 static PF rb_connect_outcome;
72 static void mangle_mapped_sockaddr(struct sockaddr *in);
73
74 #ifndef HAVE_SOCKETPAIR
75 static int rb_inet_socketpair(int d, int type, int protocol, rb_platform_fd_t sv[2]);
76 static int rb_inet_socketpair_udp(rb_fde_t **newF1, rb_fde_t **newF2);
77 #endif
78
79 static inline rb_fde_t *
80 add_fd(rb_platform_fd_t fd)
81 {
82 rb_fde_t *F = rb_find_fd(fd);
83
84 /* look up to see if we have it already */
85 if(F != NULL)
86 return F;
87
88 F = rb_bh_alloc(fd_heap);
89 F->fd = fd;
90 rb_dlinkAdd(F, &F->node, &rb_fd_table[rb_hash_fd(fd)]);
91 return (F);
92 }
93
94 static inline void
95 remove_fd(rb_fde_t *F)
96 {
97 if(F == NULL || !IsFDOpen(F))
98 return;
99
100 rb_dlinkMoveNode(&F->node, &rb_fd_table[rb_hash_fd(F->fd)], &closed_list);
101 }
102
103 static void
104 free_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;
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
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)
132 static void
133 rb_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
152 static void
153 rb_close_all(void)
154 {
155 #ifndef _WIN32
156 int i;
157
158 /* XXX someone tell me why we care about 4 fd's ? */
159 /* XXX btw, fd 3 is used for profiler ! */
160 for(i = 3; i < rb_maxconnections; ++i)
161 {
162 close(i);
163 }
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 */
174 int
175 rb_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
188 if(F != NULL
189 && !getsockopt(rb_get_fd(F), SOL_SOCKET, SO_ERROR, (char *)&err, (rb_socklen_t *) & len))
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 */
202 int
203 rb_getmaxconnect(void)
204 {
205 return (rb_maxconnections);
206 }
207
208 /*
209 * set_sock_buffers - set send and receive buffers for socket
210 *
211 * inputs - fd file descriptor
212 * - size to set
213 * output - returns true (1) if successful, false (0) otherwise
214 * side effects -
215 */
216 int
217 rb_set_buffers(rb_fde_t *F, int size)
218 {
219 if(F == NULL)
220 return 0;
221 if(setsockopt
222 (F->fd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size))
223 || setsockopt(F->fd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)))
224 return 0;
225 return 1;
226 }
227
228 /*
229 * set_non_blocking - Set the client connection into non-blocking mode.
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 */
236 int
237 rb_set_nb(rb_fde_t *F)
238 {
239 int nonb = 0;
240 int res;
241 rb_platform_fd_t fd;
242 if(F == NULL)
243 return 0;
244 fd = F->fd;
245
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 */
268 void
269 rb_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;
278 if(callback == NULL) /* user wants to remove */
279 {
280 if(td == NULL)
281 return;
282 rb_dlinkDelete(&td->node, &timeout_list);
283 rb_free(td);
284 F->timeout = NULL;
285 if(rb_dlink_list_length(&timeout_list) == 0)
286 {
287 rb_event_delete(rb_timeout_ev);
288 rb_timeout_ev = NULL;
289 }
290 return;
291 }
292
293 if(F->timeout == NULL)
294 td = F->timeout = rb_malloc(sizeof(struct timeout_data));
295
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 {
303 rb_timeout_ev = rb_event_add("rb_checktimeouts", rb_checktimeouts, NULL, 5);
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 */
314 void
315 rb_checktimeouts(void *notused)
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);
338 }
339 }
340 }
341
342 static int
343 rb_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
359 static int
360 rb_setsockopt_sctp(rb_fde_t *F)
361 {
362 int opt_zero = 0;
363 int opt_one = 1;
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;
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
380 ret = setsockopt(F->fd, SOL_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &opt_mapped, sizeof(opt_mapped));
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
449 int
450 rb_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
465 #ifdef HAVE_LIBSCTP
466 static int
467 rb_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
484 int
485 rb_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
497 ret = rb_sctp_bindx_only(F, addrs, len);
498 if (ret)
499 return ret;
500
501 return 0;
502 #else
503 return -1;
504 #endif
505 }
506
507 int
508 rb_inet_get_proto(rb_fde_t *F)
509 {
510 #ifdef HAVE_LIBSCTP
511 if (F->type & RB_FD_SCTP)
512 return IPPROTO_SCTP;
513 #endif
514 return IPPROTO_TCP;
515 }
516
517 static void rb_accept_tryaccept(rb_fde_t *F, void *data) {
518 struct rb_sockaddr_storage st;
519 rb_fde_t *new_F;
520 rb_socklen_t addrlen;
521 int new_fd;
522
523 while(1)
524 {
525 memset(&st, 0, sizeof(st));
526 addrlen = sizeof(st);
527
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
538 new_F = rb_open(new_fd, RB_FD_SOCKET | (F->type & RB_FD_INHERIT_TYPES), "Incoming Connection");
539
540 if(new_F == NULL)
541 {
542 rb_lib_log
543 ("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d",
544 new_fd);
545 close(new_fd);
546 continue;
547 }
548
549 if(rb_unlikely(!rb_set_nb(new_F)))
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
556 mangle_mapped_sockaddr((struct sockaddr *)&st);
557
558 if(F->accept->precb != NULL)
559 {
560 if(!F->accept->precb(new_F, (struct sockaddr *)&st, addrlen, F->accept->data)) /* pre-callback decided to drop it */
561 continue;
562 }
563 #ifdef HAVE_SSL
564 if(F->type & RB_FD_SSL)
565 {
566 rb_ssl_accept_setup(F, new_F, (struct sockaddr *)&st, addrlen);
567 }
568 else
569 #endif /* HAVE_SSL */
570 {
571 F->accept->callback(new_F, RB_OK, (struct sockaddr *)&st, addrlen,
572 F->accept->data);
573 }
574 }
575
576 }
577
578 /* try to accept a TCP connection */
579 void
580 rb_accept_tcp(rb_fde_t *F, ACPRE * precb, ACCB * callback, void *data)
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 /*
594 * void rb_connect_tcp(rb_platform_fd_t fd, struct sockaddr *dest,
595 * struct sockaddr *clocal,
596 * CNCB *callback, void *data, int timeout)
597 * Input: An fd to connect with, a host and port to connect to,
598 * a local sockaddr to connect from (or NULL to use the
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 */
606 void
607 rb_connect_tcp(rb_fde_t *F, struct sockaddr *dest,
608 struct sockaddr *clocal, CNCB * callback, void *data, int timeout)
609 {
610 int retval;
611
612 if (F == NULL)
613 return;
614
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 */
629 if((clocal != NULL) && (bind(F->fd, clocal, GET_SS_LEN(clocal)) < 0))
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);
640
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 }
666
667 void
668 rb_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
742 /*
743 * rb_connect_callback() - call the callback, and continue with life
744 */
745 void
746 rb_connect_callback(rb_fde_t *F, int status)
747 {
748 CNCB *hdl;
749 void *data;
750 int errtmp = errno; /* save errno as rb_settimeout clobbers it sometimes */
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
760
761 /* Clear the timeout handler */
762 rb_settimeout(F, 0, NULL, NULL);
763 errno = errtmp;
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 */
774 static void
775 rb_connect_timeout(rb_fde_t *F, void *notused)
776 {
777 /* error! */
778 rb_connect_callback(F, RB_ERR_TIMEOUT);
779 }
780
781 static void
782 rb_connect_outcome(rb_fde_t *F, void *notused)
783 {
784 int retval;
785 int err = 0;
786 socklen_t len = sizeof(err);
787
788 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
789 return;
790 retval = getsockopt(F->fd, SOL_SOCKET, SO_ERROR, &err, &len);
791 if (retval < 0) {
792 rb_get_errno();
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);
800 return;
801 }
802 /* If we get here, we've succeeded, so call with RB_OK */
803 rb_connect_callback(F, RB_OK);
804 }
805
806
807 int
808 rb_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 */
820 const char *
821 rb_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
829 int
830 rb_socketpair(int family, int sock_type, int proto, rb_fde_t **F1, rb_fde_t **F2, const char *note)
831 {
832 rb_platform_fd_t nfd[2];
833 if(number_fd >= rb_maxconnections)
834 {
835 errno = ENFILE;
836 return -1;
837 }
838
839 #ifdef HAVE_SOCKETPAIR
840 if(socketpair(family, sock_type, proto, nfd))
841 #else
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))
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 */
871 if(rb_unlikely(!rb_set_nb(*F1)))
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
879 if(rb_unlikely(!rb_set_nb(*F2)))
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
891 int
892 rb_pipe(rb_fde_t **F1, rb_fde_t **F2, const char *desc)
893 {
894 #ifndef _WIN32
895 rb_platform_fd_t fd[2];
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
908 if(rb_unlikely(!rb_set_nb(*F1)))
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
916 if(rb_unlikely(!rb_set_nb(*F2)))
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 */
930 return rb_socketpair(AF_INET, SOCK_STREAM, 0, F1, F2, desc);
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 */
941 rb_fde_t *
942 rb_socket(int family, int sock_type, int proto, const char *note)
943 {
944 rb_fde_t *F;
945 rb_platform_fd_t fd;
946 /* First, make sure we aren't going to run out of file descriptors */
947 if(rb_unlikely(number_fd >= rb_maxconnections))
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);
960 if(rb_unlikely(fd < 0))
961 return NULL; /* errno will be passed through, yay.. */
962
963 /*
964 * Make sure we can take both IPv4 and IPv6 connections
965 * on an AF_INET6 SCTP socket, otherwise keep them separate
966 */
967 if(family == AF_INET6)
968 {
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)
975 {
976 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to %d on FD %d: %s",
977 v6only, fd, strerror(errno));
978 close(fd);
979 return NULL;
980 }
981 }
982
983 F = rb_open(fd, RB_FD_SOCKET, note);
984 if(F == NULL)
985 {
986 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd,
987 strerror(errno));
988 close(fd);
989 return NULL;
990 }
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
1005 /* Set the socket non-blocking, and other wonderful bits */
1006 if(rb_unlikely(!rb_set_nb(F)))
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 */
1020 static void
1021 mangle_mapped_sockaddr(struct sockaddr *in)
1022 {
1023 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)in;
1024
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;
1031 in4.sin_addr.s_addr = ((uint32_t *)&in6->sin6_addr)[3];
1032 memcpy(in, &in4, sizeof(struct sockaddr_in));
1033 }
1034 }
1035
1036 /*
1037 * rb_listen() - listen on a port
1038 */
1039 int
1040 rb_listen(rb_fde_t *F, int backlog, int defer_accept)
1041 {
1042 int result;
1043
1044 F->type = RB_FD_SOCKET | RB_FD_LISTEN | (F->type & RB_FD_INHERIT_TYPES);
1045 result = listen(F->fd, backlog);
1046
1047 #ifdef TCP_DEFER_ACCEPT
1048 if (defer_accept && !result)
1049 {
1050 (void)setsockopt(F->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &backlog, sizeof(int));
1051 }
1052 #endif
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
1064
1065 return result;
1066 }
1067
1068 void
1069 rb_fdlist_init(int closeall, int maxfds, size_t heapsize)
1070 {
1071 static int initialized = 0;
1072 #ifdef _WIN32
1073 WSADATA wsaData;
1074 int err;
1075 int vers = MAKEWORD(2, 0);
1076
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 */
1098 rb_fde_t *
1099 rb_open(rb_platform_fd_t fd, uint8_t type, const char *desc)
1100 {
1101 rb_fde_t *F;
1102 lrb_assert(fd >= 0);
1103
1104 F = add_fd(fd);
1105
1106 lrb_assert(!IsFDOpen(F));
1107 if(rb_unlikely(IsFDOpen(F)))
1108 {
1109 const char *fdesc;
1110 if(F != NULL && F->desc != NULL)
1111 fdesc = F->desc;
1112 else
1113 fdesc = "NULL";
1114 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd, fdesc);
1115 return NULL;
1116 }
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 */
1129 void
1130 rb_close(rb_fde_t *F)
1131 {
1132 int type, fd;
1133
1134 if(F == NULL)
1135 return;
1136
1137 fd = F->fd;
1138 type = F->type;
1139 lrb_assert(IsFDOpen(F));
1140
1141 lrb_assert(!(type & RB_FD_FILE));
1142 if(rb_unlikely(type & RB_FD_FILE))
1143 {
1144 lrb_assert(F->read_handler == NULL);
1145 lrb_assert(F->write_handler == NULL);
1146 }
1147
1148 if (type & RB_FD_LISTEN) {
1149 listen(F->fd, 0);
1150 }
1151
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 }
1168
1169 if(type & RB_FD_LISTEN)
1170 shutdown(fd, SHUT_RDWR);
1171 }
1172
1173
1174 /*
1175 * rb_dump_fd() - dump the list of active filedescriptors
1176 */
1177 void
1178 rb_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 */
1210 void
1211 rb_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
1220 void
1221 rb_set_type(rb_fde_t *F, uint8_t type)
1222 {
1223 /* if the caller is calling this, lets assume they have a clue */
1224 F->type = type;
1225 return;
1226 }
1227
1228 uint8_t
1229 rb_get_type(rb_fde_t *F)
1230 {
1231 return F->type;
1232 }
1233
1234 int
1235 rb_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
1244 rb_platform_fd_t
1245 rb_get_fd(rb_fde_t *F)
1246 {
1247 if(F == NULL)
1248 return -1;
1249 return (F->fd);
1250 }
1251
1252 rb_fde_t *
1253 rb_get_fde(rb_platform_fd_t fd)
1254 {
1255 return rb_find_fd(fd);
1256 }
1257
1258 ssize_t
1259 rb_read(rb_fde_t *F, void *buf, int count)
1260 {
1261 ssize_t ret;
1262 if(F == NULL)
1263 return 0;
1264
1265 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
1266 * an SSL socket as a regular socket
1267 */
1268 #ifdef HAVE_SSL
1269 if(F->type & RB_FD_SSL)
1270 {
1271 return rb_ssl_read(F, buf, count);
1272 }
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
1290 ssize_t
1291 rb_write(rb_fde_t *F, const void *buf, int count)
1292 {
1293 ssize_t ret;
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);
1301 }
1302 #endif
1303 if(F->type & RB_FD_SOCKET)
1304 {
1305 ret = send(F->fd, buf, count, MSG_NOSIGNAL);
1306 if(ret < 0)
1307 {
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)
1317 static ssize_t
1318 rb_fake_writev(rb_fde_t *F, const struct rb_iovec *vp, size_t vpcount)
1319 {
1320 ssize_t count = 0;
1321
1322 while(vpcount-- > 0)
1323 {
1324 ssize_t written = rb_write(F, vp->iov_base, vp->iov_len);
1325
1326 if(written <= 0)
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)
1341 ssize_t
1342 rb_writev(rb_fde_t *F, struct rb_iovec * vecount, int count)
1343 {
1344 return rb_fake_writev(F, vecount, count);
1345 }
1346
1347 #else
1348 ssize_t
1349 rb_writev(rb_fde_t *F, struct rb_iovec * vector, int count)
1350 {
1351 if(F == NULL)
1352 {
1353 errno = EBADF;
1354 return -1;
1355 }
1356 #ifdef HAVE_SSL
1357 if(F->type & RB_FD_SSL)
1358 {
1359 return rb_fake_writev(F, vector, count);
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);
1370 }
1371 #endif /* HAVE_SENDMSG */
1372 return writev(F->fd, (struct iovec *)vector, count);
1373
1374 }
1375 #endif
1376
1377
1378 /*
1379 * From: Thomas Helvey <tomh@inxpress.net>
1380 */
1381 static 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
1421 static const char *
1422 inetntoa(const char *in)
1423 {
1424 static char buf[16];
1425 char *bufptr = buf;
1426 const unsigned char *a = (const unsigned char *)in;
1427 const char *n;
1428
1429 n = IpQuadTab[*a++];
1430 while(*n)
1431 *bufptr++ = *n++;
1432 *bufptr++ = '.';
1433 n = IpQuadTab[*a++];
1434 while(*n)
1435 *bufptr++ = *n++;
1436 *bufptr++ = '.';
1437 n = IpQuadTab[*a++];
1438 while(*n)
1439 *bufptr++ = *n++;
1440 *bufptr++ = '.';
1441 n = IpQuadTab[*a];
1442 while(*n)
1443 *bufptr++ = *n++;
1444 *bufptr = '\0';
1445 return buf;
1446 }
1447
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
1453 static const char *inet_ntop4(const unsigned char *src, char *dst, unsigned int size);
1454 static const char *inet_ntop6(const unsigned char *src, char *dst, unsigned int size);
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 */
1467 static const char *
1468 inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
1469 {
1470 if(size < 16)
1471 return NULL;
1472 return strcpy(dst, inetntoa((const char *)src));
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 */
1481 static const char *
1482 inet_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);
1506 for(i = 0; i < IN6ADDRSZ; i += 2)
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;
1512 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
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;
1543 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
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 }
1568 tp += sprintf(tp, "%x", words[i]);
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
1579 if((unsigned int)(tp - tmp) > size)
1580 {
1581 return (NULL);
1582 }
1583 return memcpy(dst, tmp, tp - tmp);
1584 }
1585
1586 int
1587 rb_inet_pton_sock(const char *src, struct sockaddr_storage *dst)
1588 {
1589 memset(dst, 0, sizeof(*dst));
1590 if(rb_inet_pton(AF_INET, src, &((struct sockaddr_in *)dst)->sin_addr))
1591 {
1592 SET_SS_FAMILY(dst, AF_INET);
1593 SET_SS_PORT(dst, 0);
1594 SET_SS_LEN(dst, sizeof(struct sockaddr_in));
1595 return 1;
1596 }
1597 else if(rb_inet_pton(AF_INET6, src, &((struct sockaddr_in6 *)dst)->sin6_addr))
1598 {
1599 SET_SS_FAMILY(dst, AF_INET6);
1600 SET_SS_PORT(dst, 0);
1601 SET_SS_LEN(dst, sizeof(struct sockaddr_in6));
1602 return 1;
1603 }
1604 return 0;
1605 }
1606
1607 const char *
1608 rb_inet_ntop_sock(struct sockaddr *src, char *dst, unsigned int size)
1609 {
1610 switch (src->sa_family)
1611 {
1612 case AF_INET:
1613 return (rb_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, dst, size));
1614 case AF_INET6:
1615 return (rb_inet_ntop
1616 (AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr, dst, size));
1617 default:
1618 return NULL;
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 */
1630 const char *
1631 rb_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));
1637 case AF_INET6:
1638 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) ||
1639 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src))
1640 return (inet_ntop4
1641 ((const unsigned char *)&((const struct in6_addr *)src)->
1642 s6_addr[12], dst, size));
1643 else
1644 return (inet_ntop6(src, dst, size));
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 */
1678 static int
1679 inet_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;
1687 while((ch = *src++) != '\0')
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
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
1734 static int
1735 inet_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;
1753 while((ch = tolower((unsigned char)*src++)) != '\0')
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);
1783 *tp++ = (unsigned char)(val >> 8) & 0xff;
1784 *tp++ = (unsigned char)val & 0xff;
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);
1806 *tp++ = (unsigned char)(val >> 8) & 0xff;
1807 *tp++ = (unsigned char)val & 0xff;
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);
1820 for(i = 1; i <= n; i++)
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 }
1832
1833 int
1834 rb_inet_pton(int af, const char *src, void *dst)
1835 {
1836 switch (af)
1837 {
1838 case AF_INET:
1839 return (inet_pton4(src, dst));
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];
1845 sprintf(tmp, "::ffff:%s", src);
1846 return (inet_pton6(tmp, dst));
1847 }
1848 else
1849 return (inet_pton6(src, dst));
1850 default:
1851 return (-1);
1852 }
1853 /* NOTREACHED */
1854 }
1855
1856
1857 #ifndef HAVE_SOCKETPAIR
1858
1859 /* mostly based on perl's emulation of socketpair udp */
1860 static int
1861 rb_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];
1866 rb_platform_fd_t fd[2];
1867 int i, got;
1868 unsigned short port;
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;
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
1913 max = fd[1] > fd[0] ? fd[1] : fd[0];
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
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
1950 #ifndef ECONNABORTED
1951 #define ECONNABORTED WSAECONNABORTED
1952 #endif
1953 #endif
1954
1955 abort_failed:
1956 rb_get_errno();
1957 errno = ECONNABORTED;
1958 failed:
1959 if(errno != ECONNABORTED)
1960 rb_get_errno();
1961 o_errno = errno;
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
1971 int
1972 rb_inet_socketpair(int family, int type, int protocol, rb_platform_fd_t fd[2])
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;
1979 rb_socklen_t size;
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. */
1999 if(bind(listener, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) == -1)
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);
2009 if(getsockname(listener, (struct sockaddr *)&connect_addr, &size) == -1)
2010 goto tidy_up_and_fail;
2011 if(size != sizeof(connect_addr))
2012 goto abort_tidy_up_and_fail;
2013 if(connect(connector, (struct sockaddr *)&connect_addr, sizeof(connect_addr)) == -1)
2014 goto tidy_up_and_fail;
2015
2016 size = sizeof(listen_addr);
2017 acceptor = accept(listener, (struct sockaddr *)&listen_addr, &size);
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. */
2025 if(getsockname(connector, (struct sockaddr *)&connect_addr, &size) == -1)
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
2058 static void (*setselect_handler) (rb_fde_t *, unsigned int, PF *, void *);
2059 static int (*select_handler) (long);
2060 static int (*setup_fd_handler) (rb_fde_t *);
2061 static int (*io_sched_event) (struct ev_entry *, int);
2062 static void (*io_unsched_event) (struct ev_entry *);
2063 static int (*io_supports_event) (void);
2064 static void (*io_init_event) (void);
2065 static char iotype[25];
2066
2067 const char *
2068 rb_get_iotype(void)
2069 {
2070 return iotype;
2071 }
2072
2073 static int
2074 rb_unsupported_event(void)
2075 {
2076 return 0;
2077 }
2078
2079 static int
2080 try_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 }
2094 return -1;
2095 }
2096
2097 static int
2098 try_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
2115 static int
2116 try_ports(void)
2117 {
2118 if(!rb_init_netio_ports())
2119 {
2120 setselect_handler = rb_setselect_ports;
2121 select_handler = rb_select_ports;
2122 setup_fd_handler = rb_setup_fd_ports;
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;
2127 rb_strlcpy(iotype, "ports", sizeof(iotype));
2128 return 0;
2129 }
2130 return -1;
2131 }
2132
2133 static int
2134 try_devpoll(void)
2135 {
2136 if(!rb_init_netio_devpoll())
2137 {
2138 setselect_handler = rb_setselect_devpoll;
2139 select_handler = rb_select_devpoll;
2140 setup_fd_handler = rb_setup_fd_devpoll;
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
2151 static int
2152 try_sigio(void)
2153 {
2154 if(!rb_init_netio_sigio())
2155 {
2156 setselect_handler = rb_setselect_sigio;
2157 select_handler = rb_select_sigio;
2158 setup_fd_handler = rb_setup_fd_sigio;
2159 io_sched_event = rb_sigio_sched_event;
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
2164 rb_strlcpy(iotype, "sigio", sizeof(iotype));
2165 return 0;
2166 }
2167 return -1;
2168 }
2169
2170 static int
2171 try_poll(void)
2172 {
2173 if(!rb_init_netio_poll())
2174 {
2175 setselect_handler = rb_setselect_poll;
2176 select_handler = rb_select_poll;
2177 setup_fd_handler = rb_setup_fd_poll;
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
2188 static int
2189 try_win32(void)
2190 {
2191 if(!rb_init_netio_win32())
2192 {
2193 setselect_handler = rb_setselect_win32;
2194 select_handler = rb_select_win32;
2195 setup_fd_handler = rb_setup_fd_win32;
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
2206 static int
2207 try_select(void)
2208 {
2209 if(!rb_init_netio_select())
2210 {
2211 setselect_handler = rb_setselect_select;
2212 select_handler = rb_select_select;
2213 setup_fd_handler = rb_setup_fd_select;
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
2225 int
2226 rb_io_sched_event(struct ev_entry *ev, int when)
2227 {
2228 if(ev == NULL || io_supports_event == NULL || io_sched_event == NULL
2229 || !io_supports_event())
2230 return 0;
2231 return io_sched_event(ev, when);
2232 }
2233
2234 void
2235 rb_io_unsched_event(struct ev_entry *ev)
2236 {
2237 if(ev == NULL || io_supports_event == NULL || io_unsched_event == NULL
2238 || !io_supports_event())
2239 return;
2240 io_unsched_event(ev);
2241 }
2242
2243 int
2244 rb_io_supports_event(void)
2245 {
2246 if(io_supports_event == NULL)
2247 return 0;
2248 return io_supports_event();
2249 }
2250
2251 void
2252 rb_io_init_event(void)
2253 {
2254 io_init_event();
2255 rb_event_io_register_all();
2256 }
2257
2258 void
2259 rb_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();
2264
2265 if(ioenv != NULL)
2266 {
2267 if(!strcmp("epoll", ioenv))
2268 {
2269 if(!try_epoll())
2270 return;
2271 }
2272 else if(!strcmp("kqueue", ioenv))
2273 {
2274 if(!try_kqueue())
2275 return;
2276 }
2277 else if(!strcmp("ports", ioenv))
2278 {
2279 if(!try_ports())
2280 return;
2281 }
2282 else if(!strcmp("poll", ioenv))
2283 {
2284 if(!try_poll())
2285 return;
2286 }
2287 else if(!strcmp("devpoll", ioenv))
2288 {
2289 if(!try_devpoll())
2290 return;
2291 }
2292 else if(!strcmp("sigio", ioenv))
2293 {
2294 if(!try_sigio())
2295 return;
2296 }
2297 else if(!strcmp("select", ioenv))
2298 {
2299 if(!try_select())
2300 return;
2301 }
2302 if(!strcmp("win32", ioenv))
2303 {
2304 if(!try_win32())
2305 return;
2306 }
2307
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
2332 void
2333 rb_setselect(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
2334 {
2335 setselect_handler(F, type, handler, client_data);
2336 }
2337
2338 int
2339 rb_select(unsigned long timeout)
2340 {
2341 int ret = select_handler(timeout);
2342 free_fds();
2343 return ret;
2344 }
2345
2346 int
2347 rb_setup_fd(rb_fde_t *F)
2348 {
2349 return setup_fd_handler(F);
2350 }
2351
2352
2353 int
2354 rb_ignore_errno(int error)
2355 {
2356 switch (error)
2357 {
2358 #ifdef EINPROGRESS
2359 case EINPROGRESS:
2360 #endif
2361 #if defined EWOULDBLOCK
2362 case EWOULDBLOCK:
2363 #endif
2364 #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
2365 case EAGAIN:
2366 #endif
2367 #ifdef EINTR
2368 case EINTR:
2369 #endif
2370 #ifdef ERESTART
2371 case ERESTART:
2372 #endif
2373 #ifdef ENOBUFS
2374 case ENOBUFS:
2375 #endif
2376 return 1;
2377 default:
2378 break;
2379 }
2380 return 0;
2381 }
2382
2383
2384 #if defined(HAVE_SENDMSG) && !defined(WIN32)
2385 int
2386 rb_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;
2392 uint8_t stype = RB_FD_UNKNOWN;
2393 const char *desc;
2394 rb_platform_fd_t fd, len, x, rfds;
2395
2396 int control_len = CMSG_SPACE(sizeof(int) * nfds);
2397
2398 iov[0].iov_base = data;
2399 iov[0].iov_len = datasize;
2400
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
2413 if(msg.msg_controllen > 0 && msg.msg_control != NULL
2414 && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL)
2415 {
2416 rfds = ((unsigned char *)cmsg + cmsg->cmsg_len - CMSG_DATA(cmsg)) / sizeof(int);
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 }
2443 }
2444 else
2445 *xF = NULL;
2446 return len;
2447 }
2448
2449
2450 int
2451 rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid)
2452 {
2453 struct msghdr msg;
2454 struct cmsghdr *cmsg;
2455 struct iovec iov[1];
2456 char empty = '0';
2457
2458 memset(&msg, 0, sizeof(msg));
2459 if(datasize == 0)
2460 {
2461 iov[0].iov_base = &empty;
2462 iov[0].iov_len = 1;
2463 }
2464 else
2465 {
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 {
2479 size_t ucount = (size_t)count;
2480 int len = CMSG_SPACE(sizeof(int) * count);
2481 char buf[len];
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
2490 for(size_t i = 0; i < ucount; i++)
2491 {
2492 ((int *)CMSG_DATA(cmsg))[i] = rb_get_fd(F[i]);
2493 }
2494 msg.msg_controllen = cmsg->cmsg_len;
2495 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
2496 }
2497 return sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
2498 }
2499 #else /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2500 #ifndef _WIN32
2501 int
2502 rb_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 }
2507
2508 int
2509 rb_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 }
2514 #endif /* _WIN32 */
2515 #endif /* defined(HAVE_SENDMSG) && !defined(WIN32) */
2516
2517 int
2518 rb_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 }