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