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