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