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