25#include <freeradius-devel/bio/fd_priv.h>
26#include <freeradius-devel/bio/null.h>
33# define SOL_IP IPPROTO_IP
47# ifdef IPV6_RECVPKTINFO
48# include <linux/version.h>
49# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
50# ifdef IPV6_2292PKTINFO
51# undef IPV6_RECVPKTINFO
53# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
54# define IPV6_PKTINFO IPV6_2292PKTINFO
58# elif defined(IPV6_2292PKTINFO)
59# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
72# if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
73# define IPV6_RECVPKTINFO IPV6_PKTINFO
79# elif !defined(IPV6_PKTINFO)
80# undef IPV6_RECVPKTINFO
84#define ADDR_INIT do { \
85 addr->when = fr_time(); \
86 addr->socket.type = my->info.socket.type; \
87 addr->socket.fd = -1; \
88 addr->socket.inet.ifindex = my->info.socket.inet.ifindex; \
104 if (
my->connect.el) {
106 my->connect.el = NULL;
109 if (
my->cb.shutdown)
my->cb.shutdown(&
my->bio);
133 my->info.write_blocked =
false;
150 rcode = read(
my->info.socket.fd,
buffer, size);
187 struct sockaddr_storage sockaddr;
189#ifdef STATIC_ANALYZER
190 sockaddr = (
struct sockaddr_storage) {};
194 salen =
sizeof(sockaddr);
196 rcode = recvfrom(
my->info.socket.fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, &salen);
199 fr_assert(sockaddr.ss_family ==
my->remote_sockaddr.ss_family);
200 fr_assert((sockaddr.ss_family == AF_INET) || (sockaddr.ss_family == AF_INET6));
208 if (rcode == 0)
return rcode;
223 struct sockaddr_storage sockaddr;
226 salen =
sizeof(sockaddr);
228 rcode = recvfrom(
my->info.socket.fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, &salen);
234 addr->
socket.inet.dst_ipaddr =
my->info.socket.inet.src_ipaddr;
235 addr->
socket.inet.dst_port =
my->info.socket.inet.src_port;
241 if (rcode == 0)
return rcode;
278 rcode = write(
my->info.socket.fd,
buffer, size);
295 struct sockaddr_storage sockaddr;
306 rcode = sendto(
my->info.socket.fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, salen);
314#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
319 struct sockaddr_storage from;
322#ifdef STATIC_ANALYZER
323 from.ss_family = AF_UNSPEC;
326 memset(&
my->cbuf, 0,
sizeof(
my->cbuf));
327 memset(&
my->msgh, 0,
sizeof(
struct msghdr));
329 my->iov = (
struct iovec) {
334 my->msgh = (
struct msghdr) {
335 .msg_control =
my->cbuf,
336 .msg_controllen =
sizeof(
my->cbuf),
338 .msg_namelen =
sizeof(from),
345 rcode = recvmsg(
my->info.socket.fd, &
my->msgh, 0);
350 &from,
my->msgh.msg_namelen);
353 if (rcode == 0)
return rcode;
361#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
368 struct cmsghdr *cmsg;
373 rcode = fd_fd_recvfromto_common(
my, packet_ctx,
buffer, size);
374 if (rcode <= 0)
return rcode;
378 for (cmsg = CMSG_FIRSTHDR(&
my->msgh);
380 cmsg = CMSG_NXTHDR(&
my->msgh, cmsg)) {
384 if ((cmsg->cmsg_level ==
SOL_IP) &&
385 (cmsg->cmsg_type == IP_PKTINFO)) {
386 struct in_pktinfo *i = (
struct in_pktinfo *) CMSG_DATA(cmsg);
387 struct sockaddr_in to;
389 to.sin_addr = i->ipi_addr;
392 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in));
393 addr->
socket.inet.ifindex = i->ipi_ifindex;
399 if ((cmsg->cmsg_level == IPPROTO_IP) &&
400 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
401 struct in_addr *i = (
struct in_addr *) CMSG_DATA(cmsg);
402 struct sockaddr_in to;
406 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in));
412 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
416#elif defined(SO_TIMESTAMP)
417 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
432static
ssize_t fr_bio_fd_sendfromto4(
fr_bio_t *bio,
void *packet_ctx, const
void *
buffer,
size_t size)
436 struct cmsghdr *cmsg;
437 struct sockaddr_storage to;
442 memset(&
my->cbuf, 0,
sizeof(
my->cbuf));
443 memset(&
my->msgh, 0,
sizeof(
struct msghdr));
447 my->iov = (
struct iovec) {
452 my->msgh = (
struct msghdr) {
453 .msg_control =
my->cbuf,
456 .msg_namelen = to_len,
464 struct in_pktinfo *pkt;
466 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
468 cmsg = CMSG_FIRSTHDR(&
my->msgh);
469 cmsg->cmsg_level =
SOL_IP;
470 cmsg->cmsg_type = IP_PKTINFO;
471 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
473 pkt = (
struct in_pktinfo *) CMSG_DATA(cmsg);
474 memset(pkt, 0,
sizeof(*pkt));
475 pkt->ipi_spec_dst = addr->
socket.inet.src_ipaddr.addr.v4;
476 pkt->ipi_ifindex = addr->
socket.inet.ifindex;
478#elif defined(IP_SENDSRCADDR)
481 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*
in));
483 cmsg = CMSG_FIRSTHDR(&
my->msgh);
484 cmsg->cmsg_level = IPPROTO_IP;
485 cmsg->cmsg_type = IP_SENDSRCADDR;
486 cmsg->cmsg_len = CMSG_LEN(
sizeof(*
in));
488 in = (
struct in_addr *) CMSG_DATA(cmsg);
489 *
in = addr->
socket.inet.src_ipaddr.addr.v4;
494 rcode = sendmsg(
my->info.socket.fd, &
my->msgh, 0);
501static inline int fr_bio_fd_udpfromto_init4(
int fd)
503 int proto = 0, flag = 0, opt = 1;
505#ifdef HAVE_IP_PKTINFO
512#elif defined(IP_RECVDSTADDR)
518 flag = IP_RECVDSTADDR;
521 return setsockopt(fd, proto, flag, &opt,
sizeof(opt));
525#if defined(IPV6_PKTINFO)
531 struct cmsghdr *cmsg;
536 rcode = fd_fd_recvfromto_common(
my, packet_ctx,
buffer, size);
537 if (rcode <= 0)
return rcode;
541 for (cmsg = CMSG_FIRSTHDR(&
my->msgh);
543 cmsg = CMSG_NXTHDR(&
my->msgh, cmsg)) {
546 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
547 (cmsg->cmsg_type == IPV6_PKTINFO)) {
548 struct in6_pktinfo *i = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
549 struct sockaddr_in6 to;
551 to.sin6_addr = i->ipi6_addr;
554 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in6));
555 addr->
socket.inet.ifindex = i->ipi6_ifindex;
560 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
564#elif defined(SO_TIMESTAMP)
565 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
580static
ssize_t fr_bio_fd_sendfromto6(
fr_bio_t *bio,
void *packet_ctx, const
void *
buffer,
size_t size)
584 struct cmsghdr *cmsg;
585 struct sockaddr_storage to;
590 memset(&
my->cbuf, 0,
sizeof(
my->cbuf));
591 memset(&
my->msgh, 0,
sizeof(
struct msghdr));
595 my->iov = (
struct iovec) {
600 my->msgh = (
struct msghdr) {
601 .msg_control =
my->cbuf,
604 .msg_namelen = to_len,
611 struct in6_pktinfo *pkt;
613 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
615 cmsg = CMSG_FIRSTHDR(&
my->msgh);
616 cmsg->cmsg_level = IPPROTO_IPV6;
617 cmsg->cmsg_type = IPV6_PKTINFO;
618 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
620 pkt = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
621 memset(pkt, 0,
sizeof(*pkt));
622 pkt->ipi6_addr = addr->
socket.inet.src_ipaddr.addr.v6;
623 pkt->ipi6_ifindex = addr->
socket.inet.ifindex;
627 rcode = sendmsg(
my->info.socket.fd, &
my->msgh, 0);
635static inline int fr_bio_fd_udpfromto_init6(
int fd)
639 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt,
sizeof(opt));
647 len = strlen(filename);
648 if (len >=
sizeof(sun->sun_path)) {
649 fr_strerror_const(
"Failed parsing unix domain socket filename: Name is too long");
653 sun->sun_family = AF_LOCAL;
654 memcpy(sun->sun_path, filename, len + 1);
656 *sunlen = SUN_LEN(sun);
664 struct sockaddr_storage salocal;
670 (
my->info.socket.inet.src_port != 0)) {
679 salen =
sizeof(salocal);
680 memset(&salocal, 0, salen);
681 if (getsockname(
my->info.socket.fd, (
struct sockaddr *) &salocal, &salen) < 0) {
689 my->info.socket.inet.ifindex =
my->info.socket.inet.src_ipaddr.scope_id;
697 my->info.eof =
false;
698 my->info.read_blocked =
false;
699 my->info.write_blocked =
false;
704 if (
my->cb.connected)
my->cb.connected(&
my->bio);
721 if (
my->info.socket.af != AF_LOCAL) {
723 &
my->info.socket.inet.dst_ipaddr,
my->info.socket.inet.dst_port);
726 my->info.socket.unix.path);
737 if (connect(
my->info.socket.fd, (
struct sockaddr *) &
my->remote_sockaddr,
my->remote_sockaddr_len) == 0) {
753 if (tries <= my->max_tries)
goto retry;
767 if (!
my->info.write_blocked) {
768 my->info.write_blocked =
true;
771 if (rcode < 0)
return rcode;
796 switch (
my->info.cfg->flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
844 my->info.eof =
false;
846 my->info.read_blocked =
false;
847 my->info.write_blocked =
false;
860 setsockopt(
my->info.socket.fd, SOL_SOCKET, SO_NOSIGPIPE, &on,
sizeof(on));
867 if (!
my->info.cfg->async)
return 0;
870 if (rcode == 0)
return 0;
872 if (rcode !=
fr_bio_error(IO_WOULD_BLOCK))
return rcode;
885 if (
my->info.socket.type == SOCK_STREAM) {
897#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
898 }
else if (
my->info.socket.inet.src_ipaddr.af == AF_INET) {
899 if (fr_bio_fd_udpfromto_init4(
my->info.socket.fd) < 0)
return -1;
901 my->bio.read = fr_bio_fd_recvfromto4;
902 my->bio.write = fr_bio_fd_sendfromto4;
905#if defined(IPV6_PKTINFO)
906 }
else if (
my->info.socket.inet.src_ipaddr.af == AF_INET6) {
908 if (fr_bio_fd_udpfromto_init6(
my->info.socket.fd) < 0)
return -1;
910 my->bio.read = fr_bio_fd_recvfromto6;
911 my->bio.write = fr_bio_fd_sendfromto6;
933 struct sockaddr_storage sockaddr;
935 if (size <
sizeof(
int))
return fr_bio_error(BUFFER_TOO_SMALL);
937 salen =
sizeof(sockaddr);
944 fd = accept4(
my->info.socket.fd, (
struct sockaddr *) &sockaddr, &salen, SOCK_NONBLOCK | SOCK_CLOEXEC);
946 fd = accept(
my->info.socket.fd, (
struct sockaddr *) &sockaddr, &salen);
956 addr->
socket.inet.dst_ipaddr =
my->info.socket.inet.src_ipaddr;
957 addr->
socket.inet.dst_port =
my->info.socket.inet.src_port;
970 if (tries <= my->max_tries)
goto retry;
977#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1006 if (listen(
my->info.socket.fd, 8) < 0) {
1054 if (!
my)
return NULL;
1057 my->offset = offset;
1068 .read_blocked =
false,
1069 .write_blocked =
false,
1107 if (rcode < 0)
return rcode;
1124 (void) shutdown(
my->info.socket.fd, SHUT_RDWR);
1128 rcode =
close(
my->info.socket.fd);
1134 if (tries < my->max_tries)
goto retry;
1146 my->info.read_blocked =
true;
1147 my->info.write_blocked =
true;
1148 my->info.eof =
true;
1160 my->info.connect_errno = fd_errno;
1162 if (
my->connect.error) {
1163 my->connect.error(&
my->bio);
1190 socklen_t socklen =
sizeof(error);
1205 if (getsockopt(
my->info.socket.fd, SOL_SOCKET, SO_ERROR, (
void *)&error, &socklen) < 0) {
1230 my->connect.el = NULL;
1235 my->connect.success(&
my->bio);
1247 my->connect.timeout(&
my->bio);
1281 my->info.connect_errno = ECONNABORTED;
1283 my->info.connect_errno = ECONNREFUSED;
1285 if (error_cb) error_cb(bio);
1296 if (connected_cb) connected_cb(bio);
1318 if (!connected_cb) {
1323 if (error_cb) error_cb(bio);
1338 my->connect.success = connected_cb;
1339 my->connect.error = error_cb;
1340 my->connect.timeout = timeout_cb;
1358 my->connect.el =
el;
1383 rcode = read(
my->info.socket.fd,
buffer, size);
1384 if (rcode >= 0)
return 0;
1387#define flag_blocked read_blocked
1402 rcode = read(
my->info.socket.fd,
buffer, size);
1403 if (rcode > 0 )
return 0;
1410#define flag_blocked read_blocked
1423 switch (
my->info.type) {
1428 if (
my->info.socket.type != SOCK_DGRAM) {
1432 goto set_recv_buff_zero;
1439 if (shutdown(
my->info.socket.fd, SHUT_RD) < 0) {
1454 if (setsockopt(
my->info.socket.fd, SOL_SOCKET, SO_RCVBUF, &opt,
sizeof(opt)) < 0) {
1485 struct sockaddr_storage sockaddr;
1489 salen =
sizeof(sockaddr);
1500 fd = accept4(
my->info.socket.fd, (
struct sockaddr *) &sockaddr, &salen, SOCK_NONBLOCK | SOCK_CLOEXEC);
1502 fd = accept(
my->info.socket.fd, (
struct sockaddr *) &sockaddr, &salen);
1511 if (tries <= my->max_tries)
goto retry;
1518#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1553 cfg = talloc_memdup(
out,
my->info.cfg,
sizeof(*
my->info.cfg));
1565 out->info.socket.fd = fd;
static int const char char buffer[256]
fr_bio_write_t _CONST write
write to the underlying bio
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
fr_bio_read_t _CONST read
read from the underlying bio
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
void(* fr_bio_callback_t)(fr_bio_t *bio)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define fr_event_fd_insert(...)
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
int fr_bio_fd_connect_full(fr_bio_t *bio, fr_event_list_t *el, fr_bio_callback_t connected_cb, fr_bio_callback_t error_cb, fr_time_delta_t *timeout, fr_bio_callback_t timeout_cb)
Finalize a connect()
static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
Write to fd.
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
static void fr_bio_fd_el_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, NDEBUG_UNUSED int flags, void *uctx)
Connect callback for when the socket is writable.
static int fr_bio_fd_write_resume(fr_bio_t *bio)
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
static ssize_t fr_bio_fd_read_discard_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Discard all reads from a TCP socket.
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
static ssize_t fr_bio_fd_read_connected_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Connected datagram read.
static ssize_t fr_bio_fd_try_connect(fr_bio_fd_t *my)
Try to connect().
static ssize_t fr_bio_fd_recvfrom(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read from a UDP socket where we know our IP.
static int fr_bio_fd_eof(fr_bio_t *bio)
static ssize_t fr_bio_fd_sendto(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
Write to a UDP socket where we know our IP.
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
int fr_bio_fd_init_listen(fr_bio_fd_t *my)
int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_t *bio)
Alternative to calling fr_bio_read() on new socket.
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
static ssize_t fr_bio_fd_read_accept(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Return an fd on read()
static int fr_bio_fd_init_file(fr_bio_fd_t *my)
Files are a special case of connected sockets.
static void fr_bio_fd_el_timeout(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
We have a timeout on the conenction.
static int fr_bio_fd_destructor(fr_bio_fd_t *my)
int fr_bio_fd_init_common(fr_bio_fd_t *my)
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
static ssize_t fr_bio_fd_read_discard_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Discard all reads from a UDP socket.
static void fr_bio_fd_el_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
FD error when trying to connect, give up on the BIO.
int fr_bio_fd_close(fr_bio_t *bio)
Close the FD, but leave the bio allocated and alive.
static void fr_bio_fd_set_open(fr_bio_fd_t *my)
static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Stream read.
@ FR_BIO_FD_ACCEPTED
temporarily until it's connected.
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
@ FR_BIO_FD_INVALID
not set
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
@ FR_BIO_FD_LISTEN
returns new fd in buffer on fr_bio_read() or fr_bio_fd_accept()
@ FR_BIO_FD_STATE_CONNECTING
@ FR_BIO_FD_STATE_OPEN
error states must be before this
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
Opens a socket and updates sock->fd.
fr_socket_t socket
socket information, including FD.
Configuration for sockets.
Run-time status of the socket.
#define fr_bio_fd_packet_ctx(_my, _packet_ctx)
void fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
int8_t fr_sockaddr_cmp(struct sockaddr_storage const *a, struct sockaddr_storage const *b)
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Stores all information relating to an event list.
ssize_t fr_bio_null_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Always return 0 on write.
ssize_t fr_bio_null_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always return 0 on read.
ssize_t fr_bio_fail_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always return error on read.
ssize_t fr_bio_fail_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
Always return 0 on write.
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static fr_time_t fr_time_from_timeval(struct timeval const *when_tv)
Convert a timeval (wallclock time) to a fr_time_t (internal time)
#define fr_time_wrap(_time)
#define fr_time_eq(_a, _b)
static fr_time_t fr_time_from_timespec(struct timespec const *when_ts)
Convert a timespec (wallclock time) to a fr_time_t (internal time)
A time delta, a difference in time measured in nanoseconds.
#define FR_TIMER_DELETE(_ev_p)
static fr_event_list_t * el
int fd
File descriptor if this is a live socket.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static size_t char ** out