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