]> jfr.im git - solanum.git/blame - libratbox/src/commio.c
libratbox: make defer_accept optional.
[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
777
778 return result;
db137867
AC
779}
780
781void
782rb_fdlist_init(int closeall, int maxfds, size_t heapsize)
783{
784 static int initialized = 0;
3202e249 785#ifdef _WIN32
db137867
AC
786 WSADATA wsaData;
787 int err;
788 int vers = MAKEWORD(2, 0);
3202e249 789
db137867
AC
790 err = WSAStartup(vers, &wsaData);
791 if(err != 0)
792 {
793 rb_lib_die("WSAStartup failed");
794 }
795
796#endif
797 if(!initialized)
798 {
799 rb_maxconnections = maxfds;
800 if(closeall)
801 rb_close_all();
802 /* Since we're doing this once .. */
803 initialized = 1;
804 }
805 fd_heap = rb_bh_create(sizeof(rb_fde_t), heapsize, "librb_fd_heap");
806
807}
808
809
810/* Called to open a given filedescriptor */
811rb_fde_t *
a9fb3ed0 812rb_open(int fd, uint8_t type, const char *desc)
db137867 813{
a9fb3ed0 814 rb_fde_t *F;
db137867
AC
815 lrb_assert(fd >= 0);
816
a9fb3ed0
VY
817 F = add_fd(fd);
818
819 lrb_assert(!IsFDOpen(F));
c2ac22cc 820 if(rb_unlikely(IsFDOpen(F)))
db137867 821 {
a9fb3ed0
VY
822 const char *fdesc;
823 if(F != NULL && F->desc != NULL)
824 fdesc = F->desc;
825 else
826 fdesc = "NULL";
3202e249 827 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd, fdesc);
db137867
AC
828 return NULL;
829 }
db137867
AC
830 F->fd = fd;
831 F->type = type;
832 SetFDOpen(F);
833
834 if(desc != NULL)
835 F->desc = rb_strndup(desc, FD_DESC_SZ);
836 number_fd++;
837 return F;
838}
839
840
841/* Called to close a given filedescriptor */
842void
843rb_close(rb_fde_t *F)
844{
845 int type, fd;
3202e249 846
db137867
AC
847 if(F == NULL)
848 return;
849
850 fd = F->fd;
3202e249 851 type = F->type;
db137867
AC
852 lrb_assert(IsFDOpen(F));
853
854 lrb_assert(!(type & RB_FD_FILE));
c2ac22cc 855 if(rb_unlikely(type & RB_FD_FILE))
db137867
AC
856 {
857 lrb_assert(F->read_handler == NULL);
858 lrb_assert(F->write_handler == NULL);
859 }
860 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
861 rb_settimeout(F, 0, NULL, NULL);
862 rb_free(F->accept);
863 rb_free(F->connect);
864 rb_free(F->desc);
865#ifdef HAVE_SSL
866 if(type & RB_FD_SSL)
867 {
868 rb_ssl_shutdown(F);
869 }
870#endif /* HAVE_SSL */
871 if(IsFDOpen(F))
872 {
873 remove_fd(F);
874 ClearFDOpen(F);
875 }
876
877 number_fd--;
878
3202e249
VY
879#ifdef _WIN32
880 if(type & (RB_FD_SOCKET | RB_FD_PIPE))
db137867
AC
881 {
882 closesocket(fd);
883 return;
3202e249
VY
884 }
885 else
db137867 886#endif
3202e249 887 close(fd);
db137867
AC
888}
889
890
891/*
892 * rb_dump_fd() - dump the list of active filedescriptors
893 */
894void
895rb_dump_fd(DUMPCB * cb, void *data)
896{
897 static const char *empty = "";
898 rb_dlink_node *ptr;
899 rb_dlink_list *bucket;
900 rb_fde_t *F;
901 unsigned int i;
902
903 for(i = 0; i < RB_FD_HASH_SIZE; i++)
904 {
905 bucket = &rb_fd_table[i];
906
907 if(rb_dlink_list_length(bucket) <= 0)
908 continue;
909
910 RB_DLINK_FOREACH(ptr, bucket->head)
911 {
912 F = ptr->data;
913 if(F == NULL || !IsFDOpen(F))
914 continue;
915
916 cb(F->fd, F->desc ? F->desc : empty, data);
917 }
918 }
919}
920
921/*
922 * rb_note() - set the fd note
923 *
924 * Note: must be careful not to overflow rb_fd_table[fd].desc when
925 * calling.
926 */
927void
928rb_note(rb_fde_t *F, const char *string)
929{
930 if(F == NULL)
931 return;
932
933 rb_free(F->desc);
934 F->desc = rb_strndup(string, FD_DESC_SZ);
935}
936
937void
a9fb3ed0 938rb_set_type(rb_fde_t *F, uint8_t type)
db137867
AC
939{
940 /* if the caller is calling this, lets assume they have a clue */
941 F->type = type;
942 return;
943}
944
a9fb3ed0 945uint8_t
db137867
AC
946rb_get_type(rb_fde_t *F)
947{
948 return F->type;
949}
950
3202e249 951int
db137867
AC
952rb_fd_ssl(rb_fde_t *F)
953{
954 if(F == NULL)
955 return 0;
956 if(F->type & RB_FD_SSL)
957 return 1;
958 return 0;
959}
960
3202e249 961int
db137867
AC
962rb_get_fd(rb_fde_t *F)
963{
964 if(F == NULL)
965 return -1;
3202e249 966 return (F->fd);
db137867
AC
967}
968
969rb_fde_t *
970rb_get_fde(int fd)
971{
972 return rb_find_fd(fd);
973}
974
975ssize_t
976rb_read(rb_fde_t *F, void *buf, int count)
977{
ba1721d1 978 ssize_t ret;
db137867
AC
979 if(F == NULL)
980 return 0;
3202e249 981
db137867
AC
982 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
983 * an SSL socket as a regular socket
984 */
985#ifdef HAVE_SSL
986 if(F->type & RB_FD_SSL)
987 {
988 return rb_ssl_read(F, buf, count);
3202e249 989 }
db137867
AC
990#endif
991 if(F->type & RB_FD_SOCKET)
992 {
993 ret = recv(F->fd, buf, count, 0);
994 if(ret < 0)
995 {
996 rb_get_errno();
997 }
998 return ret;
999 }
1000
1001
1002 /* default case */
1003 return read(F->fd, buf, count);
1004}
1005
1006
1007ssize_t
1008rb_write(rb_fde_t *F, const void *buf, int count)
1009{
ba1721d1 1010 ssize_t ret;
db137867
AC
1011 if(F == NULL)
1012 return 0;
1013
1014#ifdef HAVE_SSL
1015 if(F->type & RB_FD_SSL)
1016 {
1017 return rb_ssl_write(F, buf, count);
3202e249 1018 }
db137867
AC
1019#endif
1020 if(F->type & RB_FD_SOCKET)
1021 {
1022 ret = send(F->fd, buf, count, MSG_NOSIGNAL);
3202e249
VY
1023 if(ret < 0)
1024 {
db137867
AC
1025 rb_get_errno();
1026 }
1027 return ret;
1028 }
1029
1030 return write(F->fd, buf, count);
1031}
1032
1033#if defined(HAVE_SSL) || defined(WIN32) || !defined(HAVE_WRITEV)
1034static ssize_t
1035rb_fake_writev(rb_fde_t *F, const struct rb_iovec *vp, size_t vpcount)
1036{
ba1721d1 1037 ssize_t count = 0;
db137867 1038
3202e249 1039 while(vpcount-- > 0)
db137867 1040 {
ba1721d1 1041 ssize_t written = rb_write(F, vp->iov_base, vp->iov_len);
db137867 1042
3202e249 1043 if(written <= 0)
db137867
AC
1044 {
1045 if(count > 0)
1046 return count;
1047 else
1048 return written;
1049 }
1050 count += written;
1051 vp++;
1052 }
1053 return (count);
1054}
1055#endif
1056
1057#if defined(WIN32) || !defined(HAVE_WRITEV)
1058ssize_t
3202e249 1059rb_writev(rb_fde_t *F, struct rb_iovec * vecount, int count)
db137867
AC
1060{
1061 return rb_fake_writev(F, vecount, count);
1062}
1063
1064#else
1065ssize_t
3202e249 1066rb_writev(rb_fde_t *F, struct rb_iovec * vector, int count)
db137867 1067{
3202e249
VY
1068 if(F == NULL)
1069 {
db137867
AC
1070 errno = EBADF;
1071 return -1;
1072 }
1073#ifdef HAVE_SSL
1074 if(F->type & RB_FD_SSL)
1075 {
3202e249 1076 return rb_fake_writev(F, vector, count);
db137867
AC
1077 }
1078#endif /* HAVE_SSL */
1079#ifdef HAVE_SENDMSG
1080 if(F->type & RB_FD_SOCKET)
1081 {
1082 struct msghdr msg;
1083 memset(&msg, 0, sizeof(msg));
1084 msg.msg_iov = (struct iovec *)vector;
1085 msg.msg_iovlen = count;
1086 return sendmsg(F->fd, &msg, MSG_NOSIGNAL);
3202e249 1087 }
db137867
AC
1088#endif /* HAVE_SENDMSG */
1089 return writev(F->fd, (struct iovec *)vector, count);
1090
1091}
3202e249 1092#endif
db137867
AC
1093
1094
1095/*
1096 * From: Thomas Helvey <tomh@inxpress.net>
1097 */
1098static const char *IpQuadTab[] = {
1099 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1100 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1101 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1102 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1103 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1104 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1105 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1106 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1107 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1108 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1109 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1110 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1111 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1112 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1113 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1114 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1115 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1116 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1117 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1118 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1119 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1120 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1121 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1122 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1123 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1124 "250", "251", "252", "253", "254", "255"
1125};
1126
1127/*
1128 * inetntoa - in_addr to string
1129 * changed name to remove collision possibility and
1130 * so behaviour is guaranteed to take a pointer arg.
1131 * -avalon 23/11/92
1132 * inet_ntoa -- returned the dotted notation of a given
1133 * internet number
1134 * argv 11/90).
1135 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1136 */
1137
1138static const char *
1139inetntoa(const char *in)
1140{
1141 static char buf[16];
1142 char *bufptr = buf;
3202e249 1143 const unsigned char *a = (const unsigned char *)in;
db137867
AC
1144 const char *n;
1145
1146 n = IpQuadTab[*a++];
3202e249 1147 while(*n)
db137867
AC
1148 *bufptr++ = *n++;
1149 *bufptr++ = '.';
1150 n = IpQuadTab[*a++];
3202e249 1151 while(*n)
db137867
AC
1152 *bufptr++ = *n++;
1153 *bufptr++ = '.';
1154 n = IpQuadTab[*a++];
3202e249 1155 while(*n)
db137867
AC
1156 *bufptr++ = *n++;
1157 *bufptr++ = '.';
1158 n = IpQuadTab[*a];
3202e249 1159 while(*n)
db137867
AC
1160 *bufptr++ = *n++;
1161 *bufptr = '\0';
1162 return buf;
1163}
1164
1165
1166/*
1167 * Copyright (c) 1996-1999 by Internet Software Consortium.
1168 *
1169 * Permission to use, copy, modify, and distribute this software for any
1170 * purpose with or without fee is hereby granted, provided that the above
1171 * copyright notice and this permission notice appear in all copies.
1172 *
1173 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
1174 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1175 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
1176 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1177 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1178 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1179 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1180 * SOFTWARE.
1181 */
1182
1183#define SPRINTF(x) ((size_t)rb_sprintf x)
1184
1185/*
1186 * WARNING: Don't even consider trying to compile this on a system where
1187 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1188 */
1189
3202e249 1190static const char *inet_ntop4(const unsigned char *src, char *dst, unsigned int size);
db137867 1191#ifdef RB_IPV6
3202e249 1192static const char *inet_ntop6(const unsigned char *src, char *dst, unsigned int size);
db137867
AC
1193#endif
1194
1195/* const char *
1196 * inet_ntop4(src, dst, size)
1197 * format an IPv4 address
1198 * return:
1199 * `dst' (as a const)
1200 * notes:
1201 * (1) uses no statics
1202 * (2) takes a unsigned char* not an in_addr as input
1203 * author:
1204 * Paul Vixie, 1996.
1205 */
1206static const char *
1207inet_ntop4(const unsigned char *src, char *dst, unsigned int size)
1208{
1209 if(size < 16)
1210 return NULL;
86510a73 1211 return strcpy(dst, inetntoa((const char *)src));
db137867
AC
1212}
1213
1214/* const char *
1215 * inet_ntop6(src, dst, size)
1216 * convert IPv6 binary address into presentation (printable) format
1217 * author:
1218 * Paul Vixie, 1996.
1219 */
1220#ifdef RB_IPV6
1221static const char *
1222inet_ntop6(const unsigned char *src, char *dst, unsigned int size)
1223{
1224 /*
1225 * Note that int32_t and int16_t need only be "at least" large enough
1226 * to contain a value of the specified size. On some systems, like
1227 * Crays, there is no such thing as an integer variable with 16 bits.
1228 * Keep this in mind if you think this function should have been coded
1229 * to use pointer overlays. All the world's not a VAX.
1230 */
1231 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
1232 struct
1233 {
1234 int base, len;
1235 }
1236 best, cur;
1237 unsigned int words[IN6ADDRSZ / INT16SZ];
1238 int i;
1239
1240 /*
1241 * Preprocess:
1242 * Copy the input (bytewise) array into a wordwise array.
1243 * Find the longest run of 0x00's in src[] for :: shorthanding.
1244 */
1245 memset(words, '\0', sizeof words);
3202e249 1246 for(i = 0; i < IN6ADDRSZ; i += 2)
db137867
AC
1247 words[i / 2] = (src[i] << 8) | src[i + 1];
1248 best.base = -1;
1249 best.len = 0;
1250 cur.base = -1;
1251 cur.len = 0;
3202e249 1252 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1253 {
1254 if(words[i] == 0)
1255 {
1256 if(cur.base == -1)
1257 cur.base = i, cur.len = 1;
1258 else
1259 cur.len++;
1260 }
1261 else
1262 {
1263 if(cur.base != -1)
1264 {
1265 if(best.base == -1 || cur.len > best.len)
1266 best = cur;
1267 cur.base = -1;
1268 }
1269 }
1270 }
1271 if(cur.base != -1)
1272 {
1273 if(best.base == -1 || cur.len > best.len)
1274 best = cur;
1275 }
1276 if(best.base != -1 && best.len < 2)
1277 best.base = -1;
1278
1279 /*
1280 * Format the result.
1281 */
1282 tp = tmp;
3202e249 1283 for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
db137867
AC
1284 {
1285 /* Are we inside the best run of 0x00's? */
1286 if(best.base != -1 && i >= best.base && i < (best.base + best.len))
1287 {
1288 if(i == best.base)
1289 {
1290 if(i == 0)
1291 *tp++ = '0';
1292 *tp++ = ':';
1293 }
1294 continue;
1295 }
1296 /* Are we following an initial run of 0x00s or any real hex? */
1297 if(i != 0)
1298 *tp++ = ':';
1299 /* Is this address an encapsulated IPv4? */
1300 if(i == 6 && best.base == 0 &&
1301 (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
1302 {
1303 if(!inet_ntop4(src + 12, tp, sizeof tmp - (tp - tmp)))
1304 return (NULL);
1305 tp += strlen(tp);
1306 break;
1307 }
1308 tp += SPRINTF((tp, "%x", words[i]));
1309 }
1310 /* Was it a trailing run of 0x00's? */
1311 if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
1312 *tp++ = ':';
1313 *tp++ = '\0';
1314
1315 /*
1316 * Check for overflow, copy, and we're done.
1317 */
1318
3202e249 1319 if((unsigned int)(tp - tmp) > size)
db137867
AC
1320 {
1321 return (NULL);
1322 }
86510a73 1323 return memcpy(dst, tmp, tp - tmp);
db137867
AC
1324}
1325#endif
1326
1327int
1328rb_inet_pton_sock(const char *src, struct sockaddr *dst)
1329{
3202e249 1330 if(rb_inet_pton(AF_INET, src, &((struct sockaddr_in *)dst)->sin_addr))
db137867 1331 {
3202e249
VY
1332 ((struct sockaddr_in *)dst)->sin_port = 0;
1333 ((struct sockaddr_in *)dst)->sin_family = AF_INET;
db137867
AC
1334 SET_SS_LEN(dst, sizeof(struct sockaddr_in));
1335 return 1;
1336 }
1337#ifdef RB_IPV6
3202e249 1338 else if(rb_inet_pton(AF_INET6, src, &((struct sockaddr_in6 *)dst)->sin6_addr))
db137867 1339 {
3202e249
VY
1340 ((struct sockaddr_in6 *)dst)->sin6_port = 0;
1341 ((struct sockaddr_in6 *)dst)->sin6_family = AF_INET6;
db137867
AC
1342 SET_SS_LEN(dst, sizeof(struct sockaddr_in6));
1343 return 1;
1344 }
1345#endif
1346 return 0;
1347}
1348
1349const char *
1350rb_inet_ntop_sock(struct sockaddr *src, char *dst, unsigned int size)
1351{
1352 switch (src->sa_family)
1353 {
1354 case AF_INET:
3202e249 1355 return (rb_inet_ntop(AF_INET, &((struct sockaddr_in *)src)->sin_addr, dst, size));
db137867
AC
1356 break;
1357#ifdef RB_IPV6
1358 case AF_INET6:
3202e249
VY
1359 return (rb_inet_ntop
1360 (AF_INET6, &((struct sockaddr_in6 *)src)->sin6_addr, dst, size));
db137867
AC
1361 break;
1362#endif
1363 default:
1364 return NULL;
1365 break;
1366 }
1367}
1368
1369/* char *
1370 * rb_inet_ntop(af, src, dst, size)
1371 * convert a network format address to presentation format.
1372 * return:
1373 * pointer to presentation format address (`dst'), or NULL (see errno).
1374 * author:
1375 * Paul Vixie, 1996.
1376 */
1377const char *
1378rb_inet_ntop(int af, const void *src, char *dst, unsigned int size)
1379{
1380 switch (af)
1381 {
1382 case AF_INET:
1383 return (inet_ntop4(src, dst, size));
1384#ifdef RB_IPV6
1385 case AF_INET6:
3202e249
VY
1386 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) ||
1387 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src))
db137867 1388 return (inet_ntop4
3202e249
VY
1389 ((const unsigned char *)&((const struct in6_addr *)src)->
1390 s6_addr[12], dst, size));
db137867
AC
1391 else
1392 return (inet_ntop6(src, dst, size));
1393
1394
1395#endif
1396 default:
1397 return (NULL);
1398 }
1399 /* NOTREACHED */
1400}
1401
1402/*
1403 * WARNING: Don't even consider trying to compile this on a system where
1404 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1405 */
1406
1407/* int
1408 * rb_inet_pton(af, src, dst)
1409 * convert from presentation format (which usually means ASCII printable)
1410 * to network format (which is usually some kind of binary format).
1411 * return:
1412 * 1 if the address was valid for the specified address family
1413 * 0 if the address wasn't valid (`dst' is untouched in this case)
1414 * -1 if some other error occurred (`dst' is untouched in this case, too)
1415 * author:
1416 * Paul Vixie, 1996.
1417 */
1418
1419/* int
1420 * inet_pton4(src, dst)
1421 * like inet_aton() but without all the hexadecimal and shorthand.
1422 * return:
1423 * 1 if `src' is a valid dotted quad, else 0.
1424 * notice:
1425 * does not touch `dst' unless it's returning 1.
1426 * author:
1427 * Paul Vixie, 1996.
1428 */
1429static int
1430inet_pton4(const char *src, unsigned char *dst)
1431{
1432 int saw_digit, octets, ch;
1433 unsigned char tmp[INADDRSZ], *tp;
1434
1435 saw_digit = 0;
1436 octets = 0;
1437 *(tp = tmp) = 0;
3202e249 1438 while((ch = *src++) != '\0')
db137867
AC
1439 {
1440
1441 if(ch >= '0' && ch <= '9')
1442 {
1443 unsigned int new = *tp * 10 + (ch - '0');
1444
1445 if(new > 255)
1446 return (0);
1447 *tp = new;
1448 if(!saw_digit)
1449 {
1450 if(++octets > 4)
1451 return (0);
1452 saw_digit = 1;
1453 }
1454 }
1455 else if(ch == '.' && saw_digit)
1456 {
1457 if(octets == 4)
1458 return (0);
1459 *++tp = 0;
1460 saw_digit = 0;
1461 }
1462 else
1463 return (0);
1464 }
1465 if(octets < 4)
1466 return (0);
1467 memcpy(dst, tmp, INADDRSZ);
1468 return (1);
1469}
1470
1471#ifdef RB_IPV6
1472/* int
1473 * inet_pton6(src, dst)
1474 * convert presentation level address to network order binary form.
1475 * return:
1476 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1477 * notice:
1478 * (1) does not touch `dst' unless it's returning 1.
1479 * (2) :: in a full address is silently ignored.
1480 * credit:
1481 * inspired by Mark Andrews.
1482 * author:
1483 * Paul Vixie, 1996.
1484 */
1485
1486static int
1487inet_pton6(const char *src, unsigned char *dst)
1488{
1489 static const char xdigits[] = "0123456789abcdef";
1490 unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
1491 const char *curtok;
1492 int ch, saw_xdigit;
1493 unsigned int val;
1494
1495 tp = memset(tmp, '\0', IN6ADDRSZ);
1496 endp = tp + IN6ADDRSZ;
1497 colonp = NULL;
1498 /* Leading :: requires some special handling. */
1499 if(*src == ':')
1500 if(*++src != ':')
1501 return (0);
1502 curtok = src;
1503 saw_xdigit = 0;
1504 val = 0;
3202e249 1505 while((ch = tolower(*src++)) != '\0')
db137867
AC
1506 {
1507 const char *pch;
1508
1509 pch = strchr(xdigits, ch);
1510 if(pch != NULL)
1511 {
1512 val <<= 4;
1513 val |= (pch - xdigits);
1514 if(val > 0xffff)
1515 return (0);
1516 saw_xdigit = 1;
1517 continue;
1518 }
1519 if(ch == ':')
1520 {
1521 curtok = src;
1522 if(!saw_xdigit)
1523 {
1524 if(colonp)
1525 return (0);
1526 colonp = tp;
1527 continue;
1528 }
1529 else if(*src == '\0')
1530 {
1531 return (0);
1532 }
1533 if(tp + INT16SZ > endp)
1534 return (0);
3202e249
VY
1535 *tp++ = (unsigned char)(val >> 8) & 0xff;
1536 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1537 saw_xdigit = 0;
1538 val = 0;
1539 continue;
1540 }
1541 if(*src != '\0' && ch == '.')
1542 {
1543 if(((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
1544 {
1545 tp += INADDRSZ;
1546 saw_xdigit = 0;
1547 break; /* '\0' was seen by inet_pton4(). */
1548 }
1549 }
1550 else
1551 continue;
1552 return (0);
1553 }
1554 if(saw_xdigit)
1555 {
1556 if(tp + INT16SZ > endp)
1557 return (0);
3202e249
VY
1558 *tp++ = (unsigned char)(val >> 8) & 0xff;
1559 *tp++ = (unsigned char)val & 0xff;
db137867
AC
1560 }
1561 if(colonp != NULL)
1562 {
1563 /*
1564 * Since some memmove()'s erroneously fail to handle
1565 * overlapping regions, we'll do the shift by hand.
1566 */
1567 const int n = tp - colonp;
1568 int i;
1569
1570 if(tp == endp)
1571 return (0);
3202e249 1572 for(i = 1; i <= n; i++)
db137867
AC
1573 {
1574 endp[-i] = colonp[n - i];
1575 colonp[n - i] = 0;
1576 }
1577 tp = endp;
1578 }
1579 if(tp != endp)
1580 return (0);
1581 memcpy(dst, tmp, IN6ADDRSZ);
1582 return (1);
1583}
1584#endif
1585int
1586rb_inet_pton(int af, const char *src, void *dst)
1587{
1588 switch (af)
1589 {
1590 case AF_INET:
1591 return (inet_pton4(src, dst));
1592#ifdef RB_IPV6
1593 case AF_INET6:
1594 /* Somebody might have passed as an IPv4 address this is sick but it works */
1595 if(inet_pton4(src, dst))
1596 {
1597 char tmp[HOSTIPLEN];
1598 rb_sprintf(tmp, "::ffff:%s", src);
1599 return (inet_pton6(tmp, dst));
1600 }
1601 else
1602 return (inet_pton6(src, dst));
1603#endif
1604 default:
1605 return (-1);
1606 }
1607 /* NOTREACHED */
1608}
1609
1610
1611#ifndef HAVE_SOCKETPAIR
3202e249
VY
1612
1613/* mostly based on perl's emulation of socketpair udp */
1614static int
1615rb_inet_socketpair_udp(rb_fde_t **newF1, rb_fde_t **newF2)
1616{
1617 struct sockaddr_in addr[2];
1618 rb_socklen_t size = sizeof(struct sockaddr_in);
1619 rb_fde_t *F[2];
1620 unsigned int fd[2];
1621 int i, got;
1622 unsigned short port;
030272f3
VY
1623 struct timeval wait = { 0, 100000 };
1624 int max;
1625 fd_set rset;
1626 struct sockaddr_in readfrom;
1627 unsigned short buf[2];
1628 int o_errno;
3202e249
VY
1629
1630 memset(&addr, 0, sizeof(addr));
1631
1632 for(i = 0; i < 2; i++)
1633 {
1634 F[i] = rb_socket(AF_INET, SOCK_DGRAM, 0, "udp socketpair");
1635 if(F[i] == NULL)
1636 goto failed;
1637 addr[i].sin_family = AF_INET;
1638 addr[i].sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1639 addr[i].sin_port = 0;
1640 if(bind(rb_get_fd(F[i]), (struct sockaddr *)&addr[i], sizeof(struct sockaddr_in)))
1641 goto failed;
1642 fd[i] = rb_get_fd(F[i]);
1643 }
1644
1645 for(i = 0; i < 2; i++)
1646 {
1647 if(getsockname(fd[i], (struct sockaddr *)&addr[i], &size))
1648 goto failed;
1649 if(size != sizeof(struct sockaddr_in))
1650 goto failed;
1651 if(connect(fd[!i], (struct sockaddr *)&addr[i], sizeof(struct sockaddr_in)) == -1)
1652 goto failed;
1653 }
1654
1655 for(i = 0; i < 2; i++)
1656 {
1657 port = addr[i].sin_port;
1658 got = rb_write(F[i], &port, sizeof(port));
1659 if(got != sizeof(port))
1660 {
1661 if(got == -1)
1662 goto failed;
1663 goto abort_failed;
1664 }
1665 }
1666
030272f3 1667 max = fd[1] > fd[0] ? fd[1] : fd[0];
3202e249
VY
1668 FD_ZERO(&rset);
1669 FD_SET(fd[0], &rset);
1670 FD_SET(fd[1], &rset);
1671 got = select(max + 1, &rset, NULL, NULL, &wait);
1672 if(got != 2 || !FD_ISSET(fd[0], &rset) || !FD_ISSET(fd[1], &rset))
1673 {
1674 if(got == -1)
1675 goto failed;
1676 goto abort_failed;
1677 }
1678
3202e249
VY
1679 for(i = 0; i < 2; i++)
1680 {
1681#ifdef MSG_DONTWAIT
1682 int flag = MSG_DONTWAIT
1683#else
1684 int flag = 0;
1685#endif
1686 got = recvfrom(rb_get_fd(F[i]), (char *)&buf, sizeof(buf), flag,
1687 (struct sockaddr *)&readfrom, &size);
1688 if(got == -1)
1689 goto failed;
1690 if(got != sizeof(port)
1691 || size != sizeof(struct sockaddr_in)
1692 || buf[0] != (unsigned short)addr[!i].sin_port
1693 || readfrom.sin_family != addr[!i].sin_family
1694 || readfrom.sin_addr.s_addr != addr[!i].sin_addr.s_addr
1695 || readfrom.sin_port != addr[!i].sin_port)
1696 goto abort_failed;
1697 }
1698
1699 *newF1 = F[0];
1700 *newF2 = F[1];
1701 return 0;
1702
1703#ifdef _WIN32
1704#define ECONNABORTED WSAECONNABORTED
1705#endif
1706
1707 abort_failed:
1708 rb_get_errno();
1709 errno = ECONNABORTED;
1710 failed:
1711 if(errno != ECONNABORTED)
1712 rb_get_errno();
030272f3 1713 o_errno = errno;
3202e249
VY
1714 if(F[0] != NULL)
1715 rb_close(F[0]);
1716 if(F[1] != NULL)
1717 rb_close(F[1]);
1718 errno = o_errno;
1719 return -1;
1720}
1721
1722
db137867
AC
1723int
1724rb_inet_socketpair(int family, int type, int protocol, int fd[2])
1725{
1726 int listener = -1;
1727 int connector = -1;
1728 int acceptor = -1;
1729 struct sockaddr_in listen_addr;
1730 struct sockaddr_in connect_addr;
3202e249 1731 rb_socklen_t size;
db137867
AC
1732
1733 if(protocol || family != AF_INET)
1734 {
1735 errno = EAFNOSUPPORT;
1736 return -1;
1737 }
1738 if(!fd)
1739 {
1740 errno = EINVAL;
1741 return -1;
1742 }
1743
1744 listener = socket(AF_INET, type, 0);
1745 if(listener == -1)
1746 return -1;
1747 memset(&listen_addr, 0, sizeof(listen_addr));
1748 listen_addr.sin_family = AF_INET;
1749 listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1750 listen_addr.sin_port = 0; /* kernel choses port. */
3202e249 1751 if(bind(listener, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) == -1)
db137867
AC
1752 goto tidy_up_and_fail;
1753 if(listen(listener, 1) == -1)
1754 goto tidy_up_and_fail;
1755
1756 connector = socket(AF_INET, type, 0);
1757 if(connector == -1)
1758 goto tidy_up_and_fail;
1759 /* We want to find out the port number to connect to. */
1760 size = sizeof(connect_addr);
3202e249 1761 if(getsockname(listener, (struct sockaddr *)&connect_addr, &size) == -1)
db137867
AC
1762 goto tidy_up_and_fail;
1763 if(size != sizeof(connect_addr))
1764 goto abort_tidy_up_and_fail;
3202e249 1765 if(connect(connector, (struct sockaddr *)&connect_addr, sizeof(connect_addr)) == -1)
db137867
AC
1766 goto tidy_up_and_fail;
1767
1768 size = sizeof(listen_addr);
3202e249 1769 acceptor = accept(listener, (struct sockaddr *)&listen_addr, &size);
db137867
AC
1770 if(acceptor == -1)
1771 goto tidy_up_and_fail;
1772 if(size != sizeof(listen_addr))
1773 goto abort_tidy_up_and_fail;
1774 close(listener);
1775 /* Now check we are talking to ourself by matching port and host on the
1776 two sockets. */
3202e249 1777 if(getsockname(connector, (struct sockaddr *)&connect_addr, &size) == -1)
db137867
AC
1778 goto tidy_up_and_fail;
1779 if(size != sizeof(connect_addr)
1780 || listen_addr.sin_family != connect_addr.sin_family
1781 || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
1782 || listen_addr.sin_port != connect_addr.sin_port)
1783 {
1784 goto abort_tidy_up_and_fail;
1785 }
1786 fd[0] = connector;
1787 fd[1] = acceptor;
1788 return 0;
1789
1790 abort_tidy_up_and_fail:
1791 errno = EINVAL; /* I hope this is portable and appropriate. */
1792
1793 tidy_up_and_fail:
1794 {
1795 int save_errno = errno;
1796 if(listener != -1)
1797 close(listener);
1798 if(connector != -1)
1799 close(connector);
1800 if(acceptor != -1)
1801 close(acceptor);
1802 errno = save_errno;
1803 return -1;
1804 }
1805}
1806
1807#endif
1808
1809
1810static void (*setselect_handler) (rb_fde_t *, unsigned int, PF *, void *);
1811static int (*select_handler) (long);
1812static int (*setup_fd_handler) (rb_fde_t *);
1813static int (*io_sched_event) (struct ev_entry *, int);
1814static void (*io_unsched_event) (struct ev_entry *);
1815static int (*io_supports_event) (void);
1816static void (*io_init_event) (void);
1817static char iotype[25];
1818
1819const char *
1820rb_get_iotype(void)
1821{
1822 return iotype;
1823}
1824
1825static int
1826rb_unsupported_event(void)
1827{
1828 return 0;
1829}
1830
1831static int
1832try_kqueue(void)
1833{
1834 if(!rb_init_netio_kqueue())
1835 {
1836 setselect_handler = rb_setselect_kqueue;
1837 select_handler = rb_select_kqueue;
1838 setup_fd_handler = rb_setup_fd_kqueue;
1839 io_sched_event = rb_kqueue_sched_event;
1840 io_unsched_event = rb_kqueue_unsched_event;
1841 io_init_event = rb_kqueue_init_event;
1842 io_supports_event = rb_kqueue_supports_event;
1843 rb_strlcpy(iotype, "kqueue", sizeof(iotype));
1844 return 0;
1845 }
3202e249 1846 return -1;
db137867
AC
1847}
1848
1849static int
1850try_epoll(void)
1851{
1852 if(!rb_init_netio_epoll())
1853 {
1854 setselect_handler = rb_setselect_epoll;
1855 select_handler = rb_select_epoll;
1856 setup_fd_handler = rb_setup_fd_epoll;
1857 io_sched_event = rb_epoll_sched_event;
1858 io_unsched_event = rb_epoll_unsched_event;
1859 io_supports_event = rb_epoll_supports_event;
1860 io_init_event = rb_epoll_init_event;
1861 rb_strlcpy(iotype, "epoll", sizeof(iotype));
1862 return 0;
1863 }
1864 return -1;
1865}
1866
1867static int
1868try_ports(void)
1869{
1870 if(!rb_init_netio_ports())
1871 {
1872 setselect_handler = rb_setselect_ports;
1873 select_handler = rb_select_ports;
3202e249 1874 setup_fd_handler = rb_setup_fd_ports;
030272f3
VY
1875 io_sched_event = rb_ports_sched_event;
1876 io_unsched_event = rb_ports_unsched_event;
1877 io_init_event = rb_ports_init_event;
1878 io_supports_event = rb_ports_supports_event;
db137867
AC
1879 rb_strlcpy(iotype, "ports", sizeof(iotype));
1880 return 0;
1881 }
1882 return -1;
1883}
1884
1885static int
1886try_devpoll(void)
1887{
1888 if(!rb_init_netio_devpoll())
1889 {
1890 setselect_handler = rb_setselect_devpoll;
1891 select_handler = rb_select_devpoll;
3202e249 1892 setup_fd_handler = rb_setup_fd_devpoll;
db137867
AC
1893 io_sched_event = NULL;
1894 io_unsched_event = NULL;
1895 io_init_event = NULL;
1896 io_supports_event = rb_unsupported_event;
1897 rb_strlcpy(iotype, "devpoll", sizeof(iotype));
1898 return 0;
1899 }
1900 return -1;
1901}
1902
1903static int
1904try_sigio(void)
1905{
1906 if(!rb_init_netio_sigio())
1907 {
1908 setselect_handler = rb_setselect_sigio;
1909 select_handler = rb_select_sigio;
3202e249 1910 setup_fd_handler = rb_setup_fd_sigio;
db137867 1911 io_sched_event = rb_sigio_sched_event;
3202e249
VY
1912 io_unsched_event = rb_sigio_unsched_event;
1913 io_supports_event = rb_sigio_supports_event;
1914 io_init_event = rb_sigio_init_event;
1915
db137867
AC
1916 rb_strlcpy(iotype, "sigio", sizeof(iotype));
1917 return 0;
1918 }
1919 return -1;
1920}
1921
3202e249 1922static int
db137867
AC
1923try_poll(void)
1924{
1925 if(!rb_init_netio_poll())
1926 {
1927 setselect_handler = rb_setselect_poll;
1928 select_handler = rb_select_poll;
3202e249 1929 setup_fd_handler = rb_setup_fd_poll;
db137867
AC
1930 io_sched_event = NULL;
1931 io_unsched_event = NULL;
1932 io_init_event = NULL;
1933 io_supports_event = rb_unsupported_event;
1934 rb_strlcpy(iotype, "poll", sizeof(iotype));
1935 return 0;
1936 }
1937 return -1;
1938}
1939
1940static int
1941try_win32(void)
1942{
1943 if(!rb_init_netio_win32())
1944 {
1945 setselect_handler = rb_setselect_win32;
1946 select_handler = rb_select_win32;
3202e249 1947 setup_fd_handler = rb_setup_fd_win32;
db137867
AC
1948 io_sched_event = NULL;
1949 io_unsched_event = NULL;
1950 io_init_event = NULL;
1951 io_supports_event = rb_unsupported_event;
1952 rb_strlcpy(iotype, "win32", sizeof(iotype));
1953 return 0;
1954 }
1955 return -1;
1956}
1957
1958static int
1959try_select(void)
3202e249 1960{
db137867
AC
1961 if(!rb_init_netio_select())
1962 {
1963 setselect_handler = rb_setselect_select;
1964 select_handler = rb_select_select;
3202e249 1965 setup_fd_handler = rb_setup_fd_select;
db137867
AC
1966 io_sched_event = NULL;
1967 io_unsched_event = NULL;
1968 io_init_event = NULL;
1969 io_supports_event = rb_unsupported_event;
1970 rb_strlcpy(iotype, "select", sizeof(iotype));
1971 return 0;
1972 }
1973 return -1;
1974}
1975
1976
1977int
1978rb_io_sched_event(struct ev_entry *ev, int when)
1979{
3202e249
VY
1980 if(ev == NULL || io_supports_event == NULL || io_sched_event == NULL
1981 || !io_supports_event())
db137867
AC
1982 return 0;
1983 return io_sched_event(ev, when);
1984}
1985
1986void
1987rb_io_unsched_event(struct ev_entry *ev)
1988{
3202e249
VY
1989 if(ev == NULL || io_supports_event == NULL || io_unsched_event == NULL
1990 || !io_supports_event())
db137867 1991 return;
3202e249 1992 io_unsched_event(ev);
db137867 1993}
3202e249 1994
db137867
AC
1995int
1996rb_io_supports_event(void)
1997{
1998 if(io_supports_event == NULL)
1999 return 0;
2000 return io_supports_event();
2001}
2002
2003void
2004rb_io_init_event(void)
2005{
2006 io_init_event();
2007 rb_event_io_register_all();
2008}
2009
2010void
2011rb_init_netio(void)
2012{
2013 char *ioenv = getenv("LIBRB_USE_IOTYPE");
2014 rb_fd_table = rb_malloc(RB_FD_HASH_SIZE * sizeof(rb_dlink_list));
2015 rb_init_ssl();
3202e249 2016
db137867
AC
2017 if(ioenv != NULL)
2018 {
2019 if(!strcmp("epoll", ioenv))
2020 {
2021 if(!try_epoll())
2022 return;
3202e249
VY
2023 }
2024 else if(!strcmp("kqueue", ioenv))
db137867
AC
2025 {
2026 if(!try_kqueue())
2027 return;
3202e249
VY
2028 }
2029 else if(!strcmp("ports", ioenv))
db137867
AC
2030 {
2031 if(!try_ports())
2032 return;
3202e249
VY
2033 }
2034 else if(!strcmp("poll", ioenv))
db137867
AC
2035 {
2036 if(!try_poll())
2037 return;
3202e249
VY
2038 }
2039 else if(!strcmp("devpoll", ioenv))
db137867
AC
2040 {
2041 if(!try_devpoll())
2042 return;
3202e249
VY
2043 }
2044 else if(!strcmp("sigio", ioenv))
db137867
AC
2045 {
2046 if(!try_sigio())
2047 return;
3202e249
VY
2048 }
2049 else if(!strcmp("select", ioenv))
db137867 2050 {
3202e249 2051 if(!try_select())
db137867
AC
2052 return;
2053 }
3202e249 2054 if(!strcmp("win32", ioenv))
db137867 2055 {
3202e249 2056 if(!try_win32())
db137867
AC
2057 return;
2058 }
3202e249 2059
db137867
AC
2060 }
2061
2062 if(!try_kqueue())
2063 return;
2064 if(!try_epoll())
2065 return;
2066 if(!try_ports())
2067 return;
2068 if(!try_devpoll())
2069 return;
2070 if(!try_sigio())
2071 return;
2072 if(!try_poll())
2073 return;
2074 if(!try_win32())
2075 return;
2076 if(!try_select())
2077 return;
2078
2079 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
2080
2081 abort();
2082}
2083
3202e249 2084void
db137867
AC
2085rb_setselect(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
2086{
2087 setselect_handler(F, type, handler, client_data);
2088}
2089
3202e249 2090int
db137867
AC
2091rb_select(unsigned long timeout)
2092{
2093 int ret = select_handler(timeout);
2094 free_fds();
2095 return ret;
2096}
2097
3202e249 2098int
db137867
AC
2099rb_setup_fd(rb_fde_t *F)
2100{
2101 return setup_fd_handler(F);
2102}
2103
2104
2105
2106int
2107rb_ignore_errno(int error)
2108{
3202e249 2109 switch (error)
db137867
AC
2110 {
2111#ifdef EINPROGRESS
3202e249 2112 case EINPROGRESS:
db137867
AC
2113#endif
2114#if defined EWOULDBLOCK
3202e249 2115 case EWOULDBLOCK:
db137867
AC
2116#endif
2117#if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
3202e249 2118 case EAGAIN:
db137867
AC
2119#endif
2120#ifdef EINTR
3202e249 2121 case EINTR:
db137867
AC
2122#endif
2123#ifdef ERESTART
3202e249 2124 case ERESTART:
db137867
AC
2125#endif
2126#ifdef ENOBUFS
3202e249
VY
2127 case ENOBUFS:
2128#endif
2129 return 1;
2130 default:
2131 break;
2132 }
db137867
AC
2133 return 0;
2134}
2135
2136
3202e249 2137#if defined(HAVE_SENDMSG) && !defined(WIN32)
db137867
AC
2138int
2139rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2140{
2141 struct msghdr msg;
2142 struct cmsghdr *cmsg;
2143 struct iovec iov[1];
2144 struct stat st;
a9fb3ed0 2145 uint8_t stype = RB_FD_UNKNOWN;
db137867
AC
2146 const char *desc;
2147 int fd, len, x, rfds;
2148
2149 int control_len = CMSG_SPACE(sizeof(int) * nfds);
2150
2151 iov[0].iov_base = data;
2152 iov[0].iov_len = datasize;
3202e249 2153
db137867
AC
2154 msg.msg_name = NULL;
2155 msg.msg_namelen = 0;
2156 msg.msg_iov = iov;
2157 msg.msg_iovlen = 1;
2158 msg.msg_flags = 0;
2159 cmsg = alloca(control_len);
2160 msg.msg_control = cmsg;
2161 msg.msg_controllen = control_len;
2162
2163 if((len = recvmsg(rb_get_fd(F), &msg, 0)) <= 0)
2164 return len;
2165
3202e249
VY
2166 if(msg.msg_controllen > 0 && msg.msg_control != NULL
2167 && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL)
db137867 2168 {
90e960f0 2169 rfds = ((unsigned char *)cmsg + cmsg->cmsg_len - CMSG_DATA(cmsg)) / sizeof(int);
db137867
AC
2170
2171 for(x = 0; x < nfds && x < rfds; x++)
2172 {
2173 fd = ((int *)CMSG_DATA(cmsg))[x];
2174 stype = RB_FD_UNKNOWN;
2175 desc = "remote unknown";
2176 if(!fstat(fd, &st))
2177 {
2178 if(S_ISSOCK(st.st_mode))
2179 {
2180 stype = RB_FD_SOCKET;
2181 desc = "remote socket";
2182 }
2183 else if(S_ISFIFO(st.st_mode))
2184 {
2185 stype = RB_FD_PIPE;
2186 desc = "remote pipe";
2187 }
2188 else if(S_ISREG(st.st_mode))
2189 {
2190 stype = RB_FD_FILE;
2191 desc = "remote file";
2192 }
2193 }
2194 xF[x] = rb_open(fd, stype, desc);
2195 }
3202e249
VY
2196 }
2197 else
db137867 2198 *xF = NULL;
3202e249 2199 return len;
db137867
AC
2200}
2201
2202
2203int
3202e249 2204rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid)
db137867
AC
2205{
2206 int n;
2207 struct msghdr msg;
2208 struct cmsghdr *cmsg;
2209 struct iovec iov[1];
2210 char empty = '0';
2211 char *buf;
2212
2213 memset(&msg, 0, sizeof(&msg));
2214 if(datasize == 0)
2215 {
2216 iov[0].iov_base = &empty;
3202e249
VY
2217 iov[0].iov_len = 1;
2218 }
2219 else
2220 {
db137867
AC
2221 iov[0].iov_base = data;
2222 iov[0].iov_len = datasize;
2223 }
2224 msg.msg_iov = iov;
2225 msg.msg_iovlen = 1;
2226 msg.msg_name = NULL;
2227 msg.msg_namelen = 0;
2228 msg.msg_flags = 0;
2229 msg.msg_control = NULL;
2230 msg.msg_controllen = 0;
2231
2232 if(count > 0)
2233 {
2234 int i;
2235 int len = CMSG_SPACE(sizeof(int) * count);
2236 buf = alloca(len);
2237
2238 msg.msg_control = buf;
2239 msg.msg_controllen = len;
2240 cmsg = CMSG_FIRSTHDR(&msg);
2241 cmsg->cmsg_level = SOL_SOCKET;
2242 cmsg->cmsg_type = SCM_RIGHTS;
2243 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * count);
2244
2245 for(i = 0; i < count; i++)
3202e249
VY
2246 {
2247 ((int *)CMSG_DATA(cmsg))[i] = rb_get_fd(F[i]);
db137867
AC
2248 }
2249 msg.msg_controllen = cmsg->cmsg_len;
2250 }
2251 n = sendmsg(rb_get_fd(xF), &msg, MSG_NOSIGNAL);
2252 return n;
2253}
3202e249
VY
2254#else
2255#ifndef _WIN32
2256int
2257rb_recv_fd_buf(rb_fde_t *F, void *data, size_t datasize, rb_fde_t **xF, int nfds)
2258{
2259 errno = ENOSYS;
2260 return -1;
2261}
db137867 2262
3202e249
VY
2263int
2264rb_send_fd_buf(rb_fde_t *xF, rb_fde_t **F, int count, void *data, size_t datasize, pid_t pid)
2265{
2266 errno = ENOSYS;
2267 return -1;
2268}
2269#endif
2270#endif