The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: f1eb33d5425b8eff530cfd9b39a593e9b1048781 $
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 FR_TIMER_DELETE(&my->connect.ev);
104 if (my->connect.el) {
105 (void) fr_event_fd_delete(my->connect.el, my->info.socket.fd, FR_EVENT_FILTER_IO);
106 my->connect.el = NULL;
107 }
108
109 if (my->cb.shutdown) my->cb.shutdown(&my->bio);
110
111 return fr_bio_fd_close(&my->bio);
112}
113
114static int fr_bio_fd_eof(fr_bio_t *bio)
115{
116 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
117
118 my->info.eof = true;
119
120 bio->read = fr_bio_null_read;
122
123 /*
124 * Nothing more for us to do, tell fr_bio_eof() that it can continue with poking other BIOs.
125 */
126 return 1;
127}
128
130{
131 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
132
133 my->info.write_blocked = false;
134 return 1;
135}
136
137/** Stream read.
138 *
139 * Stream sockets return 0 at EOF. However, we want to distinguish that from the case of datagram
140 * sockets, which return 0 when there's no data. So we return 0 to the caller for "no data", but also
141 * call the EOF function to tell all of the related BIOs that we're at EOF.
142 */
143static ssize_t fr_bio_fd_read_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
144{
145 int tries = 0;
146 ssize_t rcode;
147 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
148
149retry:
150 rcode = read(my->info.socket.fd, buffer, size);
151 if (rcode == 0) {
152 fr_bio_eof(bio);
153 return 0;
154 }
155
156#include "fd_read.h"
157
158 return fr_bio_error(IO);
159}
160
161/** Connected datagram read.
162 *
163 * The difference between this and stream protocols is that for datagrams. a read of zero means "no packets",
164 * where a read of zero on a steam socket means "EOF".
165 *
166 * Connected sockets do _not_ update per-packet contexts.
167 *
168 * Note that for UDP, connect() only affects the sending path. It
169 * means that the application can call send() without specifying IP
170 * addresses. But when the application calls recv(), the OS will
171 * deliver packets which have been sent from _any_ port, even ones
172 * which don't match the address given in connect().
173 *
174 * As a result, this function has to check the received remote IP
175 * against the expected remote IP. If they don't match, then we
176 * can't accept the packet.
177 *
178 * This ALSO means that we should NOT use connected UDP sockets when
179 * the source IP address+port is reused via SO_REUSEPORT.
180 */
181static ssize_t fr_bio_fd_read_connected_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
182{
183 int tries = 0;
184 ssize_t rcode;
185 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
186 socklen_t salen;
187 struct sockaddr_storage sockaddr;
188
189#ifdef STATIC_ANALYZER
190 sockaddr = (struct sockaddr_storage) {};
191#endif
192
193retry:
194 salen = sizeof(sockaddr);
195
196 rcode = recvfrom(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, &salen);
197 if (rcode > 0) {
198 fr_assert(salen == my->remote_sockaddr_len);
199 fr_assert(sockaddr.ss_family == my->remote_sockaddr.ss_family);
200 fr_assert((sockaddr.ss_family == AF_INET) || (sockaddr.ss_family == AF_INET6)); /* datagram unix is not supported */
201
202 /*
203 * Some _other_ client sent this socket a packet. Ignore it.
204 */
205 if (fr_sockaddr_cmp(&sockaddr, &my->remote_sockaddr) != 0) return 0;
206 }
207
208 if (rcode == 0) return rcode;
209
210#include "fd_read.h"
211
212 return fr_bio_error(IO);
213}
214
215/** Read from a UDP socket where we know our IP
216 */
217static ssize_t fr_bio_fd_recvfrom(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
218{
219 int tries = 0;
220 ssize_t rcode;
221 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
222 socklen_t salen;
223 struct sockaddr_storage sockaddr;
224
225retry:
226 salen = sizeof(sockaddr);
227
228 rcode = recvfrom(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, &salen);
229 if (rcode > 0) {
231
232 ADDR_INIT;
233
234 addr->socket.inet.dst_ipaddr = my->info.socket.inet.src_ipaddr;
235 addr->socket.inet.dst_port = my->info.socket.inet.src_port;
236
237 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
238 &sockaddr, salen);
239 }
240
241 if (rcode == 0) return rcode;
242
243#include "fd_read.h"
244
245 return fr_bio_error(IO);
246}
247
248/** Write to fd.
249 *
250 * This function is used for connected sockets, where we ignore the packet_ctx.
251 */
252static ssize_t fr_bio_fd_write(fr_bio_t *bio, UNUSED void *packet_ctx, const void *buffer, size_t size)
253{
254 int tries = 0;
255 ssize_t rcode;
256 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
257
258 /*
259 * FD bios do nothing on flush.
260 */
261 if (!buffer) return 0;
262
263retry:
264 /*
265 * We could call send() instead of write()! Posix says:
266 *
267 * "A write was attempted on a socket that is shut down for writing, or is no longer
268 * connected. In the latter case, if the socket is of type SOCK_STREAM, a SIGPIPE signal shall
269 * also be sent to the thread."
270 *
271 * We can override this behavior by calling send(), and passing the special flag which says
272 * "don't do that!". The system call will then return EPIPE, which indicates that the socket is
273 * no longer usable.
274 *
275 * However, we also set the SO_NOSIGPIPE socket option, which means that we can just call write()
276 * here.
277 */
278 rcode = write(my->info.socket.fd, buffer, size);
279
280#include "fd_write.h"
281
282 return fr_bio_error(IO);
283}
284
285/** Write to a UDP socket where we know our IP
286 *
287 */
288static ssize_t fr_bio_fd_sendto(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
289{
290 int tries = 0;
291 ssize_t rcode;
292 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
294 socklen_t salen;
295 struct sockaddr_storage sockaddr;
296
297 /*
298 * FD bios do nothing on flush.
299 */
300 if (!buffer) return 0;
301
302 // get destination IP
303 (void) fr_ipaddr_to_sockaddr(&sockaddr, &salen, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
304
305retry:
306 rcode = sendto(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, salen);
307
308#include "fd_write.h"
309
310 return fr_bio_error(IO);
311}
312
313
314#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) || defined(IPV6_PKTINFO)
315static ssize_t fd_fd_recvfromto_common(fr_bio_fd_t *my, void *packet_ctx, void *buffer, size_t size)
316{
317 int tries = 0;
318 ssize_t rcode;
319 struct sockaddr_storage from;
321
322#ifdef STATIC_ANALYZER
323 from.ss_family = AF_UNSPEC;
324#endif
325
326 memset(&my->cbuf, 0, sizeof(my->cbuf));
327 memset(&my->msgh, 0, sizeof(struct msghdr));
328
329 my->iov = (struct iovec) {
330 .iov_base = buffer,
331 .iov_len = size,
332 };
333
334 my->msgh = (struct msghdr) {
335 .msg_control = my->cbuf,
336 .msg_controllen = sizeof(my->cbuf),
337 .msg_name = &from,
338 .msg_namelen = sizeof(from),
339 .msg_iov = &my->iov,
340 .msg_iovlen = 1,
341 .msg_flags = 0,
342 };
343
344retry:
345 rcode = recvmsg(my->info.socket.fd, &my->msgh, 0);
346 if (rcode > 0) {
347 ADDR_INIT;
348
349 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
350 &from, my->msgh.msg_namelen);
351 }
352
353 if (rcode == 0) return rcode;
354
355#include "fd_read.h"
356
357 return fr_bio_error(IO);
358}
359#endif
360
361#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
362
363/** Read from a UDP socket where we can change our IP, IPv4 version.
364 */
365static ssize_t fr_bio_fd_recvfromto4(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
366{
367 ssize_t rcode;
368 struct cmsghdr *cmsg;
369 fr_time_t when = fr_time_wrap(0);
370 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
372
373 rcode = fd_fd_recvfromto_common(my, packet_ctx, buffer, size);
374 if (rcode <= 0) return rcode;
375
376DIAG_OFF(sign-compare)
377 /* Process auxiliary received data in msgh */
378 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
379 cmsg != NULL;
380 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
381DIAG_ON(sign-compare)
382
383#ifdef IP_PKTINFO
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;
388
389 to.sin_addr = i->ipi_addr;
390
391 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
392 (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in));
393 addr->socket.inet.ifindex = i->ipi_ifindex;
394 break;
395 }
396#endif
397
398#ifdef IP_RECVDSTADDR
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;
403
404 to.sin_addr = *i;
405 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
406 (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in));
407 break;
408 }
409#endif
410
411#ifdef SO_TIMESTAMPNS
412 if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
413 when = fr_time_from_timespec((struct timespec *)CMSG_DATA(cmsg));
414 }
415
416#elif defined(SO_TIMESTAMP)
417 if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
418 when = fr_time_from_timeval((struct timeval *)CMSG_DATA(cmsg));
419 }
420#endif
421 }
422
423 if fr_time_eq(when, fr_time_wrap(0)) when = fr_time();
424
425 addr->when = when;
426
427 return rcode;
428}
429
430/** Send to UDP socket where we can change our IP, IPv4 version.
431 */
432static ssize_t fr_bio_fd_sendfromto4(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
433{
434 int tries = 0;
435 ssize_t rcode;
436 struct cmsghdr *cmsg;
437 struct sockaddr_storage to;
438 socklen_t to_len;
439 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
441
442 memset(&my->cbuf, 0, sizeof(my->cbuf));
443 memset(&my->msgh, 0, sizeof(struct msghdr));
444
445 (void) fr_ipaddr_to_sockaddr(&to, &to_len, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
446
447 my->iov = (struct iovec) {
448 .iov_base = UNCONST(void *, buffer),
449 .iov_len = size,
450 };
451
452 my->msgh = (struct msghdr) {
453 .msg_control = my->cbuf,
454 // controllen is set below
455 .msg_name = &to,
456 .msg_namelen = to_len,
457 .msg_iov = &my->iov,
458 .msg_iovlen = 1,
459 .msg_flags = 0,
460 };
461
462 {
463#ifdef IP_PKTINFO
464 struct in_pktinfo *pkt;
465
466 my->msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
467
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));
472
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;
477
478#elif defined(IP_SENDSRCADDR)
479 struct in_addr *in;
480
481 my->msgh.msg_controllen = CMSG_SPACE(sizeof(*in));
482
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));
487
488 in = (struct in_addr *) CMSG_DATA(cmsg);
489 *in = addr->socket.inet.src_ipaddr.addr.v4;
490#endif
491 }
492
493retry:
494 rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
495
496#include "fd_write.h"
497
498 return fr_bio_error(IO);
499}
500
501static inline int fr_bio_fd_udpfromto_init4(int fd)
502{
503 int proto = 0, flag = 0, opt = 1;
504
505#ifdef HAVE_IP_PKTINFO
506 /*
507 * Linux
508 */
509 proto = SOL_IP;
510 flag = IP_PKTINFO;
511
512#elif defined(IP_RECVDSTADDR)
513 /*
514 * Set the IP_RECVDSTADDR option (BSD). Note:
515 * IP_RECVDSTADDR == IP_SENDSRCADDR
516 */
517 proto = IPPROTO_IP;
518 flag = IP_RECVDSTADDR;
519#endif
520
521 return setsockopt(fd, proto, flag, &opt, sizeof(opt));
522}
523#endif
524
525#if defined(IPV6_PKTINFO)
526/** Read from a UDP socket where we can change our IP, IPv4 version.
527 */
528static ssize_t fr_bio_fd_recvfromto6(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
529{
530 ssize_t rcode;
531 struct cmsghdr *cmsg;
532 fr_time_t when = fr_time_wrap(0);
533 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
535
536 rcode = fd_fd_recvfromto_common(my, packet_ctx, buffer, size);
537 if (rcode <= 0) return rcode;
538
539DIAG_OFF(sign-compare)
540 /* Process auxiliary received data in msgh */
541 for (cmsg = CMSG_FIRSTHDR(&my->msgh);
542 cmsg != NULL;
543 cmsg = CMSG_NXTHDR(&my->msgh, cmsg)) {
544DIAG_ON(sign-compare)
545
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;
550
551 to.sin6_addr = i->ipi6_addr;
552
553 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.dst_ipaddr, &addr->socket.inet.dst_port,
554 (struct sockaddr_storage *) &to, sizeof(struct sockaddr_in6));
555 addr->socket.inet.ifindex = i->ipi6_ifindex;
556 break;
557 }
558
559#ifdef SO_TIMESTAMPNS
560 if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
561 when = fr_time_from_timespec((struct timespec *)CMSG_DATA(cmsg));
562 }
563
564#elif defined(SO_TIMESTAMP)
565 if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
566 when = fr_time_from_timeval((struct timeval *)CMSG_DATA(cmsg));
567 }
568#endif
569 }
570
571 if fr_time_eq(when, fr_time_wrap(0)) when = fr_time();
572
573 addr->when = when;
574
575 return rcode;
576}
577
578/** Send to UDP socket where we can change our IP, IPv4 version.
579 */
580static ssize_t fr_bio_fd_sendfromto6(fr_bio_t *bio, void *packet_ctx, const void *buffer, size_t size)
581{
582 int tries = 0;
583 ssize_t rcode;
584 struct cmsghdr *cmsg;
585 struct sockaddr_storage to;
586 socklen_t to_len;
587 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
589
590 memset(&my->cbuf, 0, sizeof(my->cbuf));
591 memset(&my->msgh, 0, sizeof(struct msghdr));
592
593 (void) fr_ipaddr_to_sockaddr(&to, &to_len, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
594
595 my->iov = (struct iovec) {
596 .iov_base = UNCONST(void *, buffer),
597 .iov_len = size,
598 };
599
600 my->msgh = (struct msghdr) {
601 .msg_control = my->cbuf,
602 // controllen is set below
603 .msg_name = &to,
604 .msg_namelen = to_len,
605 .msg_iov = &my->iov,
606 .msg_iovlen = 1,
607 .msg_flags = 0,
608 };
609
610 {
611 struct in6_pktinfo *pkt;
612
613 my->msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
614
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));
619
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;
624 }
625
626retry:
627 rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
628
629#include "fd_write.h"
630
631 return fr_bio_error(IO);
632}
633
634
635static inline int fr_bio_fd_udpfromto_init6(int fd)
636{
637 int opt = 1;
638
639 return setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt));
640}
641#endif
642
643int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
644{
645 size_t len;
646
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");
650 return -1;
651 }
652
653 sun->sun_family = AF_LOCAL;
654 memcpy(sun->sun_path, filename, len + 1); /* SUN_LEN will do strlen */
655
656 *sunlen = SUN_LEN(sun);
657
658 return 0;
659}
660
662{
663 socklen_t salen;
664 struct sockaddr_storage salocal;
665
666 /*
667 * Already set: do nothing.
668 */
669 if (!fr_ipaddr_is_inaddr_any(&my->info.socket.inet.src_ipaddr) &&
670 (my->info.socket.inet.src_port != 0)) {
671 return 0;
672 }
673
674 /*
675 * FreeBSD jail issues. We bind to 0.0.0.0, but the
676 * kernel instead binds us to a 1.2.3.4. So once the
677 * socket is bound, ask it what it's IP address is.
678 */
679 salen = sizeof(salocal);
680 memset(&salocal, 0, salen);
681 if (getsockname(my->info.socket.fd, (struct sockaddr *) &salocal, &salen) < 0) {
682 fr_strerror_printf("Failed getting socket name: %s", fr_syserror(errno));
683 return -1;
684 }
685
686 if (fr_ipaddr_from_sockaddr(&my->info.socket.inet.src_ipaddr, &my->info.socket.inet.src_port, &salocal, salen) < 0) return -1;
687
688 fr_ipaddr_get_scope_id(&my->info.socket.inet.src_ipaddr);
689 my->info.socket.inet.ifindex = my->info.socket.inet.src_ipaddr.scope_id;
690
691 return 0;
692}
693
695{
696 my->info.state = FR_BIO_FD_STATE_OPEN;
697 my->info.eof = false;
698 my->info.read_blocked = false;
699 my->info.write_blocked = false;
700
701 /*
702 * Tell the caller that the socket is ready for application data.
703 */
704 if (my->cb.connected) my->cb.connected(&my->bio);
705}
706
707
708/** Try to connect().
709 *
710 * If connect is blocking, we either succeed or error immediately. Otherwise, the caller has to select the
711 * socket for writeability, and then call fr_bio_fd_connect() as soon as the socket is writeable.
712 */
714{
715 int tries = 0;
716 int rcode;
717
718 /*
719 * Save a "sockaddr" version of the address of the other end.
720 */
721 if (my->info.socket.af != AF_LOCAL) {
722 rcode = fr_ipaddr_to_sockaddr(&my->remote_sockaddr, &my->remote_sockaddr_len,
723 &my->info.socket.inet.dst_ipaddr, my->info.socket.inet.dst_port);
724 } else {
725 rcode = fr_filename_to_sockaddr((struct sockaddr_un *) &my->remote_sockaddr, &my->remote_sockaddr_len,
726 my->info.socket.unix.path);
727 }
728
729 if (rcode < 0) {
730 fr_bio_shutdown(&my->bio);
731 return fr_bio_error(GENERIC);
732 }
733
734 my->info.state = FR_BIO_FD_STATE_CONNECTING;
735
736retry:
737 if (connect(my->info.socket.fd, (struct sockaddr *) &my->remote_sockaddr, my->remote_sockaddr_len) == 0) {
739
740 /*
741 * The source IP may have changed, so get the new one.
742 */
743 if (fr_bio_fd_socket_name(my) < 0) goto fail;
744
745 if (fr_bio_fd_init_common(my) < 0) goto fail;
746
747 return 0;
748 }
749
750 switch (errno) {
751 case EINTR:
752 tries++;
753 if (tries <= my->max_tries) goto retry;
755
756 /*
757 * This shouldn't happen, but we'll allow it
758 */
759 case EALREADY:
761
762 /*
763 * Once the socket is writable, it will be active, or in an error state. The caller has
764 * to call fr_bio_fd_connect() before calling write()
765 */
766 case EINPROGRESS:
767 if (!my->info.write_blocked) {
768 my->info.write_blocked = true;
769
770 rcode = fr_bio_write_blocked((fr_bio_t *) my);
771 if (rcode < 0) return rcode;
772 }
773
774 return fr_bio_error(IO_WOULD_BLOCK);
775
776 default:
777 break;
778 }
779
780fail:
781 fr_bio_shutdown(&my->bio);
782 return fr_bio_error(IO);
783}
784
785
786/** Files are a special case of connected sockets.
787 *
788 */
790{
792
793 /*
794 * Other flags may be O_CREAT, etc.
795 */
796 switch (my->info.cfg->flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
797 case O_RDONLY:
798 my->bio.read = fr_bio_fd_read_stream;
799 my->bio.write = fr_bio_fail_write;
800 break;
801
802 case O_WRONLY:
803 my->bio.read = fr_bio_fail_read;
804 my->bio.write = fr_bio_fd_write;
805 break;
806
807 case O_RDWR:
808 my->bio.read = fr_bio_fd_read_stream;
809 my->bio.write = fr_bio_fd_write;
810 break;
811
812 default:
813 fr_strerror_const("Invalid flag for opening file");
814 return -1;
815 }
816
817 return 0;
818}
819
821{
822 int rcode;
823
824 if (my->info.socket.af == AF_FILE_BIO) return fr_bio_fd_init_file(my);
825
826 /*
827 * The source IP can be unspecified. It will get updated after we call connect().
828 */
829
830 /*
831 * All connected sockets must have a destination IP.
832 */
833 if (fr_ipaddr_is_inaddr_any(&my->info.socket.inet.dst_ipaddr)) {
834 fr_strerror_const("Destination IP address cannot be wildcard");
835 return -1;
836 }
837
838 /*
839 * Don't do any reads until we're connected.
840 */
841 my->bio.read = fr_bio_null_read;
842 my->bio.write = fr_bio_null_write;
843
844 my->info.eof = false;
845
846 my->info.read_blocked = false;
847 my->info.write_blocked = false;
848
849#ifdef SO_NOSIGPIPE
850 /*
851 * Although the server ignore SIGPIPE, some operating systems like BSD and OSX ignore the
852 * ignoring.
853 *
854 * Fortunately, those operating systems usually support SO_NOSIGPIPE. We set that to prevent
855 * them raising the signal in the first place.
856 */
857 {
858 int on = 1;
859
860 setsockopt(my->info.socket.fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
861 }
862#endif
863
864 /*
865 * Don't call connect() if the socket is synchronous, it will block.
866 */
867 if (!my->info.cfg->async) return 0;
868
869 rcode = fr_bio_fd_try_connect(my);
870 if (rcode == 0) return 0;
871
872 if (rcode != fr_bio_error(IO_WOULD_BLOCK)) return rcode;
873
874 /*
875 * The socket is blocked, and should be selected for writing.
876 */
877 fr_assert(my->info.write_blocked);
879
880 return 0;
881}
882
884{
885 if (my->info.socket.type == SOCK_STREAM) { //!< stream socket
886 my->bio.read = fr_bio_fd_read_stream;
887 my->bio.write = fr_bio_fd_write;
888
889 } else if (my->info.type == FR_BIO_FD_CONNECTED) { //!< connected datagram
891 my->bio.write = fr_bio_fd_write;
892
893 } else if (!fr_ipaddr_is_inaddr_any(&my->info.socket.inet.src_ipaddr)) { //!< we know our IP address
894 my->bio.read = fr_bio_fd_recvfrom;
895 my->bio.write = fr_bio_fd_sendto;
896
897#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
898 } else if (my->info.socket.inet.src_ipaddr.af == AF_INET) { //!< we don't know our IPv4
899 if (fr_bio_fd_udpfromto_init4(my->info.socket.fd) < 0) return -1;
900
901 my->bio.read = fr_bio_fd_recvfromto4;
902 my->bio.write = fr_bio_fd_sendfromto4;
903#endif
904
905#if defined(IPV6_PKTINFO)
906 } else if (my->info.socket.inet.src_ipaddr.af == AF_INET6) { //!< we don't know our IPv6
907
908 if (fr_bio_fd_udpfromto_init6(my->info.socket.fd) < 0) return -1;
909
910 my->bio.read = fr_bio_fd_recvfromto6;
911 my->bio.write = fr_bio_fd_sendfromto6;
912#endif
913
914 } else {
915 fr_strerror_const("Failed initializing socket: cannot determine what to do");
916 return -1;
917 }
918
920
921 return 0;
922}
923
924/** Return an fd on read()
925 *
926 * With packet_ctx containing information about the socket.
927 */
928static ssize_t fr_bio_fd_read_accept(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
929{
930 int fd, tries = 0;
931 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
932 socklen_t salen;
933 struct sockaddr_storage sockaddr;
934
935 if (size < sizeof(int)) return fr_bio_error(BUFFER_TOO_SMALL);
936
937 salen = sizeof(sockaddr);
938
939retry:
940#ifdef __linux__
941 /*
942 * Set these flags immediately on the new socket.
943 */
944 fd = accept4(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen, SOCK_NONBLOCK | SOCK_CLOEXEC);
945#else
946 fd = accept(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen);
947#endif
948 if (fd >= 0) {
950
951 ADDR_INIT;
952
953 (void) fr_ipaddr_from_sockaddr(&addr->socket.inet.src_ipaddr, &addr->socket.inet.src_port,
954 &sockaddr, salen);
955
956 addr->socket.inet.dst_ipaddr = my->info.socket.inet.src_ipaddr;
957 addr->socket.inet.dst_port = my->info.socket.inet.src_port;
958 addr->socket.fd = fd; /* might as well! */
959
960 *(int *) buffer = fd;
961 return sizeof(int);
962 }
963
964 switch (errno) {
965 case EINTR:
966 /*
967 * Try a few times before giving up.
968 */
969 tries++;
970 if (tries <= my->max_tries) goto retry;
971 return 0;
972
973 /*
974 * We can ignore these errors.
975 */
976 case ECONNABORTED:
977#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
978 case EWOULDBLOCK:
979#endif
980 case EAGAIN:
981#ifdef EPERM
982 case EPERM:
983#endif
984#ifdef ETIMEDOUT
985 case ETIMEDOUT:
986#endif
987 return 0;
988
989 default:
990 /*
991 * Some other error, it's fatal.
992 */
993 fr_bio_shutdown(&my->bio);
994 break;
995 }
996
997 return fr_bio_error(IO);
998}
999
1000
1002{
1003 my->bio.read = fr_bio_fd_read_accept;
1004 my->bio.write = fr_bio_null_write;
1005
1006 if (listen(my->info.socket.fd, 8) < 0) {
1007 fr_strerror_printf("Failed opening setting FD_CLOEXE: %s", fr_syserror(errno));
1008 return -1;
1009 }
1010
1012
1013 return 0;
1014}
1015
1016/** Allocate a FD bio
1017 *
1018 * The caller is responsible for tracking the FD, and all associated management of it. The bio API is
1019 * intended to be simple, and does not provide wrapper functions for various ioctls. The caller should
1020 * instead do that work.
1021 *
1022 * Once the FD is give to the bio, its lifetime is "owned" by the bio. Calling talloc_free(bio) will close
1023 * the FD.
1024 *
1025 * The caller can still manage the FD for being readable / writeable. However, the caller should not call
1026 * this bio directly (unless it is the only one). Instead, the caller should read from / write to the
1027 * previous bio which will then eventually call this one.
1028 *
1029 * Before updating any event handler readable / writeable callbacks, the caller should check
1030 * fr_bio_fd_at_eof(). If true, then the handlers should not be inserted. The previous bios should still be
1031 * called to process any pending data, until they return EOF.
1032 *
1033 * The main purpose of an FD bio is to wrap the FD in a bio container. That, and handling retries on read /
1034 * write, along with returning EOF as an error instead of zero.
1035 *
1036 * Note that the read / write functions can return partial data. It is the callers responsibility to ensure
1037 * that any writes continue from where they left off (otherwise dat awill be missing). And any partial reads
1038 * should go to a memory bio.
1039 *
1040 * If a read returns EOF, then the FD remains open until talloc_free(bio) or fr_bio_fd_close() is called.
1041 *
1042 * @param ctx the talloc ctx
1043 * @param cfg structure holding configuration information
1044 * @param offset only for unconnected datagram sockets, where #fr_bio_fd_packet_ctx_t is stored
1045 * @return
1046 * - NULL on error, memory allocation failed
1047 * - !NULL the bio
1048 */
1049fr_bio_t *fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
1050{
1051 fr_bio_fd_t *my;
1052
1053 my = talloc_zero(ctx, fr_bio_fd_t);
1054 if (!my) return NULL;
1055
1056 my->max_tries = 4;
1057 my->offset = offset;
1058
1059 if (!cfg) {
1060 /*
1061 * Add place-holder information.
1062 */
1063 my->info = (fr_bio_fd_info_t) {
1064 .socket = {
1065 .af = AF_UNSPEC,
1066 },
1067 .type = FR_BIO_FD_UNCONNECTED,
1068 .read_blocked = false,
1069 .write_blocked = false,
1070 .eof = false,
1071 .state = FR_BIO_FD_STATE_CLOSED,
1072 };
1073
1074 my->bio.read = fr_bio_null_read;
1075 my->bio.write = fr_bio_null_write;
1076 } else {
1077 my->info.state = FR_BIO_FD_STATE_CLOSED;
1078
1079 if (fr_bio_fd_open(&my->bio, cfg) < 0) {
1080 talloc_free(my);
1081 return NULL;
1082 }
1083 }
1084
1085 my->priv_cb.eof = fr_bio_fd_eof;
1086 my->priv_cb.write_resume = fr_bio_fd_write_resume;
1087
1088 talloc_set_destructor(my, fr_bio_fd_destructor);
1089 return (fr_bio_t *) my;
1090}
1091
1092/** Close the FD, but leave the bio allocated and alive.
1093 *
1094 */
1096{
1097 int rcode;
1098 int tries = 0;
1099 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1100
1101 if (my->info.state == FR_BIO_FD_STATE_CLOSED) return 0;
1102
1103 /*
1104 * Shut the bio down cleanly.
1105 */
1106 rcode = fr_bio_shutdown(bio);
1107 if (rcode < 0) return rcode;
1108
1109 my->bio.read = fr_bio_fail_read;
1110 my->bio.write = fr_bio_fail_write;
1111
1112 /*
1113 * Shut down the connected socket. The only errors possible here are things we can't do anything
1114 * about.
1115 *
1116 * shutdown() will close ALL versions of this file descriptor, even if it's (somehow) used in
1117 * another process. shutdown() will also tell the kernel to gracefully close the connected
1118 * socket, so that it can signal the other end, instead of having the connection disappear.
1119 *
1120 * This shouldn't strictly be necessary, as no other processes should be sharing this file
1121 * descriptor. But it's the safe (and polite) thing to do.
1122 */
1123 if (my->info.type == FR_BIO_FD_CONNECTED) {
1124 (void) shutdown(my->info.socket.fd, SHUT_RDWR);
1125 }
1126
1127retry:
1128 rcode = close(my->info.socket.fd);
1129 if (rcode < 0) {
1130 switch (errno) {
1131 case EINTR:
1132 case EIO:
1133 tries++;
1134 if (tries < my->max_tries) goto retry;
1135 return -1;
1136
1137 default:
1138 /*
1139 * EBADF, or other unrecoverable error. We just call it closed, and continue.
1140 */
1141 break;
1142 }
1143 }
1144
1145 my->info.state = FR_BIO_FD_STATE_CLOSED;
1146 my->info.read_blocked = true;
1147 my->info.write_blocked = true;
1148 my->info.eof = true;
1149
1150 return 0;
1151}
1152
1153/** FD error when trying to connect, give up on the BIO.
1154 *
1155 */
1156static void fr_bio_fd_el_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
1157{
1158 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1159
1160 my->info.connect_errno = fd_errno;
1161
1162 if (my->connect.error) {
1163 my->connect.error(&my->bio);
1164 }
1165
1166 fr_bio_shutdown(&my->bio);
1167}
1168
1169/** Connect callback for when the socket is writable.
1170 *
1171 * We try to connect the socket, and if so, call the application which should update the BIO status.
1172 */
1174{
1175 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1176
1177 fr_assert(my->info.type == FR_BIO_FD_CONNECTED);
1178 fr_assert(my->info.state == FR_BIO_FD_STATE_CONNECTING);
1179 fr_assert(my->connect.el == el); /* and not NULL */
1180 fr_assert(my->connect.success != NULL);
1181 fr_assert(my->info.socket.fd == fd);
1182
1183#ifndef NDEBUG
1184 /*
1185 * This check shouldn't be necessary, as we have a kqeueue error callback. That should be called
1186 * when there's a connect error.
1187 */
1188 {
1189 int error;
1190 socklen_t socklen = sizeof(error);
1191
1192 /*
1193 * The socket is writeable. Let's see if there's an error.
1194 *
1195 * Unix Network Programming says:
1196 *
1197 * ""If so_error is nonzero when the process calls write, -1 is returned with errno set to the
1198 * value of SO_ERROR (p. 495 of TCPv2) and SO_ERROR is reset to 0. We have to check for the
1199 * error, and if there's no error, set the state to "open". ""
1200 *
1201 * The same applies to connect(). If a non-blocking connect returns INPROGRESS, it may later
1202 * become writable. It will be writable even if the connection fails. Rather than writing some
1203 * random application data, we call SO_ERROR, and get the underlying error.
1204 */
1205 if (getsockopt(my->info.socket.fd, SOL_SOCKET, SO_ERROR, (void *)&error, &socklen) < 0) {
1206 fr_bio_fd_el_error(el, fd, flags, errno, uctx);
1207 return;
1208 }
1209
1210 fr_assert(error == 0);
1211
1212 /*
1213 * There was an error, we call the error handler.
1214 */
1215 if (error) {
1216 fr_bio_fd_el_error(el, fd, flags, error, uctx);
1217 return;
1218 }
1219 }
1220#endif
1221
1222 /*
1223 * Try to connect it. Any magic handling is done in the callbacks.
1224 */
1225 if (fr_bio_fd_try_connect(my) < 0) return;
1226
1227 fr_assert(my->connect.success);
1228
1229 FR_TIMER_DELETE(&my->connect.ev);
1230 my->connect.el = NULL;
1231
1232 /*
1233 * This function MUST change the read/write/error callbacks for the FD.
1234 */
1235 my->connect.success(&my->bio);
1236}
1237
1238/** We have a timeout on the conenction
1239 *
1240 */
1242{
1243 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1244
1245 fr_assert(my->connect.timeout);
1246
1247 my->connect.timeout(&my->bio);
1248
1249 fr_bio_shutdown(&my->bio);
1250}
1251
1252
1253/** Finalize a connect()
1254 *
1255 * connect() said "come back when the socket is writeable". It's now writeable, so we check if there was a
1256 * connection error.
1257 *
1258 * @param bio the binary IO handler
1259 * @param el the event list
1260 * @param connected_cb callback to run when the BIO is connected
1261 * @param error_cb callback to run when the FD has an error
1262 * @param timeout when to time out the connect() attempt
1263 * @param timeout_cb to call when the timeout runs.
1264 * @return
1265 * - <0 on error
1266 * - 0 for "try again later". If callbacks are set, the callbacks will try again. Otherwise the application has to try again.
1267 * - 1 for "we are now connected".
1268 */
1270 fr_bio_callback_t error_cb,
1271 fr_time_delta_t *timeout, fr_bio_callback_t timeout_cb)
1272{
1273 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1274
1275 /*
1276 * We shouldn't be connected an unconnected socket.
1277 */
1278 if (my->info.type == FR_BIO_FD_UNCONNECTED) {
1279 error:
1280#ifdef ECONNABORTED
1281 my->info.connect_errno = ECONNABORTED;
1282#else
1283 my->info.connect_errno = ECONNREFUSED;
1284#endif
1285 if (error_cb) error_cb(bio);
1286 fr_bio_shutdown(&my->bio);
1287 return fr_bio_error(GENERIC);
1288 }
1289
1290 /*
1291 * The initial open may have succeeded in connecting the socket. In which case we just run the
1292 * callbacks and return.
1293 */
1294 if (my->info.state == FR_BIO_FD_STATE_OPEN) {
1295 connected:
1296 if (connected_cb) connected_cb(bio);
1297
1298 return 1;
1299 }
1300
1301 /*
1302 * The caller may just call us without caring about what the underlying BIO is. In which case we
1303 * need to be safe.
1304 */
1305 if ((my->info.socket.af == AF_FILE_BIO) || (my->info.type == FR_BIO_FD_LISTEN)) {
1307 goto connected;
1308 }
1309
1310 /*
1311 * It must be in the connecting state, i.e. not INVALID or CLOSED.
1312 */
1313 if (my->info.state != FR_BIO_FD_STATE_CONNECTING) goto error;
1314
1315 /*
1316 * No callback
1317 */
1318 if (!connected_cb) {
1319 ssize_t rcode;
1320
1321 rcode = fr_bio_fd_try_connect(my);
1322 if (rcode < 0) {
1323 if (error_cb) error_cb(bio);
1324 return rcode; /* it already called shutdown */
1325 }
1326
1327 return 1;
1328 }
1329
1330 /*
1331 * It's not connected, the caller has to try again.
1332 */
1333 if (!el) return 0;
1334
1335 /*
1336 * Set the callbacks to run when something happens.
1337 */
1338 my->connect.success = connected_cb;
1339 my->connect.error = error_cb;
1340 my->connect.timeout = timeout_cb;
1341
1342 /*
1343 * Set the timeout callback if asked.
1344 */
1345 if (timeout_cb) {
1346 if (fr_timer_in(my, el->tl, &my->connect.ev, *timeout, false, fr_bio_fd_el_timeout, my) < 0) {
1347 goto error;
1348 }
1349 }
1350
1351 /*
1352 * Set the FD callbacks, and tell the caller that we're not connected.
1353 */
1354 if (fr_event_fd_insert(my, NULL, el, my->info.socket.fd, NULL,
1356 goto error;
1357 }
1358 my->connect.el = el;
1359
1360 return 0;
1361}
1362
1363/** Returns a pointer to the bio-specific information.
1364 *
1365 */
1367{
1368 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1369
1370 return &my->info;
1371}
1372
1373
1374/** Discard all reads from a UDP socket.
1375 */
1376static ssize_t fr_bio_fd_read_discard_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
1377{
1378 int tries = 0;
1379 ssize_t rcode;
1380 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1381
1382retry:
1383 rcode = read(my->info.socket.fd, buffer, size);
1384 if (rcode >= 0) return 0; /* always return that we read no data */
1385
1386#undef flag_blocked
1387#define flag_blocked read_blocked
1388#include "fd_errno.h"
1389
1390 return fr_bio_error(IO);
1391}
1392
1393/** Discard all reads from a TCP socket.
1394 */
1395static ssize_t fr_bio_fd_read_discard_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
1396{
1397 int tries = 0;
1398 ssize_t rcode;
1399 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1400
1401retry:
1402 rcode = read(my->info.socket.fd, buffer, size);
1403 if (rcode > 0 ) return 0; /* always return that we read no data */
1404 if (rcode == 0) {
1405 fr_bio_eof(bio);
1406 return 0;
1407 }
1408
1409#undef flag_blocked
1410#define flag_blocked read_blocked
1411#include "fd_errno.h"
1412
1413 return fr_bio_error(IO);
1414}
1415
1416/** Mark up a bio as write-only
1417 *
1418 */
1420{
1421 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1422
1423 switch (my->info.type) {
1424 case FR_BIO_FD_INVALID:
1425 return -1;
1426
1428 if (my->info.socket.type != SOCK_DGRAM) {
1429 fr_strerror_const("Only datagram sockets can be marked 'write-only'");
1430 return -1;
1431 }
1432 goto set_recv_buff_zero;
1433
1435 case FR_BIO_FD_ACCEPTED:
1436 /*
1437 * Further reads are disallowed. However, this likely has no effect for UDP sockets.
1438 */
1439 if (shutdown(my->info.socket.fd, SHUT_RD) < 0) {
1440 fr_strerror_printf("Failed shutting down connected socket - %s", fr_syserror(errno));
1441 return -1;
1442 }
1443
1444 set_recv_buff_zero:
1445#ifdef __linux__
1446#ifdef SO_RCVBUF
1447 /*
1448 * On Linux setting the receive buffer to zero has the effect of discarding all incoming
1449 * data in the kernel. With macOS and others it's an invalid value.
1450 */
1451 {
1452 int opt = 0;
1453
1454 if (setsockopt(my->info.socket.fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
1455 fr_strerror_printf("Failed setting SO_RCVBUF: %s", fr_syserror(errno));
1456 return -1;
1457 }
1458 }
1459#endif
1460#endif
1461 break;
1462
1463 case FR_BIO_FD_LISTEN:
1464 fr_strerror_const("Only unconnected sockets can be marked 'write-only'");
1465 return -1;
1466 }
1467
1468 /*
1469 * No matter what the possibilities above, we replace the read function with a "discard"
1470 * function.
1471 */
1472 my->bio.read = (my->info.socket.type == SOCK_DGRAM) ? fr_bio_fd_read_discard_datagram : fr_bio_fd_read_discard_stream;
1473 return 0;
1474}
1475
1476/** Alternative to calling fr_bio_read() on new socket.
1477 *
1478 */
1479int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_t *bio)
1480{
1481 int fd, tries = 0;
1482 int rcode;
1483 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1484 socklen_t salen;
1485 struct sockaddr_storage sockaddr;
1487 fr_bio_fd_config_t *cfg;
1488
1489 salen = sizeof(sockaddr);
1490 *out_p = NULL;
1491
1492 fr_assert(my->info.type == FR_BIO_FD_LISTEN);
1493 fr_assert(my->info.socket.type == SOCK_STREAM);
1494
1495retry:
1496#ifdef __linux__
1497 /*
1498 * Set these flags immediately on the new socket.
1499 */
1500 fd = accept4(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen, SOCK_NONBLOCK | SOCK_CLOEXEC);
1501#else
1502 fd = accept(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen);
1503#endif
1504 if (fd < 0) {
1505 switch (errno) {
1506 case EINTR:
1507 /*
1508 * Try a few times before giving up.
1509 */
1510 tries++;
1511 if (tries <= my->max_tries) goto retry;
1512 return 0;
1513
1514 /*
1515 * We can ignore these errors.
1516 */
1517 case ECONNABORTED:
1518#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1519 case EWOULDBLOCK:
1520#endif
1521 case EAGAIN:
1522#ifdef EPERM
1523 case EPERM:
1524#endif
1525#ifdef ETIMEDOUT
1526 case ETIMEDOUT:
1527#endif
1528 return 0;
1529
1530 default:
1531 /*
1532 * Some other error, it's fatal.
1533 */
1534 fr_bio_shutdown(&my->bio);
1535 break;
1536 }
1537
1538 return fr_bio_error(IO);
1539 }
1540
1541 /*
1542 * Allocate the base BIO and set it up.
1543 */
1544 out = (fr_bio_fd_t *) fr_bio_fd_alloc(ctx, NULL, my->offset);
1545 if (!out) {
1546 close(fd);
1547 return fr_bio_error(GENERIC);
1548 }
1549
1550 /*
1551 * We have a file descriptor. Initialize the configuration with the new information.
1552 */
1553 cfg = talloc_memdup(out, my->info.cfg, sizeof(*my->info.cfg));
1554 if (!cfg) {
1555 fr_strerror_const("Out of memory");
1556 close(fd);
1558 return fr_bio_error(GENERIC);
1559 }
1560
1561 /*
1562 * Set the type to ACCEPTED, and set up the rest of the callbacks to match.
1563 */
1564 cfg->type = FR_BIO_FD_ACCEPTED;
1565 out->info.socket.fd = fd;
1566
1567 rcode = fr_bio_fd_open(bio, cfg);
1568 if (rcode < 0) {
1570 return rcode;
1571 }
1572
1573 fr_assert(out->info.type == FR_BIO_FD_CONNECTED);
1574
1575 *out_p = (fr_bio_t *) out;
1576 return 1;
1577}
static int const char char buffer[256]
Definition acutest.h:576
fr_bio_write_t _CONST write
write to the underlying bio
Definition base.h:116
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition base.h:121
fr_bio_read_t _CONST read
read from the underlying bio
Definition base.h:115
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:130
void(* fr_bio_callback_t)(fr_bio_t *bio)
Definition base.h:85
#define fr_bio_error(_x)
Definition base.h:192
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define NDEBUG_UNUSED
Definition build.h:328
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define DIAG_ON(_x)
Definition build.h:460
#define UNUSED
Definition build.h:317
#define DIAG_OFF(_x)
Definition build.h:459
static fr_slen_t in
Definition dict.h:840
#define fr_event_fd_insert(...)
Definition event.h:248
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:84
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()
Definition fd.c:1269
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:252
int fr_bio_fd_socket_name(fr_bio_fd_t *my)
Definition fd.c:661
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.
Definition fd.c:1173
#define ADDR_INIT
Definition fd.c:84
static int fr_bio_fd_write_resume(fr_bio_t *bio)
Definition fd.c:129
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
Definition fd.c:1049
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.
Definition fd.c:1395
int fr_bio_fd_init_connected(fr_bio_fd_t *my)
Definition fd.c:820
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:181
static ssize_t fr_bio_fd_try_connect(fr_bio_fd_t *my)
Try to connect().
Definition fd.c:713
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:217
#define SOL_IP
Definition fd.c:33
static int fr_bio_fd_eof(fr_bio_t *bio)
Definition fd.c:114
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:288
int fr_filename_to_sockaddr(struct sockaddr_un *sun, socklen_t *sunlen, char const *filename)
Definition fd.c:643
int fr_bio_fd_init_listen(fr_bio_fd_t *my)
Definition fd.c:1001
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.
Definition fd.c:1479
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:1366
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:928
static int fr_bio_fd_init_file(fr_bio_fd_t *my)
Files are a special case of connected sockets.
Definition fd.c:789
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.
Definition fd.c:1241
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:883
int fr_bio_fd_write_only(fr_bio_t *bio)
Mark up a bio as write-only.
Definition fd.c:1419
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.
Definition fd.c:1376
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.
Definition fd.c:1156
int fr_bio_fd_close(fr_bio_t *bio)
Close the FD, but leave the bio allocated and alive.
Definition fd.c:1095
static void fr_bio_fd_set_open(fr_bio_fd_t *my)
Definition fd.c:694
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:143
@ FR_BIO_FD_ACCEPTED
temporarily until it's connected.
Definition fd.h:71
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:68
@ FR_BIO_FD_INVALID
not set
Definition fd.h:64
@ FR_BIO_FD_UNCONNECTED
unconnected UDP / datagram only
Definition fd.h:65
@ FR_BIO_FD_LISTEN
returns new fd in buffer on fr_bio_read() or fr_bio_fd_accept()
Definition fd.h:69
@ FR_BIO_FD_STATE_CLOSED
Definition fd.h:58
@ FR_BIO_FD_STATE_CONNECTING
Definition fd.h:60
@ FR_BIO_FD_STATE_OPEN
error states must be before this
Definition fd.h:59
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
Definition fd.h:82
#define AF_FILE_BIO
Definition fd.h:40
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:994
fr_socket_t socket
socket information, including FD.
Definition fd.h:52
Configuration for sockets.
Definition fd.h:81
Run-time status of the socket.
Definition fd.h:129
Per-packet context.
Definition fd.h:51
fr_bio_shutdown & my
Definition fd_errno.h:69
#define fr_bio_fd_packet_ctx(_my, _packet_ctx)
Definition fd_priv.h:62
Our FD bio structure.
Definition fd_priv.h:35
void fr_ipaddr_get_scope_id(fr_ipaddr_t *ipaddr)
Definition inet.c:1487
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:1442
int8_t fr_sockaddr_cmp(struct sockaddr_storage const *a, struct sockaddr_storage const *b)
Definition inet.c:1659
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:63
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:1393
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition base.c:291
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:242
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:141
talloc_free(reap)
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.
Definition event.c:1203
Stores all information relating to an event list.
Definition event.c:377
long int ssize_t
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
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.
Definition null.c:47
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.
Definition null.c:56
#define fr_assert(_expr)
Definition rad_assert.h:38
#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:896
#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:878
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:50
#define FR_TIMER_DELETE(_ev_p)
Definition timer.h:103
#define fr_timer_in(...)
Definition timer.h:87
close(uq->fd)
static fr_event_list_t * el
int fd
File descriptor if this is a live socket.
Definition socket.h:81
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
static size_t char ** out
Definition value.h:1020