25#include <freeradius-devel/bio/fd_priv.h>
26#include <freeradius-devel/bio/fd_read.h>
27#include <freeradius-devel/bio/fd_write.h>
28#include <freeradius-devel/bio/null.h>
35# define SOL_IP IPPROTO_IP
49# ifdef IPV6_RECVPKTINFO
50# include <linux/version.h>
51# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
52# ifdef IPV6_2292PKTINFO
53# undef IPV6_RECVPKTINFO
55# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
56# define IPV6_PKTINFO IPV6_2292PKTINFO
60# elif defined(IPV6_2292PKTINFO)
61# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
74# if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
75# define IPV6_RECVPKTINFO IPV6_PKTINFO
81# elif !defined(IPV6_PKTINFO)
82# undef IPV6_RECVPKTINFO
86#define ADDR_INIT do { \
87 addr->when = fr_time(); \
88 addr->socket.type = my->info.socket.type; \
89 addr->socket.fd = -1; \
90 addr->socket.inet.ifindex = my->info.socket.inet.ifindex; \
110 if (rcode < 0)
return rcode;
182 if (rcode < 0)
return rcode;
204 struct sockaddr_storage sockaddr;
206#ifdef STATIC_ANALYZER
207 sockaddr = (
struct sockaddr_storage) {};
211 salen =
sizeof(sockaddr);
213 rcode = recvfrom(my->
info.
socket.
fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, &salen);
217 fr_assert((sockaddr.ss_family == AF_INET) || (sockaddr.ss_family == AF_INET6));
223 if (rcode == 0)
return rcode;
245 if (
len > size)
len = size;
265 struct sockaddr_storage sockaddr;
268 salen =
sizeof(sockaddr);
270 rcode = recvfrom(my->
info.
socket.
fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, &salen);
283 if (rcode == 0)
return rcode;
335 struct sockaddr_storage sockaddr;
346 rcode = sendto(my->
info.
socket.
fd,
buffer, size, 0, (
struct sockaddr *) &sockaddr, salen);
355#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
360 struct sockaddr_storage from;
363#ifdef STATIC_ANALYZER
364 from.ss_family = AF_UNSPEC;
367 memset(&my->cbuf, 0,
sizeof(my->cbuf));
368 memset(&my->msgh, 0,
sizeof(
struct msghdr));
370 my->iov = (
struct iovec) {
375 my->msgh = (
struct msghdr) {
376 .msg_control = my->cbuf,
377 .msg_controllen =
sizeof(my->cbuf),
379 .msg_namelen =
sizeof(from),
388 if ((my->msgh.msg_flags & MSG_TRUNC) != 0)
return 0;
389 if ((my->msgh.msg_flags & MSG_CTRUNC) != 0)
return 0;
394 &from, my->msgh.msg_namelen);
397 if (rcode == 0)
return rcode;
404#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
411 struct cmsghdr *cmsg;
417 if (rcode <= 0)
return rcode;
421 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
423 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
427 if ((cmsg->cmsg_level ==
SOL_IP) &&
428 (cmsg->cmsg_type == IP_PKTINFO)) {
429 struct in_pktinfo *i = (
struct in_pktinfo *) CMSG_DATA(cmsg);
430 struct sockaddr_in to = {
431 .sin_family = AF_INET,
432 .sin_addr = i->ipi_addr,
433 .sin_port = htons(my->
info.
socket.inet.src_port),
437 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in));
438 addr->
socket.inet.ifindex = i->ipi_ifindex;
444 if ((cmsg->cmsg_level == IPPROTO_IP) &&
445 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
446 struct in_addr *i = (
struct in_addr *) CMSG_DATA(cmsg);
447 struct sockaddr_in to = {
448 .sin_family = AF_INET,
450 .sin_port = htons(my->
info.
socket.inet.src_port),
454 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in));
460 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
464#elif defined(SO_TIMESTAMP)
465 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
484 struct cmsghdr *cmsg;
485 struct sockaddr_storage to;
490 memset(&my->cbuf, 0,
sizeof(my->cbuf));
491 memset(&my->msgh, 0,
sizeof(
struct msghdr));
495 my->iov = (
struct iovec) {
500 my->msgh = (
struct msghdr) {
501 .msg_control = my->cbuf,
504 .msg_namelen = to_len,
512 struct in_pktinfo *pkt;
514 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
516 cmsg = CMSG_FIRSTHDR(&my->msgh);
517 cmsg->cmsg_level =
SOL_IP;
518 cmsg->cmsg_type = IP_PKTINFO;
519 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
521 pkt = (
struct in_pktinfo *) CMSG_DATA(cmsg);
522 memset(pkt, 0,
sizeof(*pkt));
523 pkt->ipi_spec_dst = addr->
socket.inet.src_ipaddr.addr.v4;
524 pkt->ipi_ifindex = addr->
socket.inet.ifindex;
526#elif defined(IP_SENDSRCADDR)
529 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*
in));
531 cmsg = CMSG_FIRSTHDR(&my->msgh);
532 cmsg->cmsg_level = IPPROTO_IP;
533 cmsg->cmsg_type = IP_SENDSRCADDR;
534 cmsg->cmsg_len = CMSG_LEN(
sizeof(*
in));
536 in = (
struct in_addr *) CMSG_DATA(cmsg);
537 *
in = addr->
socket.inet.src_ipaddr.addr.v4;
550static inline int fr_bio_fd_udpfromto_init4(
int fd)
552 int proto = 0, flag = 0, opt = 1;
554#ifdef HAVE_IP_PKTINFO
561#elif defined(IP_RECVDSTADDR)
567 flag = IP_RECVDSTADDR;
570 return setsockopt(fd, proto, flag, &opt,
sizeof(opt));
574#if defined(IPV6_PKTINFO)
580 struct cmsghdr *cmsg;
586 if (rcode <= 0)
return rcode;
590 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
592 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
595 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
596 (cmsg->cmsg_type == IPV6_PKTINFO)) {
597 struct in6_pktinfo *i = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
598 struct sockaddr_in6 to = {
599 .sin6_family = AF_INET6,
600 .sin6_addr = i->ipi6_addr,
601 .sin6_port = htons(my->
info.
socket.inet.src_port),
602 .sin6_scope_id = my->
info.
socket.inet.src_ipaddr.scope_id,
606 (
struct sockaddr_storage *) &to,
sizeof(
struct sockaddr_in6));
607 addr->
socket.inet.ifindex = i->ipi6_ifindex;
612 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
616#elif defined(SO_TIMESTAMP)
617 if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
636 struct cmsghdr *cmsg;
637 struct sockaddr_storage to;
642 memset(&my->cbuf, 0,
sizeof(my->cbuf));
643 memset(&my->msgh, 0,
sizeof(
struct msghdr));
647 my->iov = (
struct iovec) {
652 my->msgh = (
struct msghdr) {
653 .msg_control = my->cbuf,
656 .msg_namelen = to_len,
663 struct in6_pktinfo *pkt;
665 my->msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
667 cmsg = CMSG_FIRSTHDR(&my->msgh);
668 cmsg->cmsg_level = IPPROTO_IPV6;
669 cmsg->cmsg_type = IPV6_PKTINFO;
670 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
672 pkt = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
673 memset(pkt, 0,
sizeof(*pkt));
674 pkt->ipi6_addr = addr->
socket.inet.src_ipaddr.addr.v6;
675 pkt->ipi6_ifindex = addr->
socket.inet.ifindex;
688static inline int fr_bio_fd_udpfromto_init6(
int fd)
692 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt,
sizeof(opt));
700 len = strlen(filename);
701 if (
len >=
sizeof(sun->sun_path)) {
702 fr_strerror_const(
"Failed parsing unix domain socket filename: Name is too long");
706 sun->sun_family = AF_LOCAL;
707 memcpy(sun->sun_path, filename,
len + 1);
709 *sunlen = SUN_LEN(sun);
717 struct sockaddr_storage salocal;
732 salen =
sizeof(salocal);
733 memset(&salocal, 0, salen);
734 if (getsockname(my->
info.
socket.
fd, (
struct sockaddr *) &salocal, &salen) < 0) {
764 if (my->cb.connected) my->cb.connected(&my->bio);
824 if (tries <= my->max_tries)
goto retry;
844 if (rcode < 0)
return rcode;
873 switch (my->
info.
cfg->
flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
924 (void) setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on,
sizeof(on));
927# define fr_bio_fd_no_sigpipe(_x)
971 if (rcode == 0)
return 0;
973 if (rcode !=
fr_bio_error(IO_WOULD_BLOCK))
return rcode;
999#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
1000 }
else if (my->
info.
socket.inet.src_ipaddr.
af == AF_INET) {
1001 if (fr_bio_fd_udpfromto_init4(my->
info.
socket.
fd) < 0)
return -1;
1003 my->bio.read = fr_bio_fd_recvfromto4;
1004 my->bio.write = fr_bio_fd_sendfromto4;
1007#if defined(IPV6_PKTINFO)
1008 }
else if (my->
info.
socket.inet.src_ipaddr.
af == AF_INET6) {
1010 if (fr_bio_fd_udpfromto_init6(my->
info.
socket.
fd) < 0)
return -1;
1012 my->bio.read = fr_bio_fd_recvfromto6;
1013 my->bio.write = fr_bio_fd_sendfromto6;
1052#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
1060#if defined(IPV6_PKTINFO)
1061 if ((my->
info.
socket.inet.src_ipaddr.
af == AF_INET6) &&
1121 if (!my)
return NULL;
1136 .read_blocked =
false,
1137 .write_blocked =
false,
1247 socklen_t socklen =
sizeof(error);
1262 if (getsockopt(my->
info.
socket.
fd, SOL_SOCKET, SO_ERROR, (
void *)&error, &socklen) < 0) {
1327 my->
connect.timeout(&my->bio);
1365 if (error_cb) error_cb(bio);
1376 if (connected_cb) connected_cb(bio);
1398 if (!connected_cb) {
1403 if (error_cb) error_cb(bio);
1418 my->
connect.success = connected_cb;
1420 my->
connect.timeout = timeout_cb;
1464 if (rcode >= 0)
return 0;
1480 if (rcode > 0 )
return 0;
1506 goto set_recv_buff_zero;
1529 if (setsockopt(my->
info.
socket.
fd, SOL_SOCKET, SO_RCVBUF, &opt,
sizeof(opt)) < 0) {
1551#if !defined(__linux__) && !defined(__FreeBSD__)
1552static int inline accept4(
int fd,
struct sockaddr *sockaddr, socklen_t *salen,
UNUSED int flags)
1554 fd = accept(fd, sockaddr, salen);
1557 int our_errno = errno;
1571#ifndef SOCK_NONBLOCK
1572#define SOCK_NONBLOCK 0
1576#define SOCK_CLOEXEC 0
1597#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1608 if (tries <= my->max_tries)
goto retry;
1645 struct sockaddr_storage *from, socklen_t *from_len,
fr_ipaddr_t *dst)
1649 uint8_t cbuf[CMSG_SPACE(
sizeof(
struct in6_pktinfo)) + CMSG_SPACE(
sizeof(
struct timespec))];
1650 struct msghdr msgh = {
1651 .msg_control = cbuf,
1652 .msg_controllen =
sizeof(cbuf),
1654 .msg_namelen =
sizeof(*from),
1658 struct cmsghdr *cmsg;
1662 slen = recvmsg(
parent->info.socket.fd, &msgh, flags);
1663 if (slen < 0)
return slen;
1665 *from_len = msgh.msg_namelen;
1671 *dst =
parent->info.socket.inet.src_ipaddr;
1676 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
1678 struct sockaddr_storage to;
1681 if ((cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
1682 struct in_pktinfo *i = (
struct in_pktinfo *) CMSG_DATA(cmsg);
1684 memset(&to, 0,
sizeof(to));
1685 ((
struct sockaddr_in *) &to)->sin_family = AF_INET;
1686 ((
struct sockaddr_in *) &to)->sin_addr = i->ipi_addr;
1691#ifdef IP_RECVDSTADDR
1692 if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
1693 struct in_addr *i = (
struct in_addr *) CMSG_DATA(cmsg);
1695 memset(&to, 0,
sizeof(to));
1696 ((
struct sockaddr_in *) &to)->sin_family = AF_INET;
1697 ((
struct sockaddr_in *) &to)->sin_addr = *i;
1703 if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type == IPV6_PKTINFO)) {
1704 struct in6_pktinfo *i = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
1706 memset(&to, 0,
sizeof(to));
1707 ((
struct sockaddr_in6 *) &to)->sin6_family = AF_INET6;
1708 ((
struct sockaddr_in6 *) &to)->sin6_addr = i->ipi6_addr;
1709 ((
struct sockaddr_in6 *) &to)->sin6_scope_id = i->ipi6_ifindex;
1755 struct sockaddr_storage peer;
1774#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1782 if (tries <= parent->max_tries)
goto retry;
1793 if (dst_ipaddr.
af == AF_UNSPEC) {
1794 fr_strerror_const(
"Cannot find the address which the first datagram was sent to");
1817 *cfg = *
parent->info.cfg;
1837 out->first_datagram = talloc_memdup(
out,
parent->accept_buffer, slen ? (
size_t) slen : 1);
1838 if (!
out->first_datagram) {
1842 out->first_datagram_len = (
size_t) slen;
1849 out->info.read_blocked =
false;
1885 out->info.socket.
fd = -1;
1905 if ((
out->info.socket.af == AF_INET) || (
out->info.socket.af == AF_INET6)) {
1907 &
out->remote_sockaddr,
out->remote_sockaddr_len);
1920 if (!
out->info.name) {
static int const char char buffer[256]
fr_bio_write_t _CONST write
write to the underlying bio
fr_bio_read_t _CONST read
read from the underlying bio
static ssize_t fr_bio_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Write raw data to a bio.
static fr_bio_t * fr_bio_head(fr_bio_t *bio)
void(* fr_bio_callback_t)(fr_bio_t *bio)
static int packet_ctx
the tests pass only the address of packet_ctx
#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_notconn_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
This FD isn't connected.
static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
Write to fd.
static ssize_t fr_bio_fd_read_first_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Return the datagram which fr_bio_fd_accept() read from the listening socket.
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
static int fr_bio_fd_try_connect(fr_bio_fd_t *my)
Try to connect().
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.
static int accept4(int fd, struct sockaddr *sockaddr, socklen_t *salen, UNUSED int flags)
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_recvfrom(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read from a UDP socket where we know our IP.
#define fr_bio_fd_no_sigpipe(_x)
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)
Accept a new connection on a socket.
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
static int fr_bio_fd_accept_datagram(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_fd_t *parent)
Accept a "connection" on a datagram listening socket.
static int fr_bio_fd_shutdown(fr_bio_t *bio)
Orderly shutdown.
static int fr_bio_fd_accept_stream(fr_bio_fd_t *my, fr_bio_fd_t const *parent)
Accept a stream socket and initialize its flags.
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.
int fr_bio_fd_init_common(fr_bio_fd_t *my)
static ssize_t fr_bio_fd_recvmsg_dst(fr_bio_fd_t *parent, uint8_t *buffer, int flags, struct sockaddr_storage *from, socklen_t *from_len, fr_ipaddr_t *dst)
Receive a datagram, and find the address which the datagram was sent to.
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_socket_t socket
as connected socket
fr_bio_fd_type_t type
type of the socket
fr_bio_fd_state_t state
connecting, open, closed, etc.
int connect_errno
from connect() or other APIs
fr_ipaddr_t dst_ipaddr
their IP address
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
@ 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
call fr_bio_fd_accept() for each new connection
fr_bio_fd_config_t const * cfg
so we know what was asked, vs what was granted.
bool read_blocked
did we block on read?
@ FR_BIO_FD_TRANSPORT_TCP
TCP over IPv4 or IPv6.
bool server
is this a client or a server?
uint32_t backlog
for listen()
uint16_t dst_port
their port
fr_bio_fd_transport_t transport_type
which transport, as a number instead of a name
int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
Opens a socket and updates sock->fd.
@ FR_BIO_FD_STATE_CONNECTING
@ FR_BIO_FD_STATE_OPEN
error states must be before this
bool reuse_port
whether or not we re-use the same destination port for datagram sockets
bool backlog_is_set
Whether we were provided with a backlog.
fr_socket_t socket
socket information, including FD.
bool write_blocked
did we block on write?
fr_ipaddr_t src_ipaddr
our IP address
Configuration for sockets.
Run-time status of the socket.
static bool fr_bio_fd_errno_retry(fr_bio_fd_t *my, ssize_t *rcode_p, int *tries_p, bool is_write)
Turn a failed read / write into a bio return code.
int fr_bio_fd_unix_shutdown(fr_bio_t *bio)
Remove the Unix domain socket which this bio created.
void fr_bio_fd_name(fr_bio_fd_t *my)
Set the name of an FD BIO.
socklen_t remote_sockaddr_len
struct fr_bio_fd_s::@18 connect
size_t offset
where fr_bio_fd_packet_ctx_t is stored
int max_tries
how many times we retry on EINTR
uint8_t * first_datagram
The datagram which fr_bio_fd_accept() read to name the peer.
uint8_t * accept_buffer
A LISTEN datagram bio reads datagrams into this buffer, which is allocated once by fr_bio_fd_init_lis...
#define fr_bio_fd_packet_ctx(_my, _packet_ctx)
#define FR_BIO_FD_MAX_DATAGRAM
The largest payload of a UDP datagram.
size_t first_datagram_len
Length of first_datagram.
struct sockaddr_storage remote_sockaddr
for connected UDP sockets.
static bool fr_bio_fd_read_retry(fr_bio_fd_t *my, ssize_t *rcode_p, int *tries_p)
Common finalization code for the read functions.
static bool fr_bio_fd_write_retry(fr_bio_fd_t *my, ssize_t *rcode_p, int *tries_p, size_t size)
Common finalization code for the write functions.
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.
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.
ssize_t fr_bio_shutdown_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
ssize_t fr_bio_shutdown_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
fr_bio_t * 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.
int fr_nonblock(UNUSED int fd)
int fr_cloexec(UNUSED int fd)
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 an error on write.
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 af
AF_INET, AF_INET6, or AF_UNIX.
int fd
File descriptor if this is a live socket.
int type
SOCK_STREAM, SOCK_DGRAM, etc.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static fr_sbuff_err_t char size_t fr_sbuff_t * in
static fr_sbuff_err_t char ** out
static fr_sbuff_err_t char size_t * len