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