2 * ircd-ratbox: A slightly useful ircd.
3 * commio.c: Network/file related functions
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
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.
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.
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
26 #include <librb_config.h>
28 #include <commio-int.h>
29 #include <commio-ssl.h>
30 #include <event-int.h>
35 #define MSG_NOSIGNAL 0
48 rb_dlink_list
*rb_fd_table
;
49 static rb_bh
*fd_heap
;
51 static rb_dlink_list timeout_list
;
52 static rb_dlink_list closed_list
;
60 static rb_dlink_list defer_list
;
62 static struct ev_entry
*rb_timeout_ev
;
65 static const char *rb_err_str
[] = { "Comm OK", "Error during bind()",
66 "Error during DNS lookup", "connect timeout",
67 "Error during connect()",
72 /* Highest FD and number of open FDs .. */
73 static int number_fd
= 0;
74 int rb_maxconnections
= 0;
76 static PF rb_connect_timeout
;
77 static PF rb_connect_outcome
;
78 static void mangle_mapped_sockaddr(struct sockaddr
*in
);
80 static inline rb_fde_t
*
83 rb_fde_t
*F
= rb_find_fd(fd
);
85 /* look up to see if we have it already */
89 F
= rb_bh_alloc(fd_heap
);
91 rb_dlinkAdd(F
, &F
->node
, &rb_fd_table
[rb_hash_fd(fd
)]);
96 remove_fd(rb_fde_t
*F
)
98 if(F
== NULL
|| !IsFDOpen(F
))
101 rb_dlinkMoveNode(&F
->node
, &rb_fd_table
[rb_hash_fd(F
->fd
)], &closed_list
);
105 rb_close_pending_fds(void)
108 rb_dlink_node
*ptr
, *next
;
109 RB_DLINK_FOREACH_SAFE(ptr
, next
, closed_list
.head
)
115 rb_dlinkDelete(ptr
, &closed_list
);
116 rb_bh_free(fd_heap
, F
);
120 /* close_all_connections() can be used *before* the system come up! */
127 /* XXX someone tell me why we care about 4 fd's ? */
128 /* XXX btw, fd 3 is used for profiler ! */
129 for(i
= 3; i
< rb_maxconnections
; ++i
)
136 * get_sockerr - get the error value from the socket or the current errno
138 * Get the *real* error from the socket (well try to anyway..).
139 * This may only work when SO_DEBUG is enabled but its worth the
143 rb_get_sockerr(rb_fde_t
*F
)
147 rb_socklen_t len
= sizeof(err
);
149 if(!(F
->type
& RB_FD_SOCKET
))
155 && !getsockopt(rb_get_fd(F
), SOL_SOCKET
, SO_ERROR
, (char *)&err
, (rb_socklen_t
*) & len
))
166 * rb_getmaxconnect - return the max number of connections allowed
169 rb_getmaxconnect(void)
171 return (rb_maxconnections
);
175 * set_sock_buffers - set send and receive buffers for socket
177 * inputs - fd file descriptor
179 * output - returns true (1) if successful, false (0) otherwise
183 rb_set_buffers(rb_fde_t
*F
, int size
)
188 (F
->fd
, SOL_SOCKET
, SO_RCVBUF
, (char *)&size
, sizeof(size
))
189 || setsockopt(F
->fd
, SOL_SOCKET
, SO_SNDBUF
, (char *)&size
, sizeof(size
)))
195 * set_non_blocking - Set the client connection into non-blocking mode.
197 * inputs - fd to set into non blocking mode
198 * output - 1 if successful 0 if not
199 * side effects - use POSIX compliant non blocking and
203 rb_set_nb(rb_fde_t
*F
)
212 if((res
= rb_setup_fd(F
)))
216 res
= fcntl(fd
, F_GETFL
, 0);
217 if(-1 == res
|| fcntl(fd
, F_SETFL
, res
| nonb
) == -1)
222 if(ioctl(fd
, FIONBIO
, (char *)&nonb
) == -1)
230 rb_set_cloexec(rb_fde_t
*F
)
238 res
= fcntl(fd
, F_GETFD
, NULL
);
241 if(fcntl(fd
, F_SETFD
, res
| FD_CLOEXEC
) == -1)
248 rb_clear_cloexec(rb_fde_t
*F
)
256 res
= fcntl(fd
, F_GETFD
, NULL
);
259 if(fcntl(fd
, F_SETFD
, res
& ~FD_CLOEXEC
) == -1)
266 * rb_settimeout() - set the socket timeout
268 * Set the timeout for the fd
271 rb_settimeout(rb_fde_t
*F
, time_t timeout
, PF
* callback
, void *cbdata
)
273 struct timeout_data
*td
;
278 lrb_assert(IsFDOpen(F
));
280 if(callback
== NULL
) /* user wants to remove */
284 rb_dlinkDelete(&td
->node
, &timeout_list
);
287 if(rb_dlink_list_length(&timeout_list
) == 0)
289 rb_event_delete(rb_timeout_ev
);
290 rb_timeout_ev
= NULL
;
295 if(F
->timeout
== NULL
)
296 td
= F
->timeout
= rb_malloc(sizeof(struct timeout_data
));
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
)
305 rb_timeout_ev
= rb_event_add("rb_checktimeouts", rb_checktimeouts
, NULL
, 5);
310 * rb_checktimeouts() - check the socket timeouts
312 * All this routine does is call the given callback/cbdata, without closing
313 * down the file descriptor. When close handlers have been implemented,
317 rb_checktimeouts(void *notused
__attribute__((unused
)))
319 rb_dlink_node
*ptr
, *next
;
320 struct timeout_data
*td
;
325 RB_DLINK_FOREACH_SAFE(ptr
, next
, timeout_list
.head
)
329 if(F
== NULL
|| !IsFDOpen(F
))
332 if(td
->timeout
< rb_current_time())
334 hdl
= td
->timeout_handler
;
335 data
= td
->timeout_data
;
336 rb_dlinkDelete(&td
->node
, &timeout_list
);
345 rb_setsockopt_reuseaddr(rb_fde_t
*F
)
350 ret
= setsockopt(F
->fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt_one
, sizeof(opt_one
));
352 rb_lib_log("rb_setsockopt_reuseaddr: Cannot set SO_REUSEADDR for FD %d: %s",
353 F
->fd
, strerror(rb_get_sockerr(F
)));
362 rb_setsockopt_sctp(rb_fde_t
*F
)
366 /* workaround for https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/net/sctp?id=299ee123e19889d511092347f5fc14db0f10e3a6 */
367 char *env_mapped
= getenv("SCTP_I_WANT_MAPPED_V4_ADDR");
368 int opt_mapped
= env_mapped
!= NULL
? atoi(env_mapped
) : opt_zero
;
370 struct sctp_initmsg initmsg
;
371 struct sctp_rtoinfo rtoinfo
;
372 struct sctp_paddrparams paddrparams
;
373 struct sctp_assocparams assocparams
;
375 ret
= setsockopt(F
->fd
, IPPROTO_SCTP
, SCTP_NODELAY
, &opt_one
, sizeof(opt_one
));
377 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_NODELAY for fd %d: %s",
378 F
->fd
, strerror(rb_get_sockerr(F
)));
382 ret
= setsockopt(F
->fd
, IPPROTO_SCTP
, SCTP_I_WANT_MAPPED_V4_ADDR
, &opt_mapped
, sizeof(opt_mapped
));
384 rb_lib_log("rb_setsockopt_sctp: Cannot unset SCTP_I_WANT_MAPPED_V4_ADDR for fd %d: %s",
385 F
->fd
, strerror(rb_get_sockerr(F
)));
389 /* Configure INIT message to specify that we only want one stream */
390 memset(&initmsg
, 0, sizeof(initmsg
));
391 initmsg
.sinit_num_ostreams
= 1;
392 initmsg
.sinit_max_instreams
= 1;
394 ret
= setsockopt(F
->fd
, IPPROTO_SCTP
, SCTP_INITMSG
, &initmsg
, sizeof(initmsg
));
396 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_INITMSG for fd %d: %s",
397 F
->fd
, strerror(rb_get_sockerr(F
)));
401 /* Configure RTO values to reduce the maximum timeout */
402 memset(&rtoinfo
, 0, sizeof(rtoinfo
));
403 rtoinfo
.srto_initial
= 3000;
404 rtoinfo
.srto_min
= 1000;
405 rtoinfo
.srto_max
= 10000;
407 ret
= setsockopt(F
->fd
, IPPROTO_SCTP
, SCTP_RTOINFO
, &rtoinfo
, sizeof(rtoinfo
));
409 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_RTOINFO for fd %d: %s",
410 F
->fd
, strerror(rb_get_sockerr(F
)));
415 * Configure peer address parameters to ensure that we monitor the connection
416 * more often than the default and don't timeout retransmit attempts before
417 * the ping timeout does.
419 * Each peer address will timeout reachability in about 750s.
421 memset(&paddrparams
, 0, sizeof(paddrparams
));
422 paddrparams
.spp_assoc_id
= 0;
423 memcpy(&paddrparams
.spp_address
, &in6addr_any
, sizeof(in6addr_any
));
424 paddrparams
.spp_pathmaxrxt
= 50;
425 paddrparams
.spp_hbinterval
= 5000;
426 paddrparams
.spp_flags
|= SPP_HB_ENABLE
;
428 ret
= setsockopt(F
->fd
, IPPROTO_SCTP
, SCTP_PEER_ADDR_PARAMS
, &paddrparams
, sizeof(paddrparams
));
430 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_PEER_ADDR_PARAMS for fd %d: %s",
431 F
->fd
, strerror(rb_get_sockerr(F
)));
435 /* Configure association parameters for retransmit attempts as above */
436 memset(&assocparams
, 0, sizeof(assocparams
));
437 assocparams
.sasoc_assoc_id
= 0;
438 assocparams
.sasoc_asocmaxrxt
= 50;
440 ret
= setsockopt(F
->fd
, IPPROTO_SCTP
, SCTP_ASSOCINFO
, &assocparams
, sizeof(assocparams
));
442 rb_lib_log("rb_setsockopt_sctp: Cannot set SCTP_ASSOCINFO for fd %d: %s",
443 F
->fd
, strerror(rb_get_sockerr(F
)));
452 rb_bind(rb_fde_t
*F
, struct sockaddr
*addr
)
456 ret
= rb_setsockopt_reuseaddr(F
);
460 ret
= bind(F
->fd
, addr
, GET_SS_LEN(addr
));
469 rb_sctp_bindx_only(rb_fde_t
*F
, struct sockaddr_storage
*addrs
, size_t len
)
473 for (size_t i
= 0; i
< len
; i
++) {
474 if (GET_SS_FAMILY(&addrs
[i
]) == AF_UNSPEC
)
477 ret
= sctp_bindx(F
->fd
, (struct sockaddr
*)&addrs
[i
], 1, SCTP_BINDX_ADD_ADDR
);
487 rb_sctp_bindx(rb_fde_t
*F
, struct sockaddr_storage
*addrs
, size_t len
)
492 if ((F
->type
& RB_FD_SCTP
) == 0)
495 ret
= rb_setsockopt_reuseaddr(F
);
499 ret
= rb_sctp_bindx_only(F
, addrs
, len
);
510 rb_inet_get_proto(rb_fde_t
*F
)
513 if (F
->type
& RB_FD_SCTP
)
519 static void rb_accept_tryaccept(rb_fde_t
*F
, void *data
__attribute__((unused
))) {
520 struct rb_sockaddr_storage st
;
522 rb_socklen_t addrlen
;
527 memset(&st
, 0, sizeof(st
));
528 addrlen
= sizeof(st
);
530 new_fd
= accept(F
->fd
, (struct sockaddr
*)&st
, &addrlen
);
533 rb_setselect(F
, RB_SELECT_ACCEPT
, rb_accept_tryaccept
, NULL
);
537 new_F
= rb_open(new_fd
, RB_FD_SOCKET
| (F
->type
& RB_FD_INHERIT_TYPES
), "Incoming Connection");
542 ("rb_accept: new_F == NULL on incoming connection. Closing new_fd == %d",
548 if(rb_unlikely(!rb_set_nb(new_F
)))
550 rb_lib_log("rb_accept: Couldn't set FD %d non blocking!", new_F
->fd
);
554 mangle_mapped_sockaddr((struct sockaddr
*)&st
);
556 if(F
->accept
->precb
!= NULL
)
558 if(!F
->accept
->precb(new_F
, (struct sockaddr
*)&st
, addrlen
, F
->accept
->data
)) /* pre-callback decided to drop it */
562 if(F
->type
& RB_FD_SSL
)
564 rb_ssl_accept_setup(F
, new_F
, (struct sockaddr
*)&st
, addrlen
);
567 #endif /* HAVE_SSL */
569 F
->accept
->callback(new_F
, RB_OK
, (struct sockaddr
*)&st
, addrlen
,
576 /* try to accept a TCP connection */
578 rb_accept_tcp(rb_fde_t
*F
, ACPRE
* precb
, ACCB
* callback
, void *data
)
582 lrb_assert(callback
);
584 F
->accept
= rb_malloc(sizeof(struct acceptdata
));
585 F
->accept
->callback
= callback
;
586 F
->accept
->data
= data
;
587 F
->accept
->precb
= precb
;
588 rb_accept_tryaccept(F
, NULL
);
592 * void rb_connect_tcp(int fd, struct sockaddr *dest,
593 * struct sockaddr *clocal,
594 * CNCB *callback, void *data, int timeout)
595 * Input: An fd to connect with, a host and port to connect to,
596 * a local sockaddr to connect from (or NULL to use the
597 * default), a callback, the data to pass into the callback, the
600 * Side-effects: A non-blocking connection to the host is started, and
601 * if necessary, set up for selection. The callback given
602 * may be called now, or it may be called later.
605 rb_connect_tcp(rb_fde_t
*F
, struct sockaddr
*dest
,
606 struct sockaddr
*clocal
, CNCB
* callback
, void *data
, int timeout
)
613 lrb_assert(callback
);
614 F
->connect
= rb_malloc(sizeof(struct conndata
));
615 F
->connect
->callback
= callback
;
616 F
->connect
->data
= data
;
618 memcpy(&F
->connect
->hostaddr
, dest
, sizeof(F
->connect
->hostaddr
));
620 /* Note that we're using a passed sockaddr here. This is because
621 * generally you'll be bind()ing to a sockaddr grabbed from
622 * getsockname(), so this makes things easier.
623 * XXX If NULL is passed as local, we should later on bind() to the
624 * virtual host IP, for completeness.
627 if((clocal
!= NULL
) && (bind(F
->fd
, clocal
, GET_SS_LEN(clocal
)) < 0))
629 /* Failure, call the callback with RB_ERR_BIND */
630 rb_connect_callback(F
, RB_ERR_BIND
);
635 /* We have a valid IP, so we just call tryconnect */
636 /* Make sure we actually set the timeout here .. */
637 rb_settimeout(F
, timeout
, rb_connect_timeout
, NULL
);
639 retval
= connect(F
->fd
,
640 (struct sockaddr
*)&F
->connect
->hostaddr
,
641 GET_SS_LEN(&F
->connect
->hostaddr
));
645 * If we get EISCONN, then we've already connect()ed the socket,
646 * which is a good thing.
649 if (errno
== EISCONN
) {
650 rb_connect_callback(F
, RB_OK
);
651 } else if (rb_ignore_errno(errno
)) {
652 /* Ignore error? Reschedule */
653 rb_setselect(F
, RB_SELECT_CONNECT
, rb_connect_outcome
, NULL
);
655 /* Error? Fail with RB_ERR_CONNECT */
656 rb_connect_callback(F
, RB_ERR_CONNECT
);
660 /* If we get here, we've succeeded, so call with RB_OK */
661 rb_connect_callback(F
, RB_OK
);
665 rb_connect_sctp(rb_fde_t
*F
, struct sockaddr_storage
*dest
, size_t dest_len
,
666 struct sockaddr_storage
*clocal
, size_t clocal_len
,
667 CNCB
*callback
, void *data
, int timeout
)
670 uint8_t packed_dest
[sizeof(struct sockaddr_storage
) * dest_len
];
671 uint8_t *p
= &packed_dest
[0];
678 lrb_assert(callback
);
679 F
->connect
= rb_malloc(sizeof(struct conndata
));
680 F
->connect
->callback
= callback
;
681 F
->connect
->data
= data
;
683 if ((F
->type
& RB_FD_SCTP
) == 0) {
684 rb_connect_callback(F
, RB_ERR_CONNECT
);
688 for (size_t i
= 0; i
< dest_len
; i
++) {
689 if (GET_SS_FAMILY(&dest
[i
]) == AF_INET6
) {
690 memcpy(p
, &dest
[i
], sizeof(struct sockaddr_in6
));
692 p
+= sizeof(struct sockaddr_in6
);
693 } else if (GET_SS_FAMILY(&dest
[i
]) == AF_INET
) {
694 memcpy(p
, &dest
[i
], sizeof(struct sockaddr_in
));
696 p
+= sizeof(struct sockaddr_in
);
701 memcpy(&F
->connect
->hostaddr
, &dest
[0], sizeof(F
->connect
->hostaddr
));
703 if ((clocal_len
> 0) && (rb_sctp_bindx_only(F
, clocal
, clocal_len
) < 0)) {
704 /* Failure, call the callback with RB_ERR_BIND */
705 rb_connect_callback(F
, RB_ERR_BIND
);
710 rb_settimeout(F
, timeout
, rb_connect_timeout
, NULL
);
712 retval
= sctp_connectx(F
->fd
, (struct sockaddr
*)packed_dest
, dest_len
, NULL
);
716 * If we get EISCONN, then we've already connect()ed the socket,
717 * which is a good thing.
720 if (errno
== EISCONN
) {
721 rb_connect_callback(F
, RB_OK
);
722 } else if (rb_ignore_errno(errno
)) {
723 /* Ignore error? Reschedule */
724 rb_setselect(F
, RB_SELECT_CONNECT
, rb_connect_outcome
, NULL
);
726 /* Error? Fail with RB_ERR_CONNECT */
727 rb_connect_callback(F
, RB_ERR_CONNECT
);
731 /* If we get here, we've succeeded, so call with RB_OK */
732 rb_connect_callback(F
, RB_OK
);
734 rb_connect_callback(F
, RB_ERR_CONNECT
);
739 * rb_connect_callback() - call the callback, and continue with life
742 rb_connect_callback(rb_fde_t
*F
, int status
)
746 int errtmp
= errno
; /* save errno as rb_settimeout clobbers it sometimes */
748 /* This check is gross..but probably necessary */
749 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
751 /* Clear the connect flag + handler */
752 hdl
= F
->connect
->callback
;
753 data
= F
->connect
->data
;
754 F
->connect
->callback
= NULL
;
757 /* Clear the timeout handler */
758 rb_settimeout(F
, 0, NULL
, NULL
);
760 /* Call the handler */
761 hdl(F
, status
, data
);
766 * rb_connect_timeout() - this gets called when the socket connection
767 * times out. This *only* can be called once connect() is initially
771 rb_connect_timeout(rb_fde_t
*F
, void *notused
__attribute__((unused
)))
774 rb_connect_callback(F
, RB_ERR_TIMEOUT
);
778 rb_connect_outcome(rb_fde_t
*F
, void *notused
__attribute__((unused
)))
782 socklen_t len
= sizeof(err
);
784 if(F
== NULL
|| F
->connect
== NULL
|| F
->connect
->callback
== NULL
)
786 retval
= getsockopt(F
->fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
);
787 if ((retval
>= 0) && (err
!= 0)) {
792 /* Error? Fail with RB_ERR_CONNECT */
793 rb_connect_callback(F
, RB_ERR_CONNECT
);
796 /* If we get here, we've succeeded, so call with RB_OK */
797 rb_connect_callback(F
, RB_OK
);
802 rb_connect_sockaddr(rb_fde_t
*F
, struct sockaddr
*addr
, int len
)
807 memcpy(addr
, &F
->connect
->hostaddr
, len
);
812 * rb_error_str() - return an error string for the given error condition
817 if(error
< 0 || error
>= RB_ERR_MAX
)
818 return "Invalid error number!";
819 return rb_err_str
[error
];
824 rb_socketpair(int family
, int sock_type
, int proto
, rb_fde_t
**F1
, rb_fde_t
**F2
, const char *note
)
827 if(number_fd
>= rb_maxconnections
)
833 if(socketpair(family
, sock_type
, proto
, nfd
))
836 *F1
= rb_open(nfd
[0], RB_FD_SOCKET
, note
);
837 *F2
= rb_open(nfd
[1], RB_FD_SOCKET
, note
);
852 /* Set the socket non-blocking, and other wonderful bits */
853 if(rb_unlikely(!rb_set_nb(*F1
)))
855 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[0], strerror(errno
));
861 if(rb_unlikely(!rb_set_nb(*F2
)))
863 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", nfd
[1], strerror(errno
));
874 rb_pipe(rb_fde_t
**F1
, rb_fde_t
**F2
, const char *desc
)
877 if(number_fd
>= rb_maxconnections
)
884 *F1
= rb_open(fd
[0], RB_FD_PIPE
, desc
);
885 *F2
= rb_open(fd
[1], RB_FD_PIPE
, desc
);
887 if(rb_unlikely(!rb_set_nb(*F1
)))
889 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[0], strerror(errno
));
895 if(rb_unlikely(!rb_set_nb(*F2
)))
897 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
[1], strerror(errno
));
908 * rb_socket() - open a socket
910 * This is a highly highly cut down version of squid's rb_open() which
911 * for the most part emulates socket(), *EXCEPT* it fails if we're about
912 * to run out of file descriptors.
915 rb_socket(int family
, int sock_type
, int proto
, const char *note
)
919 /* First, make sure we aren't going to run out of file descriptors */
920 if(rb_unlikely(number_fd
>= rb_maxconnections
))
927 * Next, we try to open the socket. We *should* drop the reserved FD
928 * limit if/when we get an error, but we can deal with that later.
931 fd
= socket(family
, sock_type
, proto
);
932 if(rb_unlikely(fd
< 0))
933 return NULL
; /* errno will be passed through, yay.. */
936 * Make sure we can take both IPv4 and IPv6 connections
937 * on an AF_INET6 SCTP socket, otherwise keep them separate
939 if(family
== AF_INET6
)
942 int v6only
= (proto
== IPPROTO_SCTP
) ? 0 : 1;
946 if(setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (void *) &v6only
, sizeof(v6only
)) == -1)
948 rb_lib_log("rb_socket: Could not set IPV6_V6ONLY option to %d on FD %d: %s",
949 v6only
, fd
, strerror(errno
));
955 F
= rb_open(fd
, RB_FD_SOCKET
, note
);
958 rb_lib_log("rb_socket: rb_open returns NULL on FD %d: %s, closing fd", fd
,
965 if (proto
== IPPROTO_SCTP
) {
966 F
->type
|= RB_FD_SCTP
;
968 if (rb_setsockopt_sctp(F
)) {
969 rb_lib_log("rb_socket: Could not set SCTP socket options on FD %d: %s",
970 fd
, strerror(errno
));
977 /* Set the socket non-blocking, and other wonderful bits */
978 if(rb_unlikely(!rb_set_nb(F
)))
980 rb_lib_log("rb_open: Couldn't set FD %d non blocking: %s", fd
, strerror(errno
));
989 * If a sockaddr_storage is AF_INET6 but is a mapped IPv4
990 * socket manged the sockaddr.
993 mangle_mapped_sockaddr(struct sockaddr
*in
)
995 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)in
;
997 if(in
->sa_family
== AF_INET6
&& IN6_IS_ADDR_V4MAPPED(&in6
->sin6_addr
))
999 struct sockaddr_in in4
;
1000 memset(&in4
, 0, sizeof(struct sockaddr_in
));
1001 in4
.sin_family
= AF_INET
;
1002 in4
.sin_port
= in6
->sin6_port
;
1003 in4
.sin_addr
.s_addr
= ((uint32_t *)&in6
->sin6_addr
)[3];
1004 memcpy(in
, &in4
, sizeof(struct sockaddr_in
));
1009 * rb_listen() - listen on a port
1012 rb_listen(rb_fde_t
*F
, int backlog
, int defer_accept
)
1016 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| (F
->type
& RB_FD_INHERIT_TYPES
);
1017 result
= listen(F
->fd
, backlog
);
1019 #ifdef TCP_DEFER_ACCEPT
1020 if (defer_accept
&& !result
)
1022 (void)setsockopt(F
->fd
, IPPROTO_TCP
, TCP_DEFER_ACCEPT
, &backlog
, sizeof(int));
1025 #ifdef SO_ACCEPTFILTER
1026 if (defer_accept
&& !result
)
1028 struct accept_filter_arg afa
;
1030 memset(&afa
, '\0', sizeof afa
);
1031 rb_strlcpy(afa
.af_name
, "dataready", sizeof afa
.af_name
);
1032 (void)setsockopt(F
->fd
, SOL_SOCKET
, SO_ACCEPTFILTER
, &afa
,
1041 rb_fdlist_init(int closeall
, int maxfds
, size_t heapsize
)
1043 static int initialized
= 0;
1047 rb_maxconnections
= maxfds
;
1050 /* Since we're doing this once .. */
1053 fd_heap
= rb_bh_create(sizeof(rb_fde_t
), heapsize
, "librb_fd_heap");
1058 /* Called to open a given filedescriptor */
1060 rb_open(int fd
, uint8_t type
, const char *desc
)
1063 lrb_assert(fd
>= 0);
1067 lrb_assert(!IsFDOpen(F
));
1068 if(rb_unlikely(IsFDOpen(F
)))
1071 if(F
!= NULL
&& F
->desc
!= NULL
)
1075 rb_lib_log("Trying to rb_open an already open FD: %d desc: %s", fd
, fdesc
);
1083 F
->desc
= rb_strndup(desc
, FD_DESC_SZ
);
1089 /* Called to close a given filedescriptor */
1091 rb_close(rb_fde_t
*F
)
1100 lrb_assert(IsFDOpen(F
));
1102 lrb_assert(!(type
& RB_FD_FILE
));
1103 if(rb_unlikely(type
& RB_FD_FILE
))
1105 lrb_assert(F
->read_handler
== NULL
);
1106 lrb_assert(F
->write_handler
== NULL
);
1109 if (type
& RB_FD_LISTEN
) {
1113 rb_setselect(F
, RB_SELECT_WRITE
| RB_SELECT_READ
, NULL
, NULL
);
1114 rb_settimeout(F
, 0, NULL
, NULL
);
1116 rb_free(F
->connect
);
1119 if(type
& RB_FD_SSL
)
1123 #endif /* HAVE_SSL */
1130 if(type
& RB_FD_LISTEN
)
1131 shutdown(fd
, SHUT_RDWR
);
1136 * rb_dump_fd() - dump the list of active filedescriptors
1139 rb_dump_fd(DUMPCB
* cb
, void *data
)
1141 static const char *empty
= "";
1143 rb_dlink_list
*bucket
;
1147 for(i
= 0; i
< RB_FD_HASH_SIZE
; i
++)
1149 bucket
= &rb_fd_table
[i
];
1151 if(rb_dlink_list_length(bucket
) <= 0)
1154 RB_DLINK_FOREACH(ptr
, bucket
->head
)
1157 if(F
== NULL
|| !IsFDOpen(F
))
1160 cb(F
->fd
, F
->desc
? F
->desc
: empty
, data
);
1166 * rb_note() - set the fd note
1168 * Note: must be careful not to overflow rb_fd_table[fd].desc when
1172 rb_note(rb_fde_t
*F
, const char *string
)
1178 F
->desc
= rb_strndup(string
, FD_DESC_SZ
);
1182 rb_set_type(rb_fde_t
*F
, uint8_t type
)
1184 /* if the caller is calling this, lets assume they have a clue */
1190 rb_get_type(rb_fde_t
*F
)
1196 rb_fd_ssl(rb_fde_t
*F
)
1200 if(F
->type
& RB_FD_SSL
)
1206 rb_get_fd(rb_fde_t
*F
)
1216 return rb_find_fd(fd
);
1220 rb_read(rb_fde_t
*F
, void *buf
, int count
)
1226 /* This needs to be *before* RB_FD_SOCKET otherwise you'll process
1227 * an SSL socket as a regular socket
1230 if(F
->type
& RB_FD_SSL
)
1232 return rb_ssl_read(F
, buf
, count
);
1235 if(F
->type
& RB_FD_SOCKET
)
1237 ret
= recv(F
->fd
, buf
, count
, 0);
1243 return read(F
->fd
, buf
, count
);
1248 rb_write(rb_fde_t
*F
, const void *buf
, int count
)
1255 if(F
->type
& RB_FD_SSL
)
1257 return rb_ssl_write(F
, buf
, count
);
1260 if(F
->type
& RB_FD_SOCKET
)
1262 ret
= send(F
->fd
, buf
, count
, MSG_NOSIGNAL
);
1266 return write(F
->fd
, buf
, count
);
1271 rb_fake_writev(rb_fde_t
*F
, const struct rb_iovec
*vp
, size_t vpcount
)
1275 while(vpcount
-- > 0)
1277 ssize_t written
= rb_write(F
, vp
->iov_base
, vp
->iov_len
);
1294 rb_writev(rb_fde_t
*F
, struct rb_iovec
* vector
, int count
)
1302 if(F
->type
& RB_FD_SSL
)
1304 return rb_fake_writev(F
, vector
, count
);
1306 #endif /* HAVE_SSL */
1307 if(F
->type
& RB_FD_SOCKET
)
1310 memset(&msg
, 0, sizeof(msg
));
1311 msg
.msg_iov
= (struct iovec
*)vector
;
1312 msg
.msg_iovlen
= count
;
1313 return sendmsg(F
->fd
, &msg
, MSG_NOSIGNAL
);
1315 return writev(F
->fd
, (struct iovec
*)vector
, count
);
1320 * From: Thomas Helvey <tomh@inxpress.net>
1322 static const char *IpQuadTab
[] = {
1323 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
1324 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
1325 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
1326 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
1327 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
1328 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
1329 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
1330 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
1331 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
1332 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
1333 "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
1334 "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
1335 "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
1336 "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
1337 "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
1338 "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
1339 "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
1340 "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
1341 "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
1342 "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
1343 "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
1344 "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
1345 "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
1346 "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
1347 "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
1348 "250", "251", "252", "253", "254", "255"
1352 * inetntoa - in_addr to string
1353 * changed name to remove collision possibility and
1354 * so behaviour is guaranteed to take a pointer arg.
1356 * inet_ntoa -- returned the dotted notation of a given
1359 * inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon
1363 inetntoa(const char *in
)
1365 static char buf
[16];
1367 const unsigned char *a
= (const unsigned char *)in
;
1370 n
= IpQuadTab
[*a
++];
1374 n
= IpQuadTab
[*a
++];
1378 n
= IpQuadTab
[*a
++];
1390 * WARNING: Don't even consider trying to compile this on a system where
1391 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1394 static const char *inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
);
1395 static const char *inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
);
1398 * inet_ntop4(src, dst, size)
1399 * format an IPv4 address
1401 * `dst' (as a const)
1403 * (1) uses no statics
1404 * (2) takes a unsigned char* not an in_addr as input
1409 inet_ntop4(const unsigned char *src
, char *dst
, unsigned int size
)
1413 return strcpy(dst
, inetntoa((const char *)src
));
1417 * inet_ntop6(src, dst, size)
1418 * convert IPv6 binary address into presentation (printable) format
1423 inet_ntop6(const unsigned char *src
, char *dst
, unsigned int size
)
1426 * Note that int32_t and int16_t need only be "at least" large enough
1427 * to contain a value of the specified size. On some systems, like
1428 * Crays, there is no such thing as an integer variable with 16 bits.
1429 * Keep this in mind if you think this function should have been coded
1430 * to use pointer overlays. All the world's not a VAX.
1432 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
1438 unsigned int words
[IN6ADDRSZ
/ INT16SZ
];
1443 * Copy the input (bytewise) array into a wordwise array.
1444 * Find the longest run of 0x00's in src[] for :: shorthanding.
1446 memset(words
, '\0', sizeof words
);
1447 for(i
= 0; i
< IN6ADDRSZ
; i
+= 2)
1448 words
[i
/ 2] = (src
[i
] << 8) | src
[i
+ 1];
1453 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1458 cur
.base
= i
, cur
.len
= 1;
1466 if(best
.base
== -1 || cur
.len
> best
.len
)
1474 if(best
.base
== -1 || cur
.len
> best
.len
)
1477 if(best
.base
!= -1 && best
.len
< 2)
1481 * Format the result.
1484 for(i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++)
1486 /* Are we inside the best run of 0x00's? */
1487 if(best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
))
1497 /* Are we following an initial run of 0x00s or any real hex? */
1500 /* Is this address an encapsulated IPv4? */
1501 if(i
== 6 && best
.base
== 0 &&
1502 (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff)))
1504 if(!inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
1509 tp
+= sprintf(tp
, "%x", words
[i
]);
1511 /* Was it a trailing run of 0x00's? */
1512 if(best
.base
!= -1 && (best
.base
+ best
.len
) == (IN6ADDRSZ
/ INT16SZ
))
1517 * Check for overflow, copy, and we're done.
1520 if((unsigned int)(tp
- tmp
) > size
)
1524 return memcpy(dst
, tmp
, tp
- tmp
);
1528 rb_inet_pton_sock(const char *src
, struct sockaddr_storage
*dst
)
1530 memset(dst
, 0, sizeof(*dst
));
1531 if(rb_inet_pton(AF_INET
, src
, &((struct sockaddr_in
*)dst
)->sin_addr
))
1533 SET_SS_FAMILY(dst
, AF_INET
);
1534 SET_SS_PORT(dst
, 0);
1535 SET_SS_LEN(dst
, sizeof(struct sockaddr_in
));
1538 else if(rb_inet_pton(AF_INET6
, src
, &((struct sockaddr_in6
*)dst
)->sin6_addr
))
1540 SET_SS_FAMILY(dst
, AF_INET6
);
1541 SET_SS_PORT(dst
, 0);
1542 SET_SS_LEN(dst
, sizeof(struct sockaddr_in6
));
1549 rb_inet_ntop_sock(struct sockaddr
*src
, char *dst
, unsigned int size
)
1551 switch (src
->sa_family
)
1554 return (rb_inet_ntop(AF_INET
, &((struct sockaddr_in
*)src
)->sin_addr
, dst
, size
));
1556 return (rb_inet_ntop
1557 (AF_INET6
, &((struct sockaddr_in6
*)src
)->sin6_addr
, dst
, size
));
1564 * rb_inet_ntop(af, src, dst, size)
1565 * convert a network format address to presentation format.
1567 * pointer to presentation format address (`dst'), or NULL (see errno).
1572 rb_inet_ntop(int af
, const void *src
, char *dst
, unsigned int size
)
1577 return (inet_ntop4(src
, dst
, size
));
1579 if(IN6_IS_ADDR_V4MAPPED((const struct in6_addr
*)src
) ||
1580 IN6_IS_ADDR_V4COMPAT((const struct in6_addr
*)src
))
1582 ((const unsigned char *)&((const struct in6_addr
*)src
)->
1583 s6_addr
[12], dst
, size
));
1585 return (inet_ntop6(src
, dst
, size
));
1593 * WARNING: Don't even consider trying to compile this on a system where
1594 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
1598 * rb_inet_pton(af, src, dst)
1599 * convert from presentation format (which usually means ASCII printable)
1600 * to network format (which is usually some kind of binary format).
1602 * 1 if the address was valid for the specified address family
1603 * 0 if the address wasn't valid (`dst' is untouched in this case)
1604 * -1 if some other error occurred (`dst' is untouched in this case, too)
1610 * inet_pton4(src, dst)
1611 * like inet_aton() but without all the hexadecimal and shorthand.
1613 * 1 if `src' is a valid dotted quad, else 0.
1615 * does not touch `dst' unless it's returning 1.
1620 inet_pton4(const char *src
, unsigned char *dst
)
1622 int saw_digit
, octets
, ch
;
1623 unsigned char tmp
[INADDRSZ
], *tp
;
1628 while((ch
= *src
++) != '\0')
1631 if(ch
>= '0' && ch
<= '9')
1633 unsigned int new = *tp
* 10 + (ch
- '0');
1645 else if(ch
== '.' && saw_digit
)
1657 memcpy(dst
, tmp
, INADDRSZ
);
1662 * inet_pton6(src, dst)
1663 * convert presentation level address to network order binary form.
1665 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
1667 * (1) does not touch `dst' unless it's returning 1.
1668 * (2) :: in a full address is silently ignored.
1670 * inspired by Mark Andrews.
1676 inet_pton6(const char *src
, unsigned char *dst
)
1678 static const char xdigits
[] = "0123456789abcdef";
1679 unsigned char tmp
[IN6ADDRSZ
], *tp
, *endp
, *colonp
;
1684 tp
= memset(tmp
, '\0', IN6ADDRSZ
);
1685 endp
= tp
+ IN6ADDRSZ
;
1687 /* Leading :: requires some special handling. */
1694 while((ch
= tolower((unsigned char)*src
++)) != '\0')
1698 pch
= strchr(xdigits
, ch
);
1702 val
|= (pch
- xdigits
);
1718 else if(*src
== '\0')
1722 if(tp
+ INT16SZ
> endp
)
1724 *tp
++ = (unsigned char)(val
>> 8) & 0xff;
1725 *tp
++ = (unsigned char)val
& 0xff;
1730 if(*src
!= '\0' && ch
== '.')
1732 if(((tp
+ INADDRSZ
) <= endp
) && inet_pton4(curtok
, tp
) > 0)
1736 break; /* '\0' was seen by inet_pton4(). */
1745 if(tp
+ INT16SZ
> endp
)
1747 *tp
++ = (unsigned char)(val
>> 8) & 0xff;
1748 *tp
++ = (unsigned char)val
& 0xff;
1753 * Since some memmove()'s erroneously fail to handle
1754 * overlapping regions, we'll do the shift by hand.
1756 const int n
= tp
- colonp
;
1761 for(i
= 1; i
<= n
; i
++)
1763 endp
[-i
] = colonp
[n
- i
];
1770 memcpy(dst
, tmp
, IN6ADDRSZ
);
1775 rb_inet_pton(int af
, const char *src
, void *dst
)
1780 return (inet_pton4(src
, dst
));
1782 /* Somebody might have passed as an IPv4 address this is sick but it works */
1783 if(inet_pton4(src
, dst
))
1785 char tmp
[HOSTIPLEN
];
1786 sprintf(tmp
, "::ffff:%s", src
);
1787 return (inet_pton6(tmp
, dst
));
1790 return (inet_pton6(src
, dst
));
1798 static void (*setselect_handler
) (rb_fde_t
*, unsigned int, PF
*, void *);
1799 static int (*select_handler
) (long);
1800 static int (*setup_fd_handler
) (rb_fde_t
*);
1801 static int (*io_sched_event
) (struct ev_entry
*, int);
1802 static void (*io_unsched_event
) (struct ev_entry
*);
1803 static int (*io_supports_event
) (void);
1804 static void (*io_init_event
) (void);
1805 static char iotype
[25];
1814 rb_unsupported_event(void)
1822 if(!rb_init_netio_kqueue())
1824 setselect_handler
= rb_setselect_kqueue
;
1825 select_handler
= rb_select_kqueue
;
1826 setup_fd_handler
= rb_setup_fd_kqueue
;
1827 io_sched_event
= rb_kqueue_sched_event
;
1828 io_unsched_event
= rb_kqueue_unsched_event
;
1829 io_init_event
= rb_kqueue_init_event
;
1830 io_supports_event
= rb_kqueue_supports_event
;
1831 rb_strlcpy(iotype
, "kqueue", sizeof(iotype
));
1840 if(!rb_init_netio_epoll())
1842 setselect_handler
= rb_setselect_epoll
;
1843 select_handler
= rb_select_epoll
;
1844 setup_fd_handler
= rb_setup_fd_epoll
;
1845 io_sched_event
= rb_epoll_sched_event
;
1846 io_unsched_event
= rb_epoll_unsched_event
;
1847 io_supports_event
= rb_epoll_supports_event
;
1848 io_init_event
= rb_epoll_init_event
;
1849 rb_strlcpy(iotype
, "epoll", sizeof(iotype
));
1858 if(!rb_init_netio_ports())
1860 setselect_handler
= rb_setselect_ports
;
1861 select_handler
= rb_select_ports
;
1862 setup_fd_handler
= rb_setup_fd_ports
;
1863 io_sched_event
= rb_ports_sched_event
;
1864 io_unsched_event
= rb_ports_unsched_event
;
1865 io_init_event
= rb_ports_init_event
;
1866 io_supports_event
= rb_ports_supports_event
;
1867 rb_strlcpy(iotype
, "ports", sizeof(iotype
));
1876 if(!rb_init_netio_devpoll())
1878 setselect_handler
= rb_setselect_devpoll
;
1879 select_handler
= rb_select_devpoll
;
1880 setup_fd_handler
= rb_setup_fd_devpoll
;
1881 io_sched_event
= NULL
;
1882 io_unsched_event
= NULL
;
1883 io_init_event
= NULL
;
1884 io_supports_event
= rb_unsupported_event
;
1885 rb_strlcpy(iotype
, "devpoll", sizeof(iotype
));
1894 if(!rb_init_netio_sigio())
1896 setselect_handler
= rb_setselect_sigio
;
1897 select_handler
= rb_select_sigio
;
1898 setup_fd_handler
= rb_setup_fd_sigio
;
1899 io_sched_event
= rb_sigio_sched_event
;
1900 io_unsched_event
= rb_sigio_unsched_event
;
1901 io_supports_event
= rb_sigio_supports_event
;
1902 io_init_event
= rb_sigio_init_event
;
1904 rb_strlcpy(iotype
, "sigio", sizeof(iotype
));
1913 if(!rb_init_netio_poll())
1915 setselect_handler
= rb_setselect_poll
;
1916 select_handler
= rb_select_poll
;
1917 setup_fd_handler
= rb_setup_fd_poll
;
1918 io_sched_event
= NULL
;
1919 io_unsched_event
= NULL
;
1920 io_init_event
= NULL
;
1921 io_supports_event
= rb_unsupported_event
;
1922 rb_strlcpy(iotype
, "poll", sizeof(iotype
));
1929 rb_io_sched_event(struct ev_entry
*ev
, int when
)
1931 if(ev
== NULL
|| io_supports_event
== NULL
|| io_sched_event
== NULL
1932 || !io_supports_event())
1934 return io_sched_event(ev
, when
);
1938 rb_io_unsched_event(struct ev_entry
*ev
)
1940 if(ev
== NULL
|| io_supports_event
== NULL
|| io_unsched_event
== NULL
1941 || !io_supports_event())
1943 io_unsched_event(ev
);
1947 rb_io_supports_event(void)
1949 if(io_supports_event
== NULL
)
1951 return io_supports_event();
1955 rb_io_init_event(void)
1958 rb_event_io_register_all();
1964 char *ioenv
= getenv("LIBRB_USE_IOTYPE");
1965 rb_fd_table
= rb_malloc(RB_FD_HASH_SIZE
* sizeof(rb_dlink_list
));
1970 if(!strcmp("epoll", ioenv
))
1975 else if(!strcmp("kqueue", ioenv
))
1980 else if(!strcmp("ports", ioenv
))
1985 else if(!strcmp("poll", ioenv
))
1990 else if(!strcmp("devpoll", ioenv
))
1995 else if(!strcmp("sigio", ioenv
))
2015 rb_lib_log("rb_init_netio: Could not find any io handlers...giving up");
2021 rb_setselect(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
2023 setselect_handler(F
, type
, handler
, client_data
);
2027 rb_defer(void (*fn
)(void *), void *data
)
2029 struct defer
*defer
= rb_malloc(sizeof *defer
);
2032 rb_dlinkAdd(defer
, &defer
->node
, &defer_list
);
2036 rb_select(unsigned long timeout
)
2038 int ret
= select_handler(timeout
);
2039 rb_dlink_node
*ptr
, *next
;
2040 RB_DLINK_FOREACH_SAFE(ptr
, next
, defer_list
.head
)
2042 struct defer
*defer
= ptr
->data
;
2043 defer
->fn(defer
->data
);
2044 rb_dlinkDelete(ptr
, &defer_list
);
2047 rb_close_pending_fds();
2052 rb_setup_fd(rb_fde_t
*F
)
2055 return setup_fd_handler(F
);
2060 rb_ignore_errno(int error
)
2067 #if defined EWOULDBLOCK
2070 #if defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
2091 rb_recv_fd_buf(rb_fde_t
*F
, void *data
, size_t datasize
, rb_fde_t
**xF
, int nfds
)
2094 struct cmsghdr
*cmsg
;
2095 struct iovec iov
[1];
2097 uint8_t stype
= RB_FD_UNKNOWN
;
2099 int fd
, len
, x
, rfds
;
2101 int control_len
= CMSG_SPACE(sizeof(int) * nfds
);
2103 iov
[0].iov_base
= data
;
2104 iov
[0].iov_len
= datasize
;
2106 msg
.msg_name
= NULL
;
2107 msg
.msg_namelen
= 0;
2111 cmsg
= alloca(control_len
);
2112 msg
.msg_control
= cmsg
;
2113 msg
.msg_controllen
= control_len
;
2115 if((len
= recvmsg(rb_get_fd(F
), &msg
, 0)) <= 0)
2118 if(msg
.msg_controllen
> 0 && msg
.msg_control
!= NULL
2119 && (cmsg
= CMSG_FIRSTHDR(&msg
)) != NULL
)
2121 rfds
= ((unsigned char *)cmsg
+ cmsg
->cmsg_len
- CMSG_DATA(cmsg
)) / sizeof(int);
2123 for(x
= 0; x
< nfds
&& x
< rfds
; x
++)
2125 fd
= ((int *)CMSG_DATA(cmsg
))[x
];
2126 stype
= RB_FD_UNKNOWN
;
2127 desc
= "remote unknown";
2130 if(S_ISSOCK(st
.st_mode
))
2132 stype
= RB_FD_SOCKET
;
2133 desc
= "remote socket";
2135 else if(S_ISFIFO(st
.st_mode
))
2138 desc
= "remote pipe";
2140 else if(S_ISREG(st
.st_mode
))
2143 desc
= "remote file";
2146 xF
[x
] = rb_open(fd
, stype
, desc
);
2156 rb_send_fd_buf(rb_fde_t
*xF
, rb_fde_t
**F
, int count
, void *data
, size_t datasize
, pid_t pid
__attribute__((unused
)))
2159 struct cmsghdr
*cmsg
;
2160 struct iovec iov
[1];
2163 memset(&msg
, 0, sizeof(msg
));
2166 iov
[0].iov_base
= &empty
;
2171 iov
[0].iov_base
= data
;
2172 iov
[0].iov_len
= datasize
;
2176 msg
.msg_name
= NULL
;
2177 msg
.msg_namelen
= 0;
2179 msg
.msg_control
= NULL
;
2180 msg
.msg_controllen
= 0;
2184 size_t ucount
= (size_t)count
;
2185 int len
= CMSG_SPACE(sizeof(int) * count
);
2188 msg
.msg_control
= buf
;
2189 msg
.msg_controllen
= len
;
2190 cmsg
= CMSG_FIRSTHDR(&msg
);
2191 cmsg
->cmsg_level
= SOL_SOCKET
;
2192 cmsg
->cmsg_type
= SCM_RIGHTS
;
2193 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * count
);
2195 for(size_t i
= 0; i
< ucount
; i
++)
2197 ((int *)CMSG_DATA(cmsg
))[i
] = rb_get_fd(F
[i
]);
2199 msg
.msg_controllen
= cmsg
->cmsg_len
;
2200 return sendmsg(rb_get_fd(xF
), &msg
, MSG_NOSIGNAL
);
2202 return sendmsg(rb_get_fd(xF
), &msg
, MSG_NOSIGNAL
);
2206 rb_ipv4_from_ipv6(const struct sockaddr_in6
*restrict ip6
, struct sockaddr_in
*restrict ip4
)
2210 if (!memcmp(ip6
->sin6_addr
.s6_addr
, "\x20\x02", 2))
2212 /* 6to4 and similar */
2213 memcpy(&ip4
->sin_addr
, ip6
->sin6_addr
.s6_addr
+ 2, 4);
2215 else if (!memcmp(ip6
->sin6_addr
.s6_addr
, "\x20\x01\x00\x00", 4))
2218 for (i
= 0; i
< 4; i
++)
2219 ((uint8_t *)&ip4
->sin_addr
)[i
] = 0xFF ^
2220 ip6
->sin6_addr
.s6_addr
[12 + i
];
2224 SET_SS_LEN(ip4
, sizeof(struct sockaddr_in
));
2225 ip4
->sin_family
= AF_INET
;