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