The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
fd.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 0de587887903f000ff585244a239e25735bbb00d $
19  * @file lib/bio/fd.c
20  * @brief BIO abstractions for file descriptors
21  *
22  * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23  */
24 
25 #include <freeradius-devel/bio/fd_priv.h>
26 #include <freeradius-devel/bio/null.h>
27 
28 /*
29  * More portability idiocy
30  * Mac OSX Lion doesn't define SOL_IP. But IPPROTO_IP works.
31  */
32 #ifndef SOL_IP
33 # define SOL_IP IPPROTO_IP
34 #endif
35 
36 /*
37  * glibc 2.4 and uClibc 0.9.29 introduce IPV6_RECVPKTINFO etc. and
38  * change IPV6_PKTINFO This is only supported in Linux kernel >=
39  * 2.6.14
40  *
41  * This is only an approximation because the kernel version that libc
42  * was compiled against could be older or newer than the one being
43  * run. But this should not be a problem -- we just keep using the
44  * old kernel interface.
45  */
46 #ifdef __linux__
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
52 # undef IPV6_PKTINFO
53 # define IPV6_RECVPKTINFO IPV6_2292PKTINFO
54 # define IPV6_PKTINFO IPV6_2292PKTINFO
55 # endif
56 # endif
57 /* Fall back to the legacy socket option if IPV6_RECVPKTINFO isn't defined */
58 # elif defined(IPV6_2292PKTINFO)
59 # define IPV6_RECVPKTINFO IPV6_2292PKTINFO
60 # endif
61 #else
62 
63 /*
64  * For everything that's not Linux we assume RFC 3542 compliance
65  * - setsockopt() takes IPV6_RECVPKTINFO
66  * - cmsg_type is IPV6_PKTINFO (in sendmsg, recvmsg)
67  *
68  * If we don't have IPV6_RECVPKTINFO defined but do have IPV6_PKTINFO
69  * defined, chances are the API is RFC2292 compliant and we need to use
70  * IPV6_PKTINFO for both.
71  */
72 # if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
73 # define IPV6_RECVPKTINFO IPV6_PKTINFO
74 
75 /*
76  * Ensure IPV6_RECVPKTINFO is not defined somehow if we have we
77  * don't have IPV6_PKTINFO.
78  */
79 # elif !defined(IPV6_PKTINFO)
80 # undef IPV6_RECVPKTINFO
81 # endif
82 #endif
83 
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; \
89  } while (0)
90 
91 /*
92  * Close the descriptor and free the bio.
93  */
95 {
96  /*
97  * The upstream bio must have unlinked it from the chain before calling talloc_free() on this
98  * bio.
99  */
100  fr_assert(!fr_bio_prev(&my->bio));
101  fr_assert(!fr_bio_next(&my->bio));
102 
103  return fr_bio_fd_close(&my->bio);
104 }
105 
106 /** Stream read.
107  *
108  */
109 static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
110 {
111  int tries = 0;
112  ssize_t rcode;
113  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
114 
115  my->info.read_blocked = false;
116 
117 retry:
118  rcode = read(my->info.socket.fd, buffer, size);
119  if (rcode > 0) return rcode;
120 
121  if (rcode == 0) {
122  /*
123  * Stream sockets return 0 at EOF. However, we want to distinguish that from the case of datagram
124  * sockets, which return 0 when there's no data. So we over-ride the 0 value here, and instead
125  * return an EOF error.
126  */
129  my->info.eof = true;
130 
131  return fr_bio_error(EOF);
132  }
133 
134 #undef flag_blocked
135 #define flag_blocked info.read_blocked
136 #include "fd_errno.h"
137 
138  return fr_bio_error(IO);
139 }
140 
141 /** Connected datagram read.
142  *
143  * The difference between this and stream protocols is that for datagrams. a read of zero means "no packets",
144  * where a read of zero on a steam socket means "EOF".
145  *
146  * Connected sockets do _not_ update per-packet contexts.
147  */
148 static ssize_t fr_bio_fd_read_connected_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
149 {
150  int tries = 0;
151  ssize_t rcode;
152  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
153 
154  my->info.read_blocked = false;
155 
156 retry:
157  rcode = read(my->info.socket.fd, buffer, size);
158  if (rcode >= 0) return rcode;
159 
160 #undef flag_blocked
161 #define flag_blocked info.read_blocked
162 #include "fd_errno.h"
163 
164  return fr_bio_error(IO);
165 }
166 
167 /** Read from a UDP socket where we know our IP
168  */
169 static ssize_t fr_bio_fd_recvfrom(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
170 {
171  int tries = 0;
172  ssize_t rcode;
173  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
174  socklen_t salen;
175  struct sockaddr_storage sockaddr;
176 
177  my->info.read_blocked = false;
178 
179 retry:
180  salen = sizeof(sockaddr);
181 
182  rcode = recvfrom(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, &salen);
183  if (rcode > 0) {
184  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
185 
186  ADDR_INIT;
187 
188  addr->socket.inet.dst_ipaddr = my->info.socket.inet.src_ipaddr;
189  addr->socket.inet.dst_port = my->info.socket.inet.src_port;
190 
191  (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
192  &sockaddr, salen);
193  return rcode;
194  }
195 
196  if (rcode == 0 ) return rcode;
197 
198 #undef flag_blocked
199 #define flag_blocked info.read_blocked
200 #include "fd_errno.h"
201 
202  return fr_bio_error(IO);
203 }
204 
205 
206 /** Write to fd.
207  *
208  * This function is used for connected sockets, where we ignore the packet_ctx.
209  */
210 static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
211 {
212  int tries = 0;
213  ssize_t rcode;
214  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
215 
216  /*
217  * FD bios do nothing on flush.
218  */
219  if (!buffer) return 0;
220 
221  my->info.write_blocked = false;
222 
223 retry:
224  /*
225  * We could call send() instead of write()! Posix says:
226  *
227  * "A write was attempted on a socket that is shut down for writing, or is no longer
228  * connected. In the latter case, if the socket is of type SOCK_STREAM, a SIGPIPE signal shall
229  * also be sent to the thread."
230  *
231  * We can override this behavior by calling send(), and passing the special flag which says
232  * "don't do that!". The system call will then return EPIPE, which indicates that the socket is
233  * no longer usable.
234  *
235  * However, we also set the SO_NOSIGPIPE socket option, which means that we can just call write()
236  * here.
237  */
238  rcode = write(my->info.socket.fd, buffer, size);
239  if (rcode >= 0) return rcode;
240 
241 #undef flag_blocked
242 #define flag_blocked info.write_blocked
243 #include "fd_errno.h"
244 
245  return fr_bio_error(IO);
246 }
247 
248 /** Write to a UDP socket where we know our IP
249  *
250  */
251 static ssize_t fr_bio_fd_sendto(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
252 {
253  int tries = 0;
254  ssize_t rcode;
255  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
256  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
257  socklen_t salen;
258  struct sockaddr_storage sockaddr;
259 
260  /*
261  * FD bios do nothing on flush.
262  */
263  if (!buffer) return 0;
264 
265  my->info.write_blocked = false;
266 
267  // get destination IP
268  (void) fr_ipaddr_to_sockaddr(&sockaddr, &salen, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
269 
270 retry:
271  rcode = sendto(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, salen);
272  if (rcode >= 0) return rcode;
273 
274 #undef flag_blocked
275 #define flag_blocked info.write_blocked
276 #include "fd_errno.h"
277 
278  return fr_bio_error(IO);
279 }
280 
281 
282 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
283 static ssize_t fd_fd_recvfromto_common(fr_bio_fd_t *my, void *packet_ctx, void *buffer, size_t size)
284 {
285  int tries = 0;
286  ssize_t rcode;
287  struct sockaddr_storage from;
288  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
289 
290 #ifdef STATIC_ANALYZER
291  from.ss_family = AF_UNSPEC;
292 #endif
293 
294  my->info.read_blocked = false;
295 
296  memset(&my->cbuf, 0, sizeof(my->cbuf));
297  memset(&my->msgh, 0, sizeof(struct msghdr));
298 
299  my->iov = (struct iovec) {
300  .iov_base = buffer,
301  .iov_len = size,
302  };
303 
304  my->msgh = (struct msghdr) {
305  .msg_control = my->cbuf,
306  .msg_controllen = sizeof(my->cbuf),
307  .msg_name = &from,
308  .msg_namelen = sizeof(from),
309  .msg_iov = &my->iov,
310  .msg_iovlen = 1,
311  .msg_flags = 0,
312  };
313 
314 retry:
315  rcode = recvmsg(my->info.socket.fd, &my->msgh, 0);
316  if (rcode > 0) {
317  ADDR_INIT;
318 
319  (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
320  &from, my->msgh.msg_namelen);
321 
322  return rcode;
323  }
324 
325  if (rcode == 0) return rcode;
326 
327 #undef flag_blocked
328 #define flag_blocked info.read_blocked
329 #include "fd_errno.h"
330 
331  return fr_bio_error(IO);
332 }
333 #endif
334 
335 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
336 
337 /** Read from a UDP socket where we can change our IP, IPv4 version.
338  */
339 static ssize_t fr_bio_fd_recvfromto4(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
340 {
341  ssize_t rcode;
342  struct cmsghdr *cmsg;
343  fr_time_t when = fr_time_wrap(0);
344  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
345  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
346 
347  rcode = fd_fd_recvfromto_common(my, packet_ctx, buffer, size);
348  if (rcode <= 0) return rcode;
349 
350 DIAG_OFF(sign-compare)
351  /* Process auxiliary received data in msgh */
352  for (cmsg = CMSG_FIRSTHDR(&my->msgh);
353  cmsg != NULL;
354  cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
355 DIAG_ON(sign-compare)
356 
357 #ifdef IP_PKTINFO
358  if ((cmsg->cmsg_level == SOL_IP) &&
359  (cmsg->cmsg_type == IP_PKTINFO)) {
360  struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
361  struct sockaddr_in to;
362 
363  to.sin_addr = i->ipi_addr;
364 
365  (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
366  (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in));
367  addr->socket.inet.ifindex = i->ipi_ifindex;
368  break;
369  }
370 #endif
371 
372 #ifdef IP_RECVDSTADDR
373  if ((cmsg->cmsg_level == IPPROTO_IP) &&
374  (cmsg->cmsg_type == IP_RECVDSTADDR)) {
375  struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
376  struct sockaddr_in to;
377 
378  to.sin_addr = *i;
379  (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
380  (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in));
381  break;
382  }
383 #endif
384 
385 #ifdef SO_TIMESTAMPNS
386  if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
387  when = fr_time_from_timespec((struct timespec *)CMSG_DATA(cmsg));
388  }
389 
390 #elif defined(SO_TIMESTAMP)
391  if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
392  when = fr_time_from_timeval((struct timeval *)CMSG_DATA(cmsg));
393  }
394 #endif
395  }
396 
397  if fr_time_eq(when, fr_time_wrap(0)) when = fr_time();
398 
399  addr->when = when;
400 
401  return rcode;
402 }
403 
404 /** Send to UDP socket where we can change our IP, IPv4 version.
405  */
406 static ssize_t fr_bio_fd_sendfromto4(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
407 {
408  int tries = 0;
409  ssize_t rcode;
410  struct cmsghdr *cmsg;
411  struct sockaddr_storage to;
412  socklen_t to_len;
413  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
414  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
415 
416  my->info.write_blocked = false;
417 
418  memset(&my->cbuf, 0, sizeof(my->cbuf));
419  memset(&my->msgh, 0, sizeof(struct msghdr));
420 
421  (void) fr_ipaddr_to_sockaddr(&to, &to_len, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
422 
423  my->iov = (struct iovec) {
424  .iov_base = UNCONST(void *, buffer),
425  .iov_len = size,
426  };
427 
428  my->msgh = (struct msghdr) {
429  .msg_control = my->cbuf,
430  // controllen is set below
431  .msg_name = &to,
432  .msg_namelen = to_len,
433  .msg_iov = &my->iov,
434  .msg_iovlen = 1,
435  .msg_flags = 0,
436  };
437 
438  cmsg = CMSG_FIRSTHDR(&my->msgh);
439 
440  {
441 #ifdef IP_PKTINFO
442  struct in_pktinfo *pkt;
443 
444  my->msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
445 
446  cmsg->cmsg_level = SOL_IP;
447  cmsg->cmsg_type = IP_PKTINFO;
448  cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
449 
450  pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
451  memset(pkt, 0, sizeof(*pkt));
452  pkt->ipi_spec_dst = addr->socket.inet.src_ipaddr.addr.v4;
453  pkt->ipi_ifindex = addr->socket.inet.ifindex;
454 
455 #elif defined(IP_SENDSRCADDR)
456  struct in_addr *in;
457 
458  my->msgh.msg_controllen = CMSG_SPACE(sizeof(*in));
459 
460  cmsg->cmsg_level = IPPROTO_IP;
461  cmsg->cmsg_type = IP_SENDSRCADDR;
462  cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
463 
464  in = (struct in_addr *) CMSG_DATA(cmsg);
465  *in = addr->socket.inet.src_ipaddr.addr.v4;
466 #endif
467  }
468 
469 retry:
470  rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
471  if (rcode >= 0) return rcode;
472 
473 #undef flag_blocked
474 #define flag_blocked info.write_blocked
475 #include "fd_errno.h"
476 
477  return fr_bio_error(IO);
478 }
479 
480 static inline int fr_bio_fd_udpfromto_init4(int fd)
481 {
482  int proto = 0, flag = 0, opt = 1;
483 
484 #ifdef HAVE_IP_PKTINFO
485  /*
486  * Linux
487  */
488  proto = SOL_IP;
489  flag = IP_PKTINFO;
490 
491 #elif defined(IP_RECVDSTADDR)
492  /*
493  * Set the IP_RECVDSTADDR option (BSD). Note:
494  * IP_RECVDSTADDR == IP_SENDSRCADDR
495  */
496  proto = IPPROTO_IP;
497  flag = IP_RECVDSTADDR;
498 #endif
499 
500  return setsockopt(fd, proto, flag, &opt, sizeof(opt));
501 }
502 #endif
503 
504 #if defined(IPV6_PKTINFO)
505 /** Read from a UDP socket where we can change our IP, IPv4 version.
506  */
507 static ssize_t fr_bio_fd_recvfromto6(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
508 {
509  ssize_t rcode;
510  struct cmsghdr *cmsg;
511  fr_time_t when = fr_time_wrap(0);
512  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
513  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
514 
515  rcode = fd_fd_recvfromto_common(my, packet_ctx, buffer, size);
516  if (rcode <= 0) return rcode;
517 
518 DIAG_OFF(sign-compare)
519  /* Process auxiliary received data in msgh */
520  for (cmsg = CMSG_FIRSTHDR(&my->msgh);
521  cmsg != NULL;
522  cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
523 DIAG_ON(sign-compare)
524 
525  if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
526  (cmsg->cmsg_type == IPV6_PKTINFO)) {
527  struct in6_pktinfo *i = (struct in6_pktinfo *) CMSG_DATA(cmsg);
528  struct sockaddr_in6 to;
529 
530  to.sin6_addr = i->ipi6_addr;
531 
532  (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
533  (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in6));
534  addr->socket.inet.ifindex = i->ipi6_ifindex;
535  break;
536  }
537 
538 #ifdef SO_TIMESTAMPNS
539  if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
540  when = fr_time_from_timespec((struct timespec *)CMSG_DATA(cmsg));
541  }
542 
543 #elif defined(SO_TIMESTAMP)
544  if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
545  when = fr_time_from_timeval((struct timeval *)CMSG_DATA(cmsg));
546  }
547 #endif
548  }
549 
550  if fr_time_eq(when, fr_time_wrap(0)) when = fr_time();
551 
552  addr->when = when;
553 
554  return rcode;
555 }
556 
557 /** Send to UDP socket where we can change our IP, IPv4 version.
558  */
559 static ssize_t fr_bio_fd_sendfromto6(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
560 {
561  int tries = 0;
562  ssize_t rcode;
563  struct cmsghdr *cmsg;
564  struct sockaddr_storage to;
565  socklen_t to_len;
566  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
567  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
568 
569  my->info.write_blocked = false;
570 
571  memset(&my->cbuf, 0, sizeof(my->cbuf));
572  memset(&my->msgh, 0, sizeof(struct msghdr));
573 
574  (void) fr_ipaddr_to_sockaddr(&to, &to_len, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
575 
576  my->iov = (struct iovec) {
577  .iov_base = UNCONST(void *, buffer),
578  .iov_len = size,
579  };
580 
581  my->msgh = (struct msghdr) {
582  .msg_control = my->cbuf,
583  // controllen is set below
584  .msg_name = &to,
585  .msg_namelen = to_len,
586  .msg_iov = &my->iov,
587  .msg_iovlen = 1,
588  .msg_flags = 0,
589  };
590 
591  cmsg = CMSG_FIRSTHDR(&my->msgh);
592 
593  {
594  struct in6_pktinfo *pkt;
595 
596  my->msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
597 
598  cmsg->cmsg_level = IPPROTO_IPV6;
599  cmsg->cmsg_type = IPV6_PKTINFO;
600  cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
601 
602  pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
603  memset(pkt, 0, sizeof(*pkt));
604  pkt->ipi6_addr = addr->socket.inet.src_ipaddr.addr.v6;
605  pkt->ipi6_ifindex = addr->socket.inet.ifindex;
606  }
607 
608 retry:
609  rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
610  if (rcode >= 0) return rcode;
611 
612 #undef flag_blocked
613 #define flag_blocked info.write_blocked
614 #include "fd_errno.h"
615 
616  return fr_bio_error(IO);
617 }
618 
619 
620 static inline int fr_bio_fd_udpfromto_init6(int fd)
621 {
622  int opt = 1;
623 
624  return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt));
625 }
626 #endif
627 
628 int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
629 {
630  size_t len;
631 
632  len = strlen(filename);
633  if (len >= sizeof(sun->sun_path)) {
634  fr_strerror_const("Failed parsing unix domain socket filename: Name is too long");
635  return -1;
636  }
637 
638  sun->sun_family = AF_LOCAL;
639  memcpy(sun->sun_path, filename, len + 1); /* SUN_LEN will do strlen */
640 
641  *sunlen = SUN_LEN(sun);
642 
643  return 0;
644 }
645 
647 {
648  socklen_t salen;
649  struct sockaddr_storage salocal;
650 
651  /*
652  * Already set: do nothing.
653  */
654  if (!fr_ipaddr_is_inaddr_any(&my->info.socket.inet.src_ipaddr)) return 0;
655 
656  /*
657  * FreeBSD jail issues. We bind to 0.0.0.0, but the
658  * kernel instead binds us to a 1.2.3.4. So once the
659  * socket is bound, ask it what it's IP address is.
660  */
661  salen = sizeof(salocal);
662  memset(&salocal, 0, salen);
663  if (getsockname(my->info.socket.fd, (struct sockaddr *) &salocal, &salen) < 0) {
664  fr_strerror_printf("Failed getting socket name: %s", fr_syserror(errno));
665  return -1;
666  }
667 
668  if (fr_ipaddr_from_sockaddr(&my->info.socket.inet.src_ipaddr, &my->info.socket.inet.src_port, &salocal, salen) < 0) return -1;
669 
670  fr_ipaddr_get_scope_id(&my->info.socket.inet.src_ipaddr);
671  my->info.socket.inet.ifindex = my->info.socket.inet.src_ipaddr.scope_id;
672 
673  return 0;
674 }
675 
676 
677 /** Try to connect().
678  *
679  * If connect is blocking, we either succeed or error immediately. Otherwise, the caller has to select the
680  * socket for writeability, and then call fr_bio_fd_connect() as soon as the socket is writeable.
681  */
683 {
684  int tries = 0;
685  int rcode;
686  socklen_t salen;
687  struct sockaddr_storage sockaddr;
688 
689  if (my->info.socket.af != AF_LOCAL) {
690  rcode = fr_ipaddr_to_sockaddr(&sockaddr, &salen, &my->info.socket.inet.dst_ipaddr, my->info.socket.inet.dst_port);
691  } else {
692  rcode = fr_filename_to_sockaddr((struct sockaddr_un *) &sockaddr, &salen, my->info.socket.unix.path);
693  }
694 
695  if (rcode < 0) {
696  fr_bio_shutdown(&my->bio);
697  return fr_bio_error(GENERIC);
698  }
699 
701 
702 retry:
703  if (connect(my->info.socket.fd, (struct sockaddr *) &sockaddr, salen) == 0) {
705 
706  /*
707  * The source IP may have changed, so get the new one.
708  */
709  if (fr_bio_fd_socket_name(my) < 0) goto fail;
710 
711  if (fr_bio_fd_init_common(my) < 0) goto fail;
712 
713  return 0;
714  }
715 
716  switch (errno) {
717  case EINTR:
718  tries++;
719  if (tries <= my->max_tries) goto retry;
720  FALL_THROUGH;
721 
722  /*
723  * This shouldn't happen, but we'll allow it
724  */
725  case EALREADY:
726  FALL_THROUGH;
727 
728  /*
729  * Once the socket is writable, it will be active, or in an error state. The caller has
730  * to call fr_bio_fd_connect() before calling write()
731  */
732  case EINPROGRESS:
733  my->info.write_blocked = true;
734  return fr_bio_error(IO_WOULD_BLOCK);
735 
736  default:
737  break;
738  }
739 
740 fail:
741  fr_bio_shutdown(&my->bio);
742  return fr_bio_error(IO);
743 }
744 
745 /** Files are a special case of connected sockets.
746  *
747  */
749 {
751  my->info.eof = false;
752  my->info.read_blocked = false;
753  my->info.write_blocked = false;
754 
755  /*
756  * Other flags may be O_CREAT, etc.
757  */
758  switch (my->info.cfg->flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
759  case O_RDONLY:
760  my->bio.read = fr_bio_fd_read_stream;
761  my->bio.write = fr_bio_null_write; /* @todo - error on write? */
762  break;
763 
764  case O_WRONLY:
765  my->bio.read = fr_bio_null_read; /* @todo - error on read? */
766  my->bio.write = fr_bio_fd_write;
767  break;
768 
769  case O_RDWR:
770  my->bio.read = fr_bio_fd_read_stream;
771  my->bio.write = fr_bio_fd_write;
772  break;
773 
774  default:
775  fr_strerror_const("Invalid flag for opening file");
776  return -1;
777  }
778 
779  return 0;
780 }
781 
783 {
784  int rcode;
785 
786  if (my->info.socket.af == AF_FILE_BIO) return fr_bio_fd_init_file(my);
787 
788  /*
789  * The source IP can be unspecified. It will get updated after we call connect().
790  */
791 
792  /*
793  * All connected sockets must have a destination IP.
794  */
795  if (fr_ipaddr_is_inaddr_any(&my->info.socket.inet.dst_ipaddr)) {
796  fr_strerror_const("Destination IP address cannot be wildcard");
797  return -1;
798  }
799 
800  /*
801  * Don't do any reads until we're connected.
802  */
803  my->bio.read = fr_bio_null_read;
804  my->bio.write = fr_bio_null_write;
805 
806  my->info.eof = false;
807 
808  /*
809  * The socket shouldn't be selected for read. But it should be selected for write.
810  */
811  my->info.read_blocked = false;
812  my->info.write_blocked = true;
813 
814 #ifdef SO_NOSIGPIPE
815  /*
816  * Although the server ignore SIGPIPE, some operating systems like BSD and OSX ignore the
817  * ignoring.
818  *
819  * Fortunately, those operating systems usually support SO_NOSIGPIPE. We set that to prevent
820  * them raising the signal in the first place.
821  */
822  {
823  int on = 1;
824 
825  setsockopt(my->info.socket.fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
826  }
827 #endif
828 
829  /*
830  * Don't call connect() if the socket is synchronous, it will block.
831  */
832  if (!my->info.cfg->async) return 0;
833 
834  rcode = fr_bio_fd_try_connect(my);
835  if (rcode == 0) return 0;
836 
837  if (rcode != fr_bio_error(IO_WOULD_BLOCK)) return rcode;
838 
841 
842  return 0;
843 }
844 
846 {
847  if (my->info.socket.type == SOCK_STREAM) { //!< stream socket
848  my->bio.read = fr_bio_fd_read_stream;
849  my->bio.write = fr_bio_fd_write;
850 
851  } else if (my->info.type == FR_BIO_FD_CONNECTED) { //!< connected datagram
852  my->bio.read = fr_bio_fd_read_connected_datagram;
853  my->bio.write = fr_bio_fd_write;
854 
855  } else if (!fr_ipaddr_is_inaddr_any(&my->info.socket.inet.src_ipaddr)) { //!< we know our IP address
856  my->bio.read = fr_bio_fd_recvfrom;
857  my->bio.write = fr_bio_fd_sendto;
858 
859 #if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
860  } else if (my->info.socket.inet.src_ipaddr.af == AF_INET) { //!< we don't know our IPv4
861  if (fr_bio_fd_udpfromto_init4(my->info.socket.fd) < 0) return -1;
862 
863  my->bio.read = fr_bio_fd_recvfromto4;
864  my->bio.write = fr_bio_fd_sendfromto4;
865 #endif
866 
867 #if defined(IPV6_PKTINFO)
868  } else if (my->info.socket.inet.src_ipaddr.af == AF_INET6) { //!< we don't know our IPv6
869 
870  if (fr_bio_fd_udpfromto_init6(my->info.socket.fd) < 0) return -1;
871 
872  my->bio.read = fr_bio_fd_recvfromto6;
873  my->bio.write = fr_bio_fd_sendfromto6;
874 #endif
875 
876  } else {
877  fr_strerror_const("Failed initializing socket: cannot determine what to do");
878  return -1;
879  }
880 
882  my->info.eof = false;
883  my->info.read_blocked = false;
884  my->info.write_blocked = false;
885 
886  return 0;
887 }
888 
889 /** Return an fd on read()
890  *
891  * With packet_ctx containing information about the socket.
892  */
893 static ssize_t fr_bio_fd_read_accept(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
894 {
895  int fd, tries = 0;
896  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
897  socklen_t salen;
898  struct sockaddr_storage sockaddr;
899 
900  if (size < sizeof(int)) return fr_bio_error(BUFFER_TOO_SMALL);
901 
902  salen = sizeof(sockaddr);
903 
904 retry:
905 #ifdef __linux__
906  /*
907  * Set these flags immediately on the new socket.
908  */
909  fd = accept4(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen, SOCK_NONBLOCK | SOCK_CLOEXEC);
910 #else
911  fd = accept(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen);
912 #endif
913  if (fd >= 0) {
914  fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
915 
916  ADDR_INIT;
917 
918  (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
919  &sockaddr, salen);
920 
921  addr->socket.inet.dst_ipaddr = my->info.socket.inet.src_ipaddr;
922  addr->socket.inet.dst_port = my->info.socket.inet.src_port;
923  addr->socket.fd = fd; /* might as well! */
924 
925  *(int *) buffer = fd;
926  return sizeof(int);
927  }
928 
929  switch (errno) {
930  case EINTR:
931  /*
932  * Try a few times before giving up.
933  */
934  tries++;
935  if (tries <= my->max_tries) goto retry;
936  return 0;
937 
938  /*
939  * We can ignore these errors.
940  */
941  case ECONNABORTED:
942 #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
943  case EWOULDBLOCK:
944 #endif
945  case EAGAIN:
946 #ifdef EPERM
947  case EPERM:
948 #endif
949 #ifdef ETIMEDOUT
950  case ETIMEDOUT:
951 #endif
952  return 0;
953 
954  default:
955  /*
956  * Some other error, it's fatal.
957  */
958  fr_bio_shutdown(&my->bio);
959  break;
960  }
961 
962  return fr_bio_error(IO);
963 }
964 
965 
967 {
969  my->info.eof = false;
970  my->info.read_blocked = true;
971  my->info.write_blocked = false; /* don't select() for write */
972 
973  my->bio.read = fr_bio_fd_read_accept;
974  my->bio.write = fr_bio_null_write;
975 
976  if (listen(my->info.socket.fd, 8) < 0) {
977  fr_strerror_printf("Failed opening setting FD_CLOEXE: %s", fr_syserror(errno));
978  return -1;
979  }
980 
981  return 0;
982 }
983 
984 /** Allocate a FD bio
985  *
986  * The caller is responsible for tracking the FD, and all associated management of it. The bio API is
987  * intended to be simple, and does not provide wrapper functions for various ioctls. The caller should
988  * instead do that work.
989  *
990  * Once the FD is give to the bio, its lifetime is "owned" by the bio. Calling talloc_free(bio) will close
991  * the FD.
992  *
993  * The caller can still manage the FD for being readable / writeable. However, the caller should not call
994  * this bio directly (unless it is the only one). Instead, the caller should read from / write to the
995  * previous bio which will then eventually call this one.
996  *
997  * Before updating any event handler readable / writeable callbacks, the caller should check
998  * fr_bio_fd_at_eof(). If true, then the handlers should not be inserted. The previous bios should still be
999  * called to process any pending data, until they return EOF.
1000  *
1001  * The main purpose of an FD bio is to wrap the FD in a bio container. That, and handling retries on read /
1002  * write, along with returning EOF as an error instead of zero.
1003  *
1004  * Note that the read / write functions can return partial data. It is the callers responsibility to ensure
1005  * that any writes continue from where they left off (otherwise dat awill be missing). And any partial reads
1006  * should go to a memory bio.
1007  *
1008  * If a read returns EOF, then the FD remains open until talloc_free(bio) or fr_bio_fd_close() is called.
1009  *
1010  * @param ctx the talloc ctx
1011  * @param cb callbacks
1012  * @param cfg structure holding configuration information
1013  * @param offset only for unconnected datagram sockets, where #fr_bio_fd_packet_ctx_t is stored
1014  * @return
1015  * - NULL on error, memory allocation failed
1016  * - !NULL the bio
1017  */
1018 fr_bio_t *fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_cb_funcs_t *cb, fr_bio_fd_config_t const *cfg, size_t offset)
1019 {
1020  fr_bio_fd_t *my;
1021 
1022  my = talloc_zero(ctx, fr_bio_fd_t);
1023  if (!my) return NULL;
1024 
1025  if (cb) my->cb = *cb;
1026  my->max_tries = 4;
1027  my->offset = offset;
1028 
1029  if (!cfg) {
1030  /*
1031  * Add place-holder information.
1032  */
1033  my->info = (fr_bio_fd_info_t) {
1034  .socket = {
1035  .af = AF_UNSPEC,
1036  },
1037  .type = FR_BIO_FD_UNCONNECTED,
1038  .read_blocked = true,
1039  .write_blocked = true,
1040  .eof = false,
1041  .state = FR_BIO_FD_STATE_CLOSED,
1042  };
1043 
1044  my->bio.read = fr_bio_eof_read;
1045  my->bio.write = fr_bio_null_write;
1046  } else {
1048 
1049  if (fr_bio_fd_open(&my->bio, cfg) < 0) {
1050  talloc_free(my);
1051  return NULL;
1052  }
1053  }
1054 
1055  talloc_set_destructor(my, fr_bio_fd_destructor);
1056  return (fr_bio_t *) my;
1057 }
1058 
1059 /** Close the FD, but leave the bio allocated and alive.
1060  *
1061  */
1063 {
1064  int rcode;
1065  int tries = 0;
1066  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1067 
1068  if (my->info.state == FR_BIO_FD_STATE_CLOSED) return 0;
1069 
1070  /*
1071  * Shut the bio down cleanly.
1072  */
1073  rcode = fr_bio_shutdown(bio);
1074  if (rcode < 0) return rcode;
1075 
1076  my->bio.read = fr_bio_eof_read;
1077  my->bio.write = fr_bio_null_write;
1078 
1079  /*
1080  * Shut down the connected socket. The only errors possible here are things we can't do anything
1081  * about.
1082  *
1083  * shutdown() will close ALL versions of this file descriptor, even if it's (somehow) used in
1084  * another process. shutdown() will also tell the kernel to gracefully close the connected
1085  * socket, so that it can signal the other end, instead of having the connection disappear.
1086  *
1087  * This shouldn't strictly be necessary, as no other processes should be sharing this file
1088  * descriptor. But it's the safe (and polite) thing to do.
1089  */
1090  if (my->info.type == FR_BIO_FD_CONNECTED) {
1091  (void) shutdown(my->info.socket.fd, SHUT_RDWR);
1092  }
1093 
1094 retry:
1095  rcode = close(my->info.socket.fd);
1096  if (rcode < 0) {
1097  switch (errno) {
1098  case EINTR:
1099  case EIO:
1100  tries++;
1101  if (tries < my->max_tries) goto retry;
1102  return -1;
1103 
1104  default:
1105  /*
1106  * EBADF, or other unrecoverable error. We just call it closed, and continue.
1107  */
1108  break;
1109  }
1110  }
1111 
1113  my->info.read_blocked = true;
1114  my->info.write_blocked = true;
1115  my->info.eof = true;
1116 
1117  return 0;
1118 }
1119 
1120 /** Finalize a connect()
1121  *
1122  * connect() said "come back when the socket is writeable". It's now writeable, so we check if there was a
1123  * connection error.
1124  */
1126 {
1127  int error;
1128  socklen_t socklen = sizeof(error);
1129  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1130 
1131  if (my->info.state == FR_BIO_FD_STATE_OPEN) return 0;
1132 
1133  if (my->info.state != FR_BIO_FD_STATE_CONNECTING) return fr_bio_error(GENERIC);
1134 
1135  /*
1136  * The socket is writeable. Let's see if there's an error.
1137  *
1138  * Unix Network Programming says:
1139  *
1140  * ""If so_error is nonzero when the process calls write, -1 is returned with errno set to the
1141  * value of SO_ERROR (p. 495 of TCPv2) and SO_ERROR is reset to 0. We have to check for the
1142  * error, and if there's no error, set the state to "open". ""
1143  *
1144  * The same applies to connect(). If a non-blocking connect returns INPROGRESS, it may later
1145  * become writable. It will be writable even if the connection fails. Rather than writing some
1146  * random application data, we call SO_ERROR, and get the underlying error.
1147  */
1148  if (getsockopt(my->info.socket.fd, SOL_SOCKET, SO_ERROR, (void *)&error, &socklen) < 0) {
1149  fail:
1151  return fr_bio_error(IO);
1152  }
1153 
1155 
1156  /*
1157  * The socket is connected, so initialize the normal IO handlers.
1158  */
1159  if (fr_bio_fd_init_common(my) < 0) goto fail;
1160 
1161  return 0;
1162 }
1163 
1164 /** Returns a pointer to the bio-specific information.
1165  *
1166  */
1168 {
1169  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1170 
1171  return &my->info;
1172 }
1173 
1174 
1175 /** Discard all reads from a UDP socket.
1176  */
1177 static ssize_t fr_bio_fd_read_discard(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
1178 {
1179  int tries = 0;
1180  ssize_t rcode;
1181  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1182 
1183  my->info.read_blocked = false;
1184 
1185 retry:
1186  rcode = read(my->info.socket.fd, buffer, size);
1187  if (rcode >= 0) return 0;
1188 
1189 #undef flag_blocked
1190 #define flag_blocked info.read_blocked
1191 #include "fd_errno.h"
1192 
1193  return fr_bio_error(IO);
1194 }
1195 
1196 /** Mark up a bio as write-only
1197  *
1198  */
1200 {
1201  fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1202 
1203  switch (my->info.type) {
1204  case FR_BIO_FD_UNCONNECTED:
1205  if (my->info.socket.type != SOCK_DGRAM) {
1206  fr_strerror_const("Only datagram sockets can be marked 'write-only'");
1207  return -1;
1208  }
1209  break;
1210 
1211  case FR_BIO_FD_CONNECTED:
1212  case FR_BIO_FD_ACCEPT:
1213  fr_strerror_const("Only unconnected sockets can be marked 'write-only'");
1214  return -1;
1215  }
1216 
1217  my->bio.read = fr_bio_fd_read_discard;
1218  return 0;
1219 }
static int const char char buffer[256]
Definition: acutest.h:574
fr_bio_write_t _CONST write
write to the underlying bio
Definition: base.h:107
fr_bio_read_t _CONST read
read from the underlying bio
Definition: base.h:106
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition: base.h:112
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition: base.h:121
#define fr_bio_error(_x)
Definition: base.h:184
Definition: base.h:103
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition: build.h:320
#define DIAG_ON(_x)
Definition: build.h:419
#define UNUSED
Definition: build.h:313
#define DIAG_OFF(_x)
Definition: build.h:418
static fr_slen_t in
Definition: dict.h:645
static ssize_t fr_bio_fd_read_discard(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Discard all reads from a UDP socket.
Definition: fd.c:1177
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
Definition: fd.c:1167
static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
Write to fd.
Definition: fd.c:210
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
Definition: fd.c:646
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_cb_funcs_t *cb, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
Definition: fd.c:1018
#define ADDR_INIT
Definition: fd.c:84
int fr_bio_fd_init_accept(fr_bio_fd_t *my)
Definition: fd.c:966
int fr_bio_fd_connect(fr_bio_t *bio)
Finalize a connect()
Definition: fd.c:1125
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
Definition: fd.c:782
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.
Definition: fd.c:148
static ssize_t fr_bio_fd_try_connect(fr_bio_fd_t *my)
Try to connect().
Definition: fd.c:682
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.
Definition: fd.c:169
#define SOL_IP
Definition: fd.c:33
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.
Definition: fd.c:251
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
Definition: fd.c:628
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()
Definition: fd.c:893
static int fr_bio_fd_init_file(fr_bio_fd_t *my)
Files are a special case of connected sockets.
Definition: fd.c:748
static int fr_bio_fd_destructor(fr_bio_fd_t *my)
Definition: fd.c:94
int fr_bio_fd_init_common(fr_bio_fd_t *my)
Definition: fd.c:845
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
Definition: fd.c:1199
int fr_bio_fd_close(fr_bio_t *bio)
Close the FD, but leave the bio allocated and alive.
Definition: fd.c:1062
static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Stream read.
Definition: fd.c:109
fr_socket_t socket
as connected socket
Definition: fd.h:108
bool eof
are we at EOF?
Definition: fd.h:116
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition: fd.h:64
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
Definition: fd.h:61
@ FR_BIO_FD_ACCEPT
returns new fd in buffer on fr_bio_read()
Definition: fd.h:65
fr_bio_fd_type_t type
type of the socket
Definition: fd.h:110
fr_bio_fd_state_t state
connecting, open, closed, etc.
Definition: fd.h:112
@ FR_BIO_FD_STATE_CLOSED
Definition: fd.h:55
@ FR_BIO_FD_STATE_CONNECTING
Definition: fd.h:57
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Definition: fd.h:56
fr_bio_fd_config_t const * cfg
so we know what was asked, vs what was granted.
Definition: fd.h:118
bool read_blocked
did we block on read?
Definition: fd.h:114
#define AF_FILE_BIO
Definition: fd.h:37
int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
Opens a socket and updates sock->fd.
Definition: fd_open.c:717
fr_socket_t socket
socket information, including FD.
Definition: fd.h:49
bool async
is it async
Definition: fd.h:100
bool write_blocked
did we block on write?
Definition: fd.h:115
int flags
O_RDONLY, etc.
Definition: fd.h:98
Configuration for sockets.
Definition: fd.h:76
Run-time status of the socket.
Definition: fd.h:107
Per-packet context.
Definition: fd.h:48
size_t offset
where fr_bio_fd_packet_ctx_t is stored
Definition: fd_priv.h:42
fr_bio_fd_info_t info
Definition: fd_priv.h:39
int max_tries
how many times we retry on EINTR
Definition: fd_priv.h:41
#define fr_bio_fd_packet_ctx(_my, _packet_ctx)
Definition: fd_priv.h:51
Our FD bio structure.
Definition: fd_priv.h:35
void fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
Definition: inet.c:1472
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.
Definition: inet.c:1427
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition: inet.c:62
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.
Definition: inet.c:1378
ssize_t fr_bio_eof_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
Always returns EOF on fr_bio_read()
Definition: base.c:49
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition: base.c:152
talloc_free(reap)
long int ssize_t
Definition: merged_model.c:24
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.
Definition: null.c:39
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.
Definition: null.c:31
static fr_bio_t * bio
Definition: radclient-ng.c:86
static char const * proto(int id, int porttype)
Definition: radwho.c:85
return
Definition: module.c:186
fr_assert(0)
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
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)
Definition: time.h:894
#define fr_time_wrap(_time)
Definition: time.h:145
#define fr_time_eq(_a, _b)
Definition: time.h:241
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)
Definition: time.h:876
"server local" time.
Definition: time.h:69
close(uq->fd)
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition: socket.h:78
int fd
File descriptor if this is a live socket.
Definition: socket.h:81
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition: socket.h:79
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223