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