]> jfr.im git - irc/rqf/shadowircd.git/blame - libratbox/src/commio.c
libratbox sync - r25796
[irc/rqf/shadowircd.git] / libratbox / src / commio.c
CommitLineData
b57f37fb
WP
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 *
4414eb3c 24 * $Id: commio.c 25795 2008-07-29 15:26:55Z androsyn $
b57f37fb
WP
25 */
26#include <libratbox_config.h>
27#include <ratbox_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
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()",
62 "Comm Error"
63};
64
65/* Highest FD and number of open FDs .. */
66static int number_fd = 0;
67static int rb_maxconnections = 0;
68
69static PF rb_connect_timeout;
70static PF rb_connect_tryconnect;
71#ifdef RB_IPV6
72static void mangle_mapped_sockaddr(struct sockaddr *in);
73#endif
74
75#ifndef HAVE_SOCKETPAIR
76static int rb_inet_socketpair(int d, int type, int protocol, int sv[2]);
77#endif
78
79static inline rb_fde_t *
80add_fd(int fd)
81{
82 rb_fde_t *F = rb_find_fd(fd);
b57f37fb
WP
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;
4414eb3c 90 rb_dlinkAdd(F, &F->node, &rb_fd_table[rb_hash_fd(fd)]);
b57f37fb
WP
91 return(F);
92}
93
94static inline void
95remove_fd(rb_fde_t *F)
96{
b57f37fb
WP
97 if(F == NULL || !IsFDOpen(F))
98 return;
99
4414eb3c 100 rb_dlinkMoveNode(&F->node, &rb_fd_table[rb_hash_fd(F->fd)], &closed_list);
b57f37fb
WP
101}
102
103static void
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;
111 rb_dlinkDelete(ptr, &closed_list);
112 rb_bh_free(fd_heap, F);
113 }
114}
115
116/* 32bit solaris is kinda slow and stdio only supports fds < 256
117 * so we got to do this crap below.
118 * (BTW Fuck you Sun, I hate your guts and I hope you go bankrupt soon)
119 */
120
121#if defined (__SVR4) && defined (__sun)
122static void
123rb_fd_hack(int *fd)
124{
125 int newfd;
126 if(*fd > 256 || *fd < 0)
127 return;
128 if((newfd = fcntl(*fd, F_DUPFD, 256)) != -1)
129 {
130 close(*fd);
131 *fd = newfd;
132 }
133 return;
134}
135#else
136#define rb_fd_hack(fd)
137#endif
138
139
140/* close_all_connections() can be used *before* the system come up! */
141
142static void
143rb_close_all(void)
144{
145 int i;
146#ifndef NDEBUG
147 int fd;
148#endif
149
150 /* XXX someone tell me why we care about 4 fd's ? */
151 /* XXX btw, fd 3 is used for profiler ! */
152 for (i = 4; i < rb_maxconnections; ++i)
153 {
154 close(i);
155 }
156
157 /* XXX should his hack be done in all cases? */
158#ifndef NDEBUG
159 /* fugly hack to reserve fd == 2 */
160 (void) close(2);
161 fd = open("stderr.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
162 if(fd >= 0)
163 {
164 dup2(fd, 2);
165 close(fd);
166 }
167#endif
168}
169
170/*
171 * get_sockerr - get the error value from the socket or the current errno
172 *
173 * Get the *real* error from the socket (well try to anyway..).
174 * This may only work when SO_DEBUG is enabled but its worth the
175 * gamble anyway.
176 */
177int
178rb_get_sockerr(rb_fde_t *F)
179{
180 int errtmp;
181 int err = 0;
182 rb_socklen_t len = sizeof(err);
183
184 if(!(F->type & RB_FD_SOCKET))
185 return errno;
186
187 rb_get_errno();
188 errtmp = errno;
189
190#ifdef SO_ERROR
191 if(F != NULL && !getsockopt(rb_get_fd(F), SOL_SOCKET, SO_ERROR, (char *) &err, (rb_socklen_t *) & len))
192 {
193 if(err)
194 errtmp = err;
195 }
196 errno = errtmp;
197#endif
198 return errtmp;
199}
200
201/*
202 * rb_getmaxconnect - return the max number of connections allowed
203 */
204int
205rb_getmaxconnect(void)
206{
207 return(rb_maxconnections);
208}
209
210/*
211 * set_sock_buffers - set send and receive buffers for socket
212 *
213 * inputs - fd file descriptor
214 * - size to set
215 * output - returns true (1) if successful, false (0) otherwise
216 * side effects -
217 */
218int
219rb_set_buffers(rb_fde_t *F, int size)
220{
221 if(F == NULL)
222 return 0;
223 if(setsockopt
224 (F->fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size))
225 || setsockopt(F->fd, SOL_SOCKET, SO_SNDBUF, (char *) &size, sizeof(size)))
226 return 0;
227 return 1;
228}
229
230/*
231 * set_non_blocking - Set the client connection into non-blocking mode.
232 *
233 * inputs - fd to set into non blocking mode
234 * output - 1 if successful 0 if not
235 * side effects - use POSIX compliant non blocking and
236 * be done with it.
237 */
238int
239rb_set_nb(rb_fde_t *F)
240{
241 int nonb = 0;
242 int res;
243 int fd;
244 if(F == NULL)
245 return 0;
246 fd = F->fd;
247
248 if((res = rb_setup_fd(F)))
249 return res;
250#ifdef O_NONBLOCK
251 nonb |= O_NONBLOCK;
252 res = fcntl(fd, F_GETFL, 0);
253 if(-1 == res || fcntl(fd, F_SETFL, res | nonb) == -1)
254 return 0;
255#else
256 nonb = 1;
257 res = 0;
258 if(ioctl(fd, FIONBIO, (char *)&nonb) == -1)
259 return 0;
260#endif
261
262 return 1;
263}
264
265/*
266 * rb_settimeout() - set the socket timeout
267 *
268 * Set the timeout for the fd
269 */
270void
271rb_settimeout(rb_fde_t *F, time_t timeout, PF * callback, void *cbdata)
272{
273 struct timeout_data *td;
274
275 if(F == NULL)
276 return;
277
278 lrb_assert(IsFDOpen(F));
279 td = F->timeout;
280 if(callback == NULL) /* user wants to remove */
281 {
282 if(td == NULL)
283 return;
284 rb_dlinkDelete(&td->node, &timeout_list);
285 rb_free(td);
286 F->timeout = NULL;
287 if(rb_dlink_list_length(&timeout_list) == 0)
288 {
289 rb_event_delete(rb_timeout_ev);
290 rb_timeout_ev = NULL;
291 }
292 return;
293 }
294
295 if(F->timeout == NULL)
296 td = F->timeout = rb_malloc(sizeof(struct timeout_data));
297
298 td->F = F;
299 td->timeout = rb_current_time() + timeout;
300 td->timeout_handler = callback;
301 td->timeout_data = cbdata;
302 rb_dlinkAdd(td, &td->node, &timeout_list);
303 if(rb_timeout_ev == NULL)
304 {
305 rb_timeout_ev = rb_event_add("rb_checktimeouts", rb_checktimeouts, NULL, 5);
306 }
307}
308
309/*
310 * rb_checktimeouts() - check the socket timeouts
311 *
312 * All this routine does is call the given callback/cbdata, without closing
313 * down the file descriptor. When close handlers have been implemented,
314 * this will happen.
315 */
316void
317rb_checktimeouts(void *notused)
318{
319 rb_dlink_node *ptr, *next;
320 struct timeout_data *td;
321 rb_fde_t *F;
322 PF *hdl;
323 void *data;
324
325 RB_DLINK_FOREACH_SAFE(ptr, next, timeout_list.head)
326 {
327 td = ptr->data;
328 F = td->F;
329 if(F == NULL || !IsFDOpen(F))
330 continue;
331
332 if(td->timeout < rb_current_time())
333 {
334 hdl = td->timeout_handler;
335 data = td->timeout_data;
336 rb_dlinkDelete(&td->node, &timeout_list);
337 F->timeout = NULL;
338 rb_free(td);
339 hdl(F, data);
340 }
341 }
342}
343
344static void
345rb_accept_tryaccept(rb_fde_t *F, void *data)
346{
347 struct rb_sockaddr_storage st;
348 rb_fde_t *new_F;
349 rb_socklen_t addrlen = sizeof(st);
350 int new_fd;
351
352 while(1)
353 {
354 new_fd = accept(F->fd, (struct sockaddr *)&st, &addrlen);
355 rb_get_errno();
356 if(new_fd < 0)
357 {
358 rb_setselect(F, RB_SELECT_ACCEPT, rb_accept_tryaccept, NULL);
359 return;
360 }
361
362 rb_fd_hack(&new_fd);
363
364 new_F = rb_open(new_fd, RB_FD_SOCKET, "Incoming Connection");
365
4414eb3c
VY
366 if(new_F == NULL)
367 {
368 rb_lib_log("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d\n", new_fd);
369 close(new_fd);
370 continue;
371 }
372
033be687 373 if(rb_unlikely(!rb_set_nb(new_F)))
b57f37fb
WP
374 {
375 rb_get_errno();
376 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F->fd);
377 rb_close(new_F);
378 }
379
380#ifdef RB_IPV6
381 mangle_mapped_sockaddr((struct sockaddr *)&st);
382#endif
383
384 if(F->accept->precb != NULL)
385 {
386 if(!F->accept->precb(new_F, (struct sockaddr *)&st, addrlen, F->accept->data)) /* pre-callback decided to drop it */
387 continue;
388 }
389#ifdef HAVE_SSL
390 if(F->type & RB_FD_SSL)
391 {
4414eb3c 392 rb_ssl_accept_setup(F, new_F, (struct sockaddr *)&st, addrlen);
b57f37fb
WP
393 }
394 else
395#endif /* HAVE_SSL */
396 {
397 F->accept->callback(new_F, RB_OK, (struct sockaddr *)&st, addrlen, F->accept->data);
398 }
399 }
400
401}
402
403/* try to accept a TCP connection */
404void
405rb_accept_tcp(rb_fde_t *F, ACPRE *precb, ACCB *callback, void *data)
406{
407 if(F == NULL)
408 return;
409 lrb_assert(callback);
410
411 F->accept = rb_malloc(sizeof(struct acceptdata));
412 F->accept->callback = callback;
413 F->accept->data = data;
414 F->accept->precb = precb;
415 rb_accept_tryaccept(F, NULL);
416}
417
418/*
419 * void rb_connect_tcp(int fd, struct sockaddr *dest,
420 * struct sockaddr *clocal, int socklen,
421 * CNCB *callback, void *data, int timeout)
422 * Input: An fd to connect with, a host and port to connect to,
423 * a local sockaddr to connect from + length(or NULL to use the
424 * default), a callback, the data to pass into the callback, the
425 * address family.
426 * Output: None.
427 * Side-effects: A non-blocking connection to the host is started, and
428 * if necessary, set up for selection. The callback given
429 * may be called now, or it may be called later.
430 */
431void
432rb_connect_tcp(rb_fde_t *F, struct sockaddr *dest,
433 struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
434{
435 if(F == NULL)
436 return;
437
438 lrb_assert(callback);
439 F->connect = rb_malloc(sizeof(struct conndata));
440 F->connect->callback = callback;
441 F->connect->data = data;
442
443 memcpy(&F->connect->hostaddr, dest, sizeof(F->connect->hostaddr));
444
445 /* Note that we're using a passed sockaddr here. This is because
446 * generally you'll be bind()ing to a sockaddr grabbed from
447 * getsockname(), so this makes things easier.
448 * XXX If NULL is passed as local, we should later on bind() to the
449 * virtual host IP, for completeness.
450 * -- adrian
451 */
452 if((clocal != NULL) && (bind(F->fd, clocal, socklen) < 0))
453 {
454 /* Failure, call the callback with RB_ERR_BIND */
455 rb_connect_callback(F, RB_ERR_BIND);
456 /* ... and quit */
457 return;
458 }
459
460 /* We have a valid IP, so we just call tryconnect */
461 /* Make sure we actually set the timeout here .. */
462 rb_settimeout(F, timeout, rb_connect_timeout, NULL);
463 rb_connect_tryconnect(F, NULL);
464}
465
466
467/*
468 * rb_connect_callback() - call the callback, and continue with life
469 */
470void
471rb_connect_callback(rb_fde_t *F, int status)
472{
473 CNCB *hdl;
474 void *data;
9b4f3c47 475 int errtmp = errno; /* save errno as rb_settimeout clobbers it sometimes */
b57f37fb
WP
476
477 /* This check is gross..but probably necessary */
478 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
479 return;
480 /* Clear the connect flag + handler */
481 hdl = F->connect->callback;
482 data = F->connect->data;
483 F->connect->callback = NULL;
484
9b4f3c47 485
b57f37fb
WP
486 /* Clear the timeout handler */
487 rb_settimeout(F, 0, NULL, NULL);
9b4f3c47 488 errno = errtmp;
b57f37fb
WP
489 /* Call the handler */
490 hdl(F, status, data);
491}
492
493
494/*
495 * rb_connect_timeout() - this gets called when the socket connection
496 * times out. This *only* can be called once connect() is initially
497 * called ..
498 */
499static void
500rb_connect_timeout(rb_fde_t *F, void *notused)
501{
502 /* error! */
503 rb_connect_callback(F, RB_ERR_TIMEOUT);
504}
505
506/* static void rb_connect_tryconnect(int fd, void *notused)
507 * Input: The fd, the handler data(unused).
508 * Output: None.
509 * Side-effects: Try and connect with pending connect data for the FD. If
510 * we succeed or get a fatal error, call the callback.
511 * Otherwise, it is still blocking or something, so register
512 * to select for a write event on this FD.
513 */
514static void
515rb_connect_tryconnect(rb_fde_t *F, void *notused)
516{
517 int retval;
518
519 if(F == NULL || F->connect == NULL || F->connect->callback == NULL)
520 return;
521 /* Try the connect() */
522 retval = connect(F->fd,
523 (struct sockaddr *) &F->connect->hostaddr, GET_SS_LEN(&F->connect->hostaddr));
524 /* Error? */
525 if(retval < 0)
526 {
527 /*
528 * If we get EISCONN, then we've already connect()ed the socket,
529 * which is a good thing.
530 * -- adrian
531 */
532 rb_get_errno();
533 if(errno == EISCONN)
534 rb_connect_callback(F, RB_OK);
535 else if(rb_ignore_errno(errno))
536 /* Ignore error? Reschedule */
537 rb_setselect(F, RB_SELECT_CONNECT,
538 rb_connect_tryconnect, NULL);
539 else
540 /* Error? Fail with RB_ERR_CONNECT */
541 rb_connect_callback(F, RB_ERR_CONNECT);
542 return;
543 }
544 /* If we get here, we've suceeded, so call with RB_OK */
545 rb_connect_callback(F, RB_OK);
546}
547
548
549int
550rb_connect_sockaddr(rb_fde_t *F, struct sockaddr *addr, int len)
551{
552 if(F == NULL)
553 return 0;
554
555 memcpy(addr, &F->connect->hostaddr, len);
556 return 1;
557}
558
559/*
560 * rb_error_str() - return an error string for the given error condition
561 */
562const char *
563rb_errstr(int error)
564{
565 if(error < 0 || error >= RB_ERR_MAX)
566 return "Invalid error number!";
567 return rb_err_str[error];
568}
569
570
571int
572rb_socketpair(int family, int sock_type, int proto, rb_fde_t **F1, rb_fde_t **F2, const char *note)
573{
574 int nfd[2];
575 if(number_fd >= rb_maxconnections)
576 {
577 errno = ENFILE;
578 return -1;
579 }
580
581#ifndef WIN32
582 if(socketpair(family, sock_type, proto, nfd))
583#else
584 if(rb_inet_socketpair(AF_INET, SOCK_STREAM, proto, nfd))
585#endif
586 return -1;
587
588 rb_fd_hack(&nfd[0]);
589 rb_fd_hack(&nfd[1]);
590
591 *F1 = rb_open(nfd[0], RB_FD_SOCKET, note);
592 *F2 = rb_open(nfd[1], RB_FD_SOCKET, note);
593
594 if(*F1 == NULL)
595 {
596 if(*F2 != NULL)
597 rb_close(*F2);
598 return -1;
599 }
600
601 if(*F2 == NULL)
602 {
603 rb_close(*F1);
604 return -1;
605 }
606
607 /* Set the socket non-blocking, and other wonderful bits */
033be687 608 if(rb_unlikely(!rb_set_nb(*F1)))
b57f37fb
WP
609 {
610 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[0], strerror(errno));
611 rb_close(*F1);
612 rb_close(*F2);
613 return -1;
614 }
615
033be687 616 if(rb_unlikely(!rb_set_nb(*F2)))
b57f37fb
WP
617 {
618 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd[1], strerror(errno));
619 rb_close(*F1);
620 rb_close(*F2);
621 return -1;
622 }
623
624 return 0;
625}
626
627
628int
629rb_pipe(rb_fde_t **F1, rb_fde_t **F2, const char *desc)
630{
631#ifndef WIN32
632 int fd[2];
633 if(number_fd >= rb_maxconnections)
634 {
635 errno = ENFILE;
636 return -1;
637 }
638 if(pipe(fd) == -1)
639 return -1;
640 rb_fd_hack(&fd[0]);
641 rb_fd_hack(&fd[1]);
642 *F1 = rb_open(fd[0], RB_FD_PIPE, desc);
643 *F2 = rb_open(fd[1], RB_FD_PIPE, desc);
644
033be687 645 if(rb_unlikely(!rb_set_nb(*F1)))
b57f37fb
WP
646 {
647 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[0], strerror(errno));
648 rb_close(*F1);
649 rb_close(*F2);
650 return -1;
651 }
652
033be687 653 if(rb_unlikely(!rb_set_nb(*F2)))
b57f37fb
WP
654 {
655 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd[1], strerror(errno));
656 rb_close(*F1);
657 rb_close(*F2);
658 return -1;
659 }
660
661
662 return 0;
663#else
664 /* Its not a pipe..but its selectable. I'll take dirty hacks
665 * for $500 Alex.
666 */
667 return rb_socketpair(AF_INET, SOCK_STREAM, 0, F1, F2, desc);
668#endif
669}
670
671/*
672 * rb_socket() - open a socket
673 *
674 * This is a highly highly cut down version of squid's rb_open() which
675 * for the most part emulates socket(), *EXCEPT* it fails if we're about
676 * to run out of file descriptors.
677 */
678rb_fde_t *
679rb_socket(int family, int sock_type, int proto, const char *note)
680{
681 rb_fde_t *F;
682 int fd;
683 /* First, make sure we aren't going to run out of file descriptors */
033be687 684 if(rb_unlikely(number_fd >= rb_maxconnections))
b57f37fb
WP
685 {
686 errno = ENFILE;
687 return NULL;
688 }
689
690 /*
691 * Next, we try to open the socket. We *should* drop the reserved FD
692 * limit if/when we get an error, but we can deal with that later.
693 * XXX !!! -- adrian
694 */
695 fd = socket(family, sock_type, proto);
696 rb_fd_hack(&fd);
033be687 697 if(rb_unlikely(fd < 0))
b57f37fb
WP
698 return NULL; /* errno will be passed through, yay.. */
699
700#if defined(RB_IPV6) && defined(IPV6_V6ONLY)
701 /*
702 * Make sure we can take both IPv4 and IPv6 connections
703 * on an AF_INET6 socket
704 */
705 if(family == AF_INET6)
706 {
707 int off = 1;
708 if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) == -1)
709 {
710 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to 1 on FD %d: %s",
711 fd, strerror(errno));
712 close(fd);
713 return NULL;
714 }
715 }
716#endif
717
718 F = rb_open(fd, RB_FD_SOCKET, note);
719 if(F == NULL)
4414eb3c
VY
720 {
721 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd, strerror(errno));
722 close(fd);
b57f37fb 723 return NULL;
4414eb3c 724 }
b57f37fb 725 /* Set the socket non-blocking, and other wonderful bits */
033be687 726 if(rb_unlikely(!rb_set_nb(F)))
b57f37fb
WP
727 {
728 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd, strerror(errno));
729 rb_close(F);
730 return NULL;
731 }
732
733 return F;
734}
735
736/*
737 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
738 * socket manged the sockaddr.
739 */
740#ifdef RB_IPV6
741static void
742mangle_mapped_sockaddr(struct sockaddr *in)
743{
744 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) in;
745
746 if(in->sa_family == AF_INET)
747 return;
748
749 if(in->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr))
750 {
751 struct sockaddr_in in4;
752 memset(&in4, 0, sizeof(struct sockaddr_in));
753 in4.sin_family = AF_INET;
754 in4.sin_port = in6->sin6_port;
4414eb3c 755 in4.sin_addr.s_addr = ((uint32_t *) & in6->sin6_addr)[3];
b57f37fb
WP
756 memcpy(in, &in4, sizeof(struct sockaddr_in));
757 }
758 return;
759}
760#endif
761
762/*
763 * rb_listen() - listen on a port
764 */
765int
766rb_listen(rb_fde_t *F, int backlog)
767{
768 F->type = RB_FD_SOCKET|RB_FD_LISTEN;
769 /* Currently just a simple wrapper for the sake of being complete */
770 return listen(F->fd, backlog);
771}
772
773void
774rb_fdlist_init(int closeall, int maxfds, size_t heapsize)
775{
776 static int initialized = 0;
777#ifdef WIN32
778 WSADATA wsaData;
779 int err;
780 int vers = MAKEWORD(2, 0);
781
782 err = WSAStartup(vers, &wsaData);
783 if(err != 0)
784 {
785 rb_lib_die("WSAStartup failed");
786 }
787
788#endif
789 if(!initialized)
790 {
791 rb_maxconnections = maxfds;
792 if(closeall)
793 rb_close_all();
794 /* Since we're doing this once .. */
795 initialized = 1;
796 }
797 fd_heap = rb_bh_create(sizeof(rb_fde_t), heapsize, "librb_fd_heap");
798
799}
800
801
802/* Called to open a given filedescriptor */
803rb_fde_t *
4414eb3c 804rb_open(int fd, uint8_t type, const char *desc)
b57f37fb 805{
4414eb3c 806 rb_fde_t *F;
b57f37fb
WP
807 lrb_assert(fd >= 0);
808
4414eb3c
VY
809 F = add_fd(fd);
810
811 lrb_assert(!IsFDOpen(F));
033be687 812 if(rb_unlikely(IsFDOpen(F)))
b57f37fb 813 {
4414eb3c
VY
814 const char *fdesc;
815 if(F != NULL && F->desc != NULL)
816 fdesc = F->desc;
817 else
818 fdesc = "NULL";
819 rb_lib_log("Trying to rb_open an already open FD: %d desc: %d", fd, fdesc);
b57f37fb
WP
820 return NULL;
821 }
b57f37fb
WP
822 F->fd = fd;
823 F->type = type;
824 SetFDOpen(F);
825
826 if(desc != NULL)
827 F->desc = rb_strndup(desc, FD_DESC_SZ);
828 number_fd++;
829 return F;
830}
831
832
833/* Called to close a given filedescriptor */
834void
835rb_close(rb_fde_t *F)
836{
837 int type, fd;
838
839 if(F == NULL)
840 return;
841
842 fd = F->fd;
843 type = F->type;
844 lrb_assert(IsFDOpen(F));
845
846 lrb_assert(!(type & RB_FD_FILE));
033be687 847 if(rb_unlikely(type & RB_FD_FILE))
b57f37fb
WP
848 {
849 lrb_assert(F->read_handler == NULL);
850 lrb_assert(F->write_handler == NULL);
851 }
852 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
853 rb_settimeout(F, 0, NULL, NULL);
854 rb_free(F->accept);
855 rb_free(F->connect);
856 rb_free(F->desc);
857#ifdef HAVE_SSL
858 if(type & RB_FD_SSL)
859 {
860 rb_ssl_shutdown(F);
861 }
862#endif /* HAVE_SSL */
863 if(IsFDOpen(F))
864 {
865 remove_fd(F);
866 ClearFDOpen(F);
867 }
868
869 number_fd--;
870
871#ifdef WIN32
872 if(type & (RB_FD_SOCKET|RB_FD_PIPE))
873 {
874 closesocket(fd);
875 return;
876 } else
877#endif
878 close(fd);
879}
880
881
882/*
883 * rb_dump_fd() - dump the list of active filedescriptors
884 */
885void
886rb_dump_fd(DUMPCB * cb, void *data)
887{
888 static const char *empty = "";
889 rb_dlink_node *ptr;
890 rb_dlink_list *bucket;
891 rb_fde_t *F;
892 unsigned int i;
893
894 for(i = 0; i < RB_FD_HASH_SIZE; i++)
895 {
896 bucket = &rb_fd_table[i];
897
898 if(rb_dlink_list_length(bucket) <= 0)
899 continue;
900
901 RB_DLINK_FOREACH(ptr, bucket->head)
902 {
903 F = ptr->data;
904 if(F == NULL || !IsFDOpen(F))
905 continue;
906
907 cb(F->fd, F->desc ? F->desc : empty, data);
908 }
909 }
910}
911
912/*
913 * rb_note() - set the fd note
914 *
915 * Note: must be careful not to overflow rb_fd_table[fd].desc when
916 * calling.
917 */
918void
919rb_note(rb_fde_t *F, const char *string)
920{
921 if(F == NULL)
922 return;
923
924 rb_free(F->desc);
925 F->desc = rb_strndup(string, FD_DESC_SZ);
926}
927
928void
4414eb3c 929rb_set_type(rb_fde_t *F, uint8_t type)
b57f37fb
WP
930{
931 /* if the caller is calling this, lets assume they have a clue */
932 F->type = type;
933 return;
934}
935
4414eb3c 936uint8_t
b57f37fb
WP
937rb_get_type(rb_fde_t *F)
938{
939 return F->type;
940}
941
942int
943rb_fd_ssl(rb_fde_t *F)
944{
945 if(F == NULL)
946 return 0;
947 if(F->type & RB_FD_SSL)
948 return 1;
949 return 0;
950}
951
952int
953rb_get_fd(rb_fde_t *F)
954{
955 if(F == NULL)
956 return -1;
957 return(F->fd);
958}
959
960rb_fde_t *
961rb_get_fde(int fd)
962{
963 return rb_find_fd(fd);
964}
965
966ssize_t
967rb_read(rb_fde_t *F, void *buf, int count)
968{
ec9738cb 969 ssize_t ret;
b57f37fb
WP
970 if(F == NULL)
971 return 0;
972
973 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
974 * an SSL socket as a regular socket
975 */
976#ifdef HAVE_SSL
977 if(F->type & RB_FD_SSL)
978 {
979 return rb_ssl_read(F, buf, count);
980 }
981#endif
982 if(F->type & RB_FD_SOCKET)
983 {
984 ret = recv(F->fd, buf, count, 0);
985 if(ret < 0)
986 {
987 rb_get_errno();
988 }
989 return ret;
990 }
991
992
993 /* default case */
994 return read(F->fd, buf, count);
995}
996
997
998ssize_t
999rb_write(rb_fde_t *F, const void *buf, int count)
1000{
ec9738cb 1001 ssize_t ret;
b57f37fb
WP
1002 if(F == NULL)
1003 return 0;
1004
1005#ifdef HAVE_SSL
1006 if(F->type & RB_FD_SSL)
1007 {
1008 return rb_ssl_write(F, buf, count);
1009 }
1010#endif
1011 if(F->type & RB_FD_SOCKET)
1012 {
1013 ret = send(F->fd, buf, count, MSG_NOSIGNAL);
1014 if(ret < 0) {
1015 rb_get_errno();
1016 }
1017 return ret;
1018 }
1019
1020 return write(F->fd, buf, count);
1021}
1022
1023#if defined(HAVE_SSL) || defined(WIN32) || !defined(HAVE_WRITEV)
1024static ssize_t
1025rb_fake_writev(rb_fde_t *F, const struct rb_iovec *vp, size_t vpcount)
1026{
ec9738cb 1027 ssize_t count = 0;
b57f37fb
WP
1028
1029 while (vpcount-- > 0)
1030 {
ec9738cb 1031 ssize_t written = rb_write(F, vp->iov_base, vp->iov_len);
b57f37fb
WP
1032
1033 if (written <= 0)
1034 {
1035 if(count > 0)
1036 return count;
1037 else
1038 return written;
1039 }
1040 count += written;
1041 vp++;
1042 }
1043 return (count);
1044}
1045#endif
1046
1047#if defined(WIN32) || !defined(HAVE_WRITEV)
1048ssize_t
1049rb_writev(rb_fde_t *F, struct rb_iovec *vecount, int count)
1050{
1051 return rb_fake_writev(F, vecount, count);
1052}
1053
1054#else
1055ssize_t
1056rb_writev(rb_fde_t *F, struct rb_iovec *vector, int count)
1057{
1058 if(F == NULL) {
1059 errno = EBADF;
1060 return -1;
1061 }
1062#ifdef HAVE_SSL
1063 if(F->type & RB_FD_SSL)
1064 {
1065 return rb_fake_writev(F, vector, count);
1066 }
1067#endif /* HAVE_SSL */
1068#ifdef HAVE_SENDMSG
1069 if(F->type & RB_FD_SOCKET)
1070 {
1071 struct msghdr msg;
1072 memset(&msg, 0, sizeof(msg));
1073 msg.msg_iov = (struct iovec *)vector;
1074 msg.msg_iovlen = count;
1075 return sendmsg(F->fd, &msg, MSG_NOSIGNAL);
1076 }
1077#endif /* HAVE_SENDMSG */
1078 return writev(F->fd, (struct iovec *)vector, count);
1079
1080}
1081#endif
1082
1083
1084/*
1085 * From: Thomas Helvey <tomh@inxpress.net>
1086 */
1087static const char *IpQuadTab[] = {
1088 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1089 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1090 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1091 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1092 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1093 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1094 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1095 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1096 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1097 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1098 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1099 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1100 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1101 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1102 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1103 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1104 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1105 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1106 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1107 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1108 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1109 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1110 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1111 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1112 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1113 "250", "251", "252", "253", "254", "255"
1114};
1115
1116/*
1117 * inetntoa - in_addr to string
1118 * changed name to remove collision possibility and
1119 * so behaviour is guaranteed to take a pointer arg.
1120 * -avalon 23/11/92
1121 * inet_ntoa -- returned the dotted notation of a given
1122 * internet number
1123 * argv 11/90).
1124 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1125 */
1126
1127static const char *
1128inetntoa(const char *in)
1129{
1130 static char buf[16];
1131 char *bufptr = buf;
1132 const unsigned char *a = (const unsigned char *) in;
1133 const char *n;
1134
1135 n = IpQuadTab[*a++];
1136 while (*n)
1137 *bufptr++ = *n++;
1138 *bufptr++ = '.';
1139 n = IpQuadTab[*a++];
1140 while (*n)
1141 *bufptr++ = *n++;
1142 *bufptr++ = '.';
1143 n = IpQuadTab[*a++];
1144 while (*n)
1145 *bufptr++ = *n++;
1146 *bufptr++ = '.';
1147 n = IpQuadTab[*a];
1148 while (*n)
1149 *bufptr++ = *n++;
1150 *bufptr = '\0';
1151 return buf;
1152}
1153
1154
1155/*
1156 * Copyright (c) 1996-1999 by Internet Software Consortium.
1157 *
1158 * Permission to use, copy, modify, and distribute this software for any
1159 * purpose with or without fee is hereby granted, provided that the above
1160 * copyright notice and this permission notice appear in all copies.
1161 *
1162 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
1163 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1164 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
1165 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1166 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1167 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1168 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1169 * SOFTWARE.
1170 */
1171
1172#define SPRINTF(x) ((size_t)rb_sprintf x)
1173
1174/*
1175 * WARNING: Don't even consider trying to compile this on a system where
1176 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1177 */
1178
1179static const char *inet_ntop4(const unsigned char * src, char *dst, unsigned int size);
1180#ifdef RB_IPV6
1181static const char *inet_ntop6(const unsigned char * src, char *dst, unsigned int size);
1182#endif
1183
1184/* const char *
1185 * inet_ntop4(src, dst, size)
1186 * format an IPv4 address
1187 * return:
1188 * `dst' (as a const)
1189 * notes:
1190 * (1) uses no statics
1191 * (2) takes a unsigned char* not an in_addr as input
1192 * author:
1193 * Paul Vixie, 1996.
1194 */
1195static const char *
1196inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
1197{
1198 if(size < 16)
1199 return NULL;
1200 return strcpy(dst, inetntoa((const char *) src));
1201}
1202
1203/* const char *
1204 * inet_ntop6(src, dst, size)
1205 * convert IPv6 binary address into presentation (printable) format
1206 * author:
1207 * Paul Vixie, 1996.
1208 */
1209#ifdef RB_IPV6
1210static const char *
1211inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
1212{
1213 /*
1214 * Note that int32_t and int16_t need only be "at least" large enough
1215 * to contain a value of the specified size. On some systems, like
1216 * Crays, there is no such thing as an integer variable with 16 bits.
1217 * Keep this in mind if you think this function should have been coded
1218 * to use pointer overlays. All the world's not a VAX.
1219 */
1220 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
1221 struct
1222 {
1223 int base, len;
1224 }
1225 best, cur;
1226 unsigned int words[IN6ADDRSZ / INT16SZ];
1227 int i;
1228
1229 /*
1230 * Preprocess:
1231 * Copy the input (bytewise) array into a wordwise array.
1232 * Find the longest run of 0x00's in src[] for :: shorthanding.
1233 */
1234 memset(words, '\0', sizeof words);
1235 for (i = 0; i < IN6ADDRSZ; i += 2)
1236 words[i / 2] = (src[i] << 8) | src[i + 1];
1237 best.base = -1;
1238 best.len = 0;
1239 cur.base = -1;
1240 cur.len = 0;
1241 for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
1242 {
1243 if(words[i] == 0)
1244 {
1245 if(cur.base == -1)
1246 cur.base = i, cur.len = 1;
1247 else
1248 cur.len++;
1249 }
1250 else
1251 {
1252 if(cur.base != -1)
1253 {
1254 if(best.base == -1 || cur.len > best.len)
1255 best = cur;
1256 cur.base = -1;
1257 }
1258 }
1259 }
1260 if(cur.base != -1)
1261 {
1262 if(best.base == -1 || cur.len > best.len)
1263 best = cur;
1264 }
1265 if(best.base != -1 && best.len < 2)
1266 best.base = -1;
1267
1268 /*
1269 * Format the result.
1270 */
1271 tp = tmp;
1272 for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
1273 {
1274 /* Are we inside the best run of 0x00's? */
1275 if(best.base != -1 && i >= best.base && i < (best.base + best.len))
1276 {
1277 if(i == best.base)
1278 {
1279 if(i == 0)
1280 *tp++ = '0';
1281 *tp++ = ':';
1282 }
1283 continue;
1284 }
1285 /* Are we following an initial run of 0x00s or any real hex? */
1286 if(i != 0)
1287 *tp++ = ':';
1288 /* Is this address an encapsulated IPv4? */
1289 if(i == 6 && best.base == 0 &&
1290 (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
1291 {
1292 if(!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
1293 return (NULL);
1294 tp += strlen(tp);
1295 break;
1296 }
1297 tp += SPRINTF((tp, "%x", words[i]));
1298 }
1299 /* Was it a trailing run of 0x00's? */
1300 if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
1301 *tp++ = ':';
1302 *tp++ = '\0';
1303
1304 /*
1305 * Check for overflow, copy, and we're done.
1306 */
1307
1308 if((unsigned int) (tp - tmp) > size)
1309 {
1310 return (NULL);
1311 }
1312 return strcpy(dst, tmp);
1313}
1314#endif
1315
1316int
1317rb_inet_pton_sock(const char *src, struct sockaddr *dst)
1318{
1319 if(rb_inet_pton(AF_INET, src, &((struct sockaddr_in *) dst)->sin_addr))
1320 {
1321 ((struct sockaddr_in *) dst)->sin_port = 0;
1322 ((struct sockaddr_in *) dst)->sin_family = AF_INET;
1323 SET_SS_LEN(dst, sizeof(struct sockaddr_in));
1324 return 1;
1325 }
1326#ifdef RB_IPV6
1327 else if(rb_inet_pton(AF_INET6, src, &((struct sockaddr_in6 *) dst)->sin6_addr))
1328 {
1329 ((struct sockaddr_in6 *) dst)->sin6_port = 0;
1330 ((struct sockaddr_in6 *) dst)->sin6_family = AF_INET6;
1331 SET_SS_LEN(dst, sizeof(struct sockaddr_in6));
1332 return 1;
1333 }
1334#endif
1335 return 0;
1336}
1337
1338const char *
1339rb_inet_ntop_sock(struct sockaddr *src, char *dst, unsigned int size)
1340{
1341 switch (src->sa_family)
1342 {
1343 case AF_INET:
1344 return (rb_inet_ntop(AF_INET, &((struct sockaddr_in *) src)->sin_addr, dst, size));
1345 break;
1346#ifdef RB_IPV6
1347 case AF_INET6:
1348 return (rb_inet_ntop(AF_INET6, &((struct sockaddr_in6 *) src)->sin6_addr, dst, size));
1349 break;
1350#endif
1351 default:
1352 return NULL;
1353 break;
1354 }
1355}
1356
1357/* char *
1358 * rb_inet_ntop(af, src, dst, size)
1359 * convert a network format address to presentation format.
1360 * return:
1361 * pointer to presentation format address (`dst'), or NULL (see errno).
1362 * author:
1363 * Paul Vixie, 1996.
1364 */
1365const char *
1366rb_inet_ntop(int af, const void *src, char *dst, unsigned int size)
1367{
1368 switch (af)
1369 {
1370 case AF_INET:
1371 return (inet_ntop4(src, dst, size));
1372#ifdef RB_IPV6
1373 case AF_INET6:
1374 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *) src) ||
1375 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *) src))
1376 return (inet_ntop4
1377 ((const unsigned char *)
1378 &((const struct in6_addr *) src)->s6_addr[12], dst, size));
1379 else
1380 return (inet_ntop6(src, dst, size));
1381
1382
1383#endif
1384 default:
1385 return (NULL);
1386 }
1387 /* NOTREACHED */
1388}
1389
1390/*
1391 * WARNING: Don't even consider trying to compile this on a system where
1392 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1393 */
1394
1395/* int
1396 * rb_inet_pton(af, src, dst)
1397 * convert from presentation format (which usually means ASCII printable)
1398 * to network format (which is usually some kind of binary format).
1399 * return:
1400 * 1 if the address was valid for the specified address family
1401 * 0 if the address wasn't valid (`dst' is untouched in this case)
1402 * -1 if some other error occurred (`dst' is untouched in this case, too)
1403 * author:
1404 * Paul Vixie, 1996.
1405 */
1406
1407/* int
1408 * inet_pton4(src, dst)
1409 * like inet_aton() but without all the hexadecimal and shorthand.
1410 * return:
1411 * 1 if `src' is a valid dotted quad, else 0.
1412 * notice:
1413 * does not touch `dst' unless it's returning 1.
1414 * author:
1415 * Paul Vixie, 1996.
1416 */
1417static int
1418inet_pton4(const char *src, unsigned char *dst)
1419{
1420 int saw_digit, octets, ch;
1421 unsigned char tmp[INADDRSZ], *tp;
1422
1423 saw_digit = 0;
1424 octets = 0;
1425 *(tp = tmp) = 0;
1426 while ((ch = *src++) != '\0')
1427 {
1428
1429 if(ch >= '0' && ch <= '9')
1430 {
1431 unsigned int new = *tp * 10 + (ch - '0');
1432
1433 if(new > 255)
1434 return (0);
1435 *tp = new;
1436 if(!saw_digit)
1437 {
1438 if(++octets > 4)
1439 return (0);
1440 saw_digit = 1;
1441 }
1442 }
1443 else if(ch == '.' && saw_digit)
1444 {
1445 if(octets == 4)
1446 return (0);
1447 *++tp = 0;
1448 saw_digit = 0;
1449 }
1450 else
1451 return (0);
1452 }
1453 if(octets < 4)
1454 return (0);
1455 memcpy(dst, tmp, INADDRSZ);
1456 return (1);
1457}
1458
1459#ifdef RB_IPV6
1460/* int
1461 * inet_pton6(src, dst)
1462 * convert presentation level address to network order binary form.
1463 * return:
1464 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1465 * notice:
1466 * (1) does not touch `dst' unless it's returning 1.
1467 * (2) :: in a full address is silently ignored.
1468 * credit:
1469 * inspired by Mark Andrews.
1470 * author:
1471 * Paul Vixie, 1996.
1472 */
1473
1474static int
1475inet_pton6(const char *src, unsigned char *dst)
1476{
1477 static const char xdigits[] = "0123456789abcdef";
1478 unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
1479 const char *curtok;
1480 int ch, saw_xdigit;
1481 unsigned int val;
1482
1483 tp = memset(tmp, '\0', IN6ADDRSZ);
1484 endp = tp + IN6ADDRSZ;
1485 colonp = NULL;
1486 /* Leading :: requires some special handling. */
1487 if(*src == ':')
1488 if(*++src != ':')
1489 return (0);
1490 curtok = src;
1491 saw_xdigit = 0;
1492 val = 0;
1493 while ((ch = tolower(*src++)) != '\0')
1494 {
1495 const char *pch;
1496
1497 pch = strchr(xdigits, ch);
1498 if(pch != NULL)
1499 {
1500 val <<= 4;
1501 val |= (pch - xdigits);
1502 if(val > 0xffff)
1503 return (0);
1504 saw_xdigit = 1;
1505 continue;
1506 }
1507 if(ch == ':')
1508 {
1509 curtok = src;
1510 if(!saw_xdigit)
1511 {
1512 if(colonp)
1513 return (0);
1514 colonp = tp;
1515 continue;
1516 }
1517 else if(*src == '\0')
1518 {
1519 return (0);
1520 }
1521 if(tp + INT16SZ > endp)
1522 return (0);
1523 *tp++ = (unsigned char) (val >> 8) & 0xff;
1524 *tp++ = (unsigned char) val & 0xff;
1525 saw_xdigit = 0;
1526 val = 0;
1527 continue;
1528 }
1529 if(*src != '\0' && ch == '.')
1530 {
1531 if(((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
1532 {
1533 tp += INADDRSZ;
1534 saw_xdigit = 0;
1535 break; /* '\0' was seen by inet_pton4(). */
1536 }
1537 }
1538 else
1539 continue;
1540 return (0);
1541 }
1542 if(saw_xdigit)
1543 {
1544 if(tp + INT16SZ > endp)
1545 return (0);
1546 *tp++ = (unsigned char) (val >> 8) & 0xff;
1547 *tp++ = (unsigned char) val & 0xff;
1548 }
1549 if(colonp != NULL)
1550 {
1551 /*
1552 * Since some memmove()'s erroneously fail to handle
1553 * overlapping regions, we'll do the shift by hand.
1554 */
1555 const int n = tp - colonp;
1556 int i;
1557
1558 if(tp == endp)
1559 return (0);
1560 for (i = 1; i <= n; i++)
1561 {
1562 endp[-i] = colonp[n - i];
1563 colonp[n - i] = 0;
1564 }
1565 tp = endp;
1566 }
1567 if(tp != endp)
1568 return (0);
1569 memcpy(dst, tmp, IN6ADDRSZ);
1570 return (1);
1571}
1572#endif
1573int
1574rb_inet_pton(int af, const char *src, void *dst)
1575{
1576 switch (af)
1577 {
1578 case AF_INET:
1579 return (inet_pton4(src, dst));
1580#ifdef RB_IPV6
1581 case AF_INET6:
1582 /* Somebody might have passed as an IPv4 address this is sick but it works */
1583 if(inet_pton4(src, dst))
1584 {
1585 char tmp[HOSTIPLEN];
1586 rb_sprintf(tmp, "::ffff:%s", src);
1587 return (inet_pton6(tmp, dst));
1588 }
1589 else
1590 return (inet_pton6(src, dst));
1591#endif
1592 default:
1593 return (-1);
1594 }
1595 /* NOTREACHED */
1596}
1597
1598
1599#ifndef HAVE_SOCKETPAIR
1600int
1601rb_inet_socketpair(int family, int type, int protocol, int fd[2])
1602{
1603 int listener = -1;
1604 int connector = -1;
1605 int acceptor = -1;
1606 struct sockaddr_in listen_addr;
1607 struct sockaddr_in connect_addr;
1608 size_t size;
1609
1610 if(protocol || family != AF_INET)
1611 {
1612 errno = EAFNOSUPPORT;
1613 return -1;
1614 }
1615 if(!fd)
1616 {
1617 errno = EINVAL;
1618 return -1;
1619 }
1620
1621 listener = socket(AF_INET, type, 0);
1622 if(listener == -1)
1623 return -1;
1624 memset(&listen_addr, 0, sizeof(listen_addr));
1625 listen_addr.sin_family = AF_INET;
1626 listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1627 listen_addr.sin_port = 0; /* kernel choses port. */
1628 if(bind(listener, (struct sockaddr *) &listen_addr, sizeof(listen_addr)) == -1)
1629 goto tidy_up_and_fail;
1630 if(listen(listener, 1) == -1)
1631 goto tidy_up_and_fail;
1632
1633 connector = socket(AF_INET, type, 0);
1634 if(connector == -1)
1635 goto tidy_up_and_fail;
1636 /* We want to find out the port number to connect to. */
1637 size = sizeof(connect_addr);
1638 if(getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
1639 goto tidy_up_and_fail;
1640 if(size != sizeof(connect_addr))
1641 goto abort_tidy_up_and_fail;
1642 if(connect(connector, (struct sockaddr *) &connect_addr, sizeof(connect_addr)) == -1)
1643 goto tidy_up_and_fail;
1644
1645 size = sizeof(listen_addr);
1646 acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
1647 if(acceptor == -1)
1648 goto tidy_up_and_fail;
1649 if(size != sizeof(listen_addr))
1650 goto abort_tidy_up_and_fail;
1651 close(listener);
1652 /* Now check we are talking to ourself by matching port and host on the
1653 two sockets. */
1654 if(getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
1655 goto tidy_up_and_fail;
1656 if(size != sizeof(connect_addr)
1657 || listen_addr.sin_family != connect_addr.sin_family
1658 || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
1659 || listen_addr.sin_port != connect_addr.sin_port)
1660 {
1661 goto abort_tidy_up_and_fail;
1662 }
1663 fd[0] = connector;
1664 fd[1] = acceptor;
1665 return 0;
1666
1667 abort_tidy_up_and_fail:
1668 errno = EINVAL; /* I hope this is portable and appropriate. */
1669
1670 tidy_up_and_fail:
1671 {
1672 int save_errno = errno;
1673 if(listener != -1)
1674 close(listener);
1675 if(connector != -1)
1676 close(connector);
1677 if(acceptor != -1)
1678 close(acceptor);
1679 errno = save_errno;
1680 return -1;
1681 }
1682}
1683
1684#endif
1685
1686
1687static void (*setselect_handler) (rb_fde_t *, unsigned int, PF *, void *);
1688static int (*select_handler) (long);
1689static int (*setup_fd_handler) (rb_fde_t *);
1690static int (*io_sched_event) (struct ev_entry *, int);
1691static void (*io_unsched_event) (struct ev_entry *);
1692static int (*io_supports_event) (void);
1693static void (*io_init_event) (void);
1694static char iotype[25];
1695
1696const char *
1697rb_get_iotype(void)
1698{
1699 return iotype;
1700}
1701
1702static int
1703rb_unsupported_event(void)
1704{
1705 return 0;
1706}
1707
1708static int
1709try_kqueue(void)
1710{
1711 if(!rb_init_netio_kqueue())
1712 {
1713 setselect_handler = rb_setselect_kqueue;
1714 select_handler = rb_select_kqueue;
1715 setup_fd_handler = rb_setup_fd_kqueue;
1716 io_sched_event = rb_kqueue_sched_event;
1717 io_unsched_event = rb_kqueue_unsched_event;
1718 io_init_event = rb_kqueue_init_event;
1719 io_supports_event = rb_kqueue_supports_event;
1720 rb_strlcpy(iotype, "kqueue", sizeof(iotype));
1721 return 0;
1722 }
1723 return -1;
1724}
1725
1726static int
1727try_epoll(void)
1728{
1729 if(!rb_init_netio_epoll())
1730 {
1731 setselect_handler = rb_setselect_epoll;
1732 select_handler = rb_select_epoll;
1733 setup_fd_handler = rb_setup_fd_epoll;
1734 io_sched_event = rb_epoll_sched_event;
1735 io_unsched_event = rb_epoll_unsched_event;
1736 io_supports_event = rb_epoll_supports_event;
1737 io_init_event = rb_epoll_init_event;
1738 rb_strlcpy(iotype, "epoll", sizeof(iotype));
1739 return 0;
1740 }
1741 return -1;
1742}
1743
1744static int
1745try_ports(void)
1746{
1747 if(!rb_init_netio_ports())
1748 {
1749 setselect_handler = rb_setselect_ports;
1750 select_handler = rb_select_ports;
1751 setup_fd_handler = rb_setup_fd_ports;
1752 io_sched_event = NULL;
1753 io_unsched_event = NULL;
1754 io_init_event = NULL;
1755 io_supports_event = rb_unsupported_event;
1756 rb_strlcpy(iotype, "ports", sizeof(iotype));
1757 return 0;
1758 }
1759 return -1;
1760}
1761
1762static int
1763try_devpoll(void)
1764{
1765 if(!rb_init_netio_devpoll())
1766 {
1767 setselect_handler = rb_setselect_devpoll;
1768 select_handler = rb_select_devpoll;
1769 setup_fd_handler = rb_setup_fd_devpoll;
1770 io_sched_event = NULL;
1771 io_unsched_event = NULL;
1772 io_init_event = NULL;
1773 io_supports_event = rb_unsupported_event;
1774 rb_strlcpy(iotype, "devpoll", sizeof(iotype));
1775 return 0;
1776 }
1777 return -1;
1778}
1779
1780static int
1781try_sigio(void)
1782{
1783 if(!rb_init_netio_sigio())
1784 {
1785 setselect_handler = rb_setselect_sigio;
1786 select_handler = rb_select_sigio;
1787 setup_fd_handler = rb_setup_fd_sigio;
1788 io_sched_event = rb_sigio_sched_event;
1789 io_unsched_event = rb_sigio_unsched_event;
1790 io_supports_event = rb_sigio_supports_event;
1791 io_init_event = rb_sigio_init_event;
1792
1793 rb_strlcpy(iotype, "sigio", sizeof(iotype));
1794 return 0;
1795 }
1796 return -1;
1797}
1798
1799static int
1800try_poll(void)
1801{
1802 if(!rb_init_netio_poll())
1803 {
1804 setselect_handler = rb_setselect_poll;
1805 select_handler = rb_select_poll;
1806 setup_fd_handler = rb_setup_fd_poll;
1807 io_sched_event = NULL;
1808 io_unsched_event = NULL;
1809 io_init_event = NULL;
1810 io_supports_event = rb_unsupported_event;
1811 rb_strlcpy(iotype, "poll", sizeof(iotype));
1812 return 0;
1813 }
1814 return -1;
1815}
1816
1817static int
1818try_win32(void)
1819{
1820 if(!rb_init_netio_win32())
1821 {
1822 setselect_handler = rb_setselect_win32;
1823 select_handler = rb_select_win32;
1824 setup_fd_handler = rb_setup_fd_win32;
1825 io_sched_event = NULL;
1826 io_unsched_event = NULL;
1827 io_init_event = NULL;
1828 io_supports_event = rb_unsupported_event;
1829 rb_strlcpy(iotype, "win32", sizeof(iotype));
1830 return 0;
1831 }
1832 return -1;
1833}
1834
1835static int
1836try_select(void)
1837{
1838 if(!rb_init_netio_select())
1839 {
1840 setselect_handler = rb_setselect_select;
1841 select_handler = rb_select_select;
1842 setup_fd_handler = rb_setup_fd_select;
1843 io_sched_event = NULL;
1844 io_unsched_event = NULL;
1845 io_init_event = NULL;
1846 io_supports_event = rb_unsupported_event;
1847 rb_strlcpy(iotype, "select", sizeof(iotype));
1848 return 0;
1849 }
1850 return -1;
1851}
1852
1853
1854int
1855rb_io_sched_event(struct ev_entry *ev, int when)
1856{
1857 if(ev == NULL || io_supports_event == NULL || io_sched_event == NULL || !io_supports_event())
1858 return 0;
1859 return io_sched_event(ev, when);
1860}
1861
1862void
1863rb_io_unsched_event(struct ev_entry *ev)
1864{
1865 if(ev == NULL || io_supports_event == NULL || io_unsched_event == NULL || !io_supports_event())
1866 return;
1867 io_unsched_event(ev);
1868}
1869int
1870rb_io_supports_event(void)
1871{
1872 if(io_supports_event == NULL)
1873 return 0;
1874 return io_supports_event();
1875}
1876
1877void
1878rb_io_init_event(void)
1879{
1880 io_init_event();
1881 rb_event_io_register_all();
1882}
1883
1884void
1885rb_init_netio(void)
1886{
1887 char *ioenv = getenv("LIBRB_USE_IOTYPE");
1888 rb_fd_table = rb_malloc(RB_FD_HASH_SIZE * sizeof(rb_dlink_list));
1889 rb_init_ssl();
1890
1891 if(ioenv != NULL)
1892 {
1893 if(!strcmp("epoll", ioenv))
1894 {
1895 if(!try_epoll())
1896 return;
1897 } else
1898 if(!strcmp("kqueue", ioenv))
1899 {
1900 if(!try_kqueue())
1901 return;
1902 } else
1903 if(!strcmp("ports", ioenv))
1904 {
1905 if(!try_ports())
1906 return;
1907 } else
1908 if(!strcmp("poll", ioenv))
1909 {
1910 if(!try_poll())
1911 return;
1912 } else
1913 if(!strcmp("devpoll", ioenv))
1914 {
1915 if(!try_devpoll())
1916 return;
1917 } else
1918 if(!strcmp("sigio", ioenv))
1919 {
1920 if(!try_sigio())
1921 return;
1922 } else
1923 if(!strcmp("win32", ioenv))
1924 {
1925 if(!try_win32())
1926 return;
1927 }
1928 if(!strcmp("select", ioenv))
1929 {
1930 if(!try_select())
1931 return;
1932 }
1933
1934 }
1935
1936 if(!try_kqueue())
1937 return;
1938 if(!try_epoll())
1939 return;
1940 if(!try_ports())
1941 return;
1942 if(!try_devpoll())
1943 return;
1944 if(!try_sigio())
1945 return;
1946 if(!try_poll())
1947 return;
1948 if(!try_win32())
1949 return;
1950 if(!try_select())
1951 return;
1952
1953 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
1954
1955 abort();
1956}
1957
1958void
1959rb_setselect(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
1960{
1961 setselect_handler(F, type, handler, client_data);
1962}
1963
1964int
1965rb_select(unsigned long timeout)
1966{
1967 int ret = select_handler(timeout);
1968 free_fds();
1969 return ret;
1970}
1971
1972int
1973rb_setup_fd(rb_fde_t *F)
1974{
1975 return setup_fd_handler(F);
1976}
1977
1978
1979
1980int
1981rb_ignore_errno(int error)
1982{
1983 switch(error)
1984 {
1985#ifdef EINPROGRESS
1986 case EINPROGRESS:
1987#endif
1988#if defined EWOULDBLOCK
1989 case EWOULDBLOCK:
1990#endif
1991#if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
1992 case EAGAIN:
1993#endif
1994#ifdef EINTR
1995 case EINTR:
1996#endif
1997#ifdef ERESTART
1998 case ERESTART:
1999#endif
2000#ifdef ENOBUFS
2001 case ENOBUFS:
2002#endif
2003 return 1;
2004 default:
2005 break;
2006 }
2007 return 0;
2008}
2009
2010
2011int
2012rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2013{
2014 struct msghdr msg;
2015 struct cmsghdr *cmsg;
2016 struct iovec iov[1];
2017 struct stat st;
4414eb3c 2018 uint8_t stype = RB_FD_UNKNOWN;
b57f37fb
WP
2019 const char *desc;
2020 int fd, len, x, rfds;
2021
2022 int control_len = CMSG_SPACE(sizeof(int) * nfds);
2023
2024 iov[0].iov_base = data;
2025 iov[0].iov_len = datasize;
2026
2027 msg.msg_name = NULL;
2028 msg.msg_namelen = 0;
2029 msg.msg_iov = iov;
2030 msg.msg_iovlen = 1;
2031 msg.msg_flags = 0;
2032 cmsg = alloca(control_len);
2033 msg.msg_control = cmsg;
2034 msg.msg_controllen = control_len;
2035
2036 if((len = recvmsg(rb_get_fd(F), &msg, 0)) <= 0)
2037 return len;
2038
2039 if(msg.msg_controllen > 0 && msg.msg_control != NULL && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL)
2040 {
2041 rfds = (msg.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
2042
2043 for(x = 0; x < nfds && x < rfds; x++)
2044 {
2045 fd = ((int *)CMSG_DATA(cmsg))[x];
2046 stype = RB_FD_UNKNOWN;
2047 desc = "remote unknown";
2048 if(!fstat(fd, &st))
2049 {
2050 if(S_ISSOCK(st.st_mode))
2051 {
2052 stype = RB_FD_SOCKET;
2053 desc = "remote socket";
2054 }
2055 else if(S_ISFIFO(st.st_mode))
2056 {
2057 stype = RB_FD_PIPE;
2058 desc = "remote pipe";
2059 }
2060 else if(S_ISREG(st.st_mode))
2061 {
2062 stype = RB_FD_FILE;
2063 desc = "remote file";
2064 }
2065 }
2066 xF[x] = rb_open(fd, stype, desc);
2067 }
2068 } else
2069 *xF = NULL;
2070 return len;
2071}
2072
2073
2074int
2075rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize)
2076{
2077 int n;
2078 struct msghdr msg;
2079 struct cmsghdr *cmsg;
2080 struct iovec iov[1];
2081 char empty = '0';
2082 char *buf;
2083
2084 memset(&msg, 0, sizeof(&msg));
2085 if(datasize == 0)
2086 {
2087 iov[0].iov_base = &empty;
2088 iov[0].iov_len = 1;
2089 } else {
2090 iov[0].iov_base = data;
2091 iov[0].iov_len = datasize;
2092 }
2093 msg.msg_iov = iov;
2094 msg.msg_iovlen = 1;
2095 msg.msg_name = NULL;
2096 msg.msg_namelen = 0;
2097 msg.msg_flags = 0;
2098 msg.msg_control = NULL;
2099 msg.msg_controllen = 0;
2100
2101 if(count > 0)
2102 {
2103 int i;
2104 int len = CMSG_SPACE(sizeof(int) * count);
2105 buf = alloca(len);
2106
2107 msg.msg_control = buf;
2108 msg.msg_controllen = len;
2109 cmsg = CMSG_FIRSTHDR(&msg);
2110 cmsg->cmsg_level = SOL_SOCKET;
2111 cmsg->cmsg_type = SCM_RIGHTS;
2112 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * count);
2113
2114 for(i = 0; i < count; i++)
2115 {
2116 ((int *)CMSG_DATA(cmsg))[i] = rb_get_fd(F[i]);
2117 }
2118 msg.msg_controllen = cmsg->cmsg_len;
2119 }
2120 n = sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
2121 return n;
2122}
2123