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: 5dabcca8387414b8993bc3fcc08d0072042e30a2 $
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 /*
923 * @todo - make the backlog configurable.
924 */
925 if (listen(my->info.socket.fd, 8) < 0) {
926 fr_strerror_printf("Failed calling listen() %s", fr_syserror(errno));
927 return fr_bio_error(IO);
928 }
929
931
932 return 0;
933}
934
935/** Allocate a FD bio
936 *
937 * The caller is responsible for tracking the FD, and all associated management of it. The bio API is
938 * intended to be simple, and does not provide wrapper functions for various ioctls. The caller should
939 * instead do that work.
940 *
941 * Once the FD is give to the bio, its lifetime is "owned" by the bio. Calling talloc_free(bio) will close
942 * the FD.
943 *
944 * The caller can still manage the FD for being readable / writeable. However, the caller should not call
945 * this bio directly (unless it is the only one). Instead, the caller should read from / write to the
946 * previous bio which will then eventually call this one.
947 *
948 * Before updating any event handler readable / writeable callbacks, the caller should check
949 * fr_bio_fd_at_eof(). If true, then the handlers should not be inserted. The previous bios should still be
950 * called to process any pending data, until they return EOF.
951 *
952 * The main purpose of an FD bio is to wrap the FD in a bio container. That, and handling retries on read /
953 * write, along with returning EOF as an error instead of zero.
954 *
955 * Note that the read / write functions can return partial data. It is the callers responsibility to ensure
956 * that any writes continue from where they left off (otherwise dat awill be missing). And any partial reads
957 * should go to a memory bio.
958 *
959 * If a read returns EOF, then the FD remains open until talloc_free(bio) or fr_bio_fd_close() is called.
960 *
961 * @param ctx the talloc ctx
962 * @param cfg structure holding configuration information
963 * @param offset only for unconnected datagram sockets, where #fr_bio_fd_packet_ctx_t is stored
964 * @return
965 * - NULL on error, memory allocation failed
966 * - !NULL the bio
967 */
968fr_bio_t *fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
969{
971
972 my = talloc_zero(ctx, fr_bio_fd_t);
973 if (!my) return NULL;
974
975 my->max_tries = 4;
976 my->offset = offset;
977
978 if (!cfg) {
979 /*
980 * Add place-holder information.
981 */
982 my->info = (fr_bio_fd_info_t) {
983 .socket = {
984 .af = AF_UNSPEC,
985 },
986 .type = FR_BIO_FD_UNCONNECTED,
987 .read_blocked = false,
988 .write_blocked = false,
989 .eof = false,
990 .state = FR_BIO_FD_STATE_CLOSED,
991 };
992
993 my->bio.read = fr_bio_null_read;
994 my->bio.write = fr_bio_null_write;
995 } else {
996 my->info.state = FR_BIO_FD_STATE_CLOSED;
997
998 if (fr_bio_fd_open(&my->bio, cfg) < 0) {
1000 return NULL;
1001 }
1002 }
1003
1004 my->priv_cb.eof = fr_bio_fd_eof;
1005 my->priv_cb.write_resume = fr_bio_fd_write_resume;
1006 my->priv_cb.shutdown = fr_bio_fd_shutdown;
1007
1008 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor); /* always use a common destructor */
1009 return (fr_bio_t *) my;
1010}
1011
1012/** Close the FD, but leave the bio allocated and alive.
1013 *
1014 */
1016{
1017 int rcode;
1018 int tries = 0;
1019 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1020
1021 if (my->info.state == FR_BIO_FD_STATE_CLOSED) return 0;
1022
1023 my->bio.read = fr_bio_shutdown_read;
1024 my->bio.write = fr_bio_shutdown_write;
1025
1026 /*
1027 * Shut down the connected socket. The only errors possible here are things we can't do anything
1028 * about.
1029 *
1030 * shutdown() will close ALL versions of this file descriptor, even if it's (somehow) used in
1031 * another process. shutdown() will also tell the kernel to gracefully close the connected
1032 * socket, so that it can signal the other end, instead of having the connection disappear.
1033 *
1034 * This shouldn't strictly be necessary, as no other processes should be sharing this file
1035 * descriptor. But it's the safe (and polite) thing to do.
1036 */
1037 if (my->info.type == FR_BIO_FD_CONNECTED) {
1038 (void) shutdown(my->info.socket.fd, SHUT_RDWR);
1039 }
1040
1041retry:
1042 rcode = close(my->info.socket.fd);
1043 if (rcode < 0) {
1044 switch (errno) {
1045 case EINTR:
1046 case EIO:
1047 tries++;
1048 if (tries < my->max_tries) goto retry;
1049 return fr_bio_error(IO);
1050
1051 default:
1052 /*
1053 * EBADF, or other unrecoverable error. We just call it closed, and continue.
1054 */
1055 break;
1056 }
1057 }
1058
1059 my->info.state = FR_BIO_FD_STATE_CLOSED;
1060 my->info.read_blocked = true;
1061 my->info.write_blocked = true;
1062 my->info.eof = true;
1063 my->info.socket.fd = -1;
1064
1065 return 0;
1066}
1067
1068/** FD error when trying to connect, give up on the BIO.
1069 *
1070 */
1071static void fr_bio_fd_el_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, void *uctx)
1072{
1073 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1074
1075 my->info.connect_errno = fd_errno;
1076
1077 if (my->connect.error) {
1078 my->connect.error(&my->bio);
1079 }
1080
1081 /*
1082 * The entire bio is unusable.
1083 */
1084 (void) fr_bio_shutdown(&my->bio);
1085}
1086
1087/** Connect callback for when the socket is writable.
1088 *
1089 * We try to connect the socket, and if so, call the application which should update the BIO status.
1090 */
1092{
1093 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1094
1095 fr_assert(my->info.type == FR_BIO_FD_CONNECTED);
1096 fr_assert(my->info.state == FR_BIO_FD_STATE_CONNECTING);
1097 fr_assert(my->connect.el == el); /* and not NULL */
1098 fr_assert(my->connect.success != NULL);
1099 fr_assert(my->info.socket.fd == fd);
1100
1101#ifndef NDEBUG
1102 /*
1103 * This check shouldn't be necessary, as we have a kqeueue error callback. That should be called
1104 * when there's a connect error.
1105 */
1106 {
1107 int error;
1108 socklen_t socklen = sizeof(error);
1109
1110 /*
1111 * The socket is writeable. Let's see if there's an error.
1112 *
1113 * Unix Network Programming says:
1114 *
1115 * ""If so_error is nonzero when the process calls write, -1 is returned with errno set to the
1116 * value of SO_ERROR (p. 495 of TCPv2) and SO_ERROR is reset to 0. We have to check for the
1117 * error, and if there's no error, set the state to "open". ""
1118 *
1119 * The same applies to connect(). If a non-blocking connect returns INPROGRESS, it may later
1120 * become writable. It will be writable even if the connection fails. Rather than writing some
1121 * random application data, we call SO_ERROR, and get the underlying error.
1122 */
1123 if (getsockopt(my->info.socket.fd, SOL_SOCKET, SO_ERROR, (void *)&error, &socklen) < 0) {
1124 fr_bio_fd_el_error(el, fd, flags, errno, uctx);
1125 return;
1126 }
1127
1128 fr_assert(error == 0);
1129
1130 /*
1131 * There was an error, we call the error handler.
1132 */
1133 if (error) {
1134 fr_bio_fd_el_error(el, fd, flags, error, uctx);
1135 return;
1136 }
1137 }
1138#endif
1139
1140 /*
1141 * Try to connect it. Any magic handling is done in the callbacks.
1142 */
1143 if (fr_bio_fd_try_connect(my) < 0) return;
1144
1145 fr_assert(my->connect.success);
1146
1147 FR_TIMER_DELETE(&my->connect.ev);
1148 my->connect.el = NULL;
1149
1150 /*
1151 * This function MUST change the read/write/error callbacks for the FD.
1152 */
1153 my->connect.success(&my->bio);
1154}
1155
1156/** We have a timeout on the conenction
1157 *
1158 */
1160{
1161 fr_bio_fd_t *my = talloc_get_type_abort(uctx, fr_bio_fd_t);
1162
1163 fr_assert(my->connect.timeout);
1164
1165 my->connect.timeout(&my->bio);
1166
1167 (void) fr_bio_shutdown(&my->bio);
1168}
1169
1170
1171/** Finalize a connect()
1172 *
1173 * connect() said "come back when the socket is writeable". It's now writeable, so we check if there was a
1174 * connection error.
1175 *
1176 * @param bio the binary IO handler
1177 * @param el the event list
1178 * @param connected_cb callback to run when the BIO is connected
1179 * @param error_cb callback to run when the FD has an error
1180 * @param timeout when to time out the connect() attempt
1181 * @param timeout_cb to call when the timeout runs.
1182 * @return
1183 * - <0 on error
1184 * - 0 for "try again later". If callbacks are set, the callbacks will try again. Otherwise the application has to try again.
1185 * - 1 for "we are now connected".
1186 */
1188 fr_bio_callback_t error_cb,
1189 fr_time_delta_t *timeout, fr_bio_callback_t timeout_cb)
1190{
1191 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1192
1193 /*
1194 * We shouldn't be connected an unconnected socket.
1195 */
1196 if (my->info.type == FR_BIO_FD_UNCONNECTED) {
1197 error:
1198#ifdef ECONNABORTED
1199 my->info.connect_errno = ECONNABORTED;
1200#else
1201 my->info.connect_errno = ECONNREFUSED;
1202#endif
1203 if (error_cb) error_cb(bio);
1204 (void) fr_bio_shutdown(&my->bio);
1205 return fr_bio_error(GENERIC);
1206 }
1207
1208 /*
1209 * The initial open may have succeeded in connecting the socket. In which case we just run the
1210 * callbacks and return.
1211 */
1212 if (my->info.state == FR_BIO_FD_STATE_OPEN) {
1213 connected:
1214 if (connected_cb) connected_cb(bio);
1215
1216 return 1;
1217 }
1218
1219 /*
1220 * The caller may just call us without caring about what the underlying BIO is. In which case we
1221 * need to be safe.
1222 */
1223 if ((my->info.socket.af == AF_FILE_BIO) || (my->info.type == FR_BIO_FD_LISTEN)) {
1225 goto connected;
1226 }
1227
1228 /*
1229 * It must be in the connecting state, i.e. not INVALID or CLOSED.
1230 */
1231 if (my->info.state != FR_BIO_FD_STATE_CONNECTING) goto error;
1232
1233 /*
1234 * No callback
1235 */
1236 if (!connected_cb) {
1237 ssize_t rcode;
1238
1239 rcode = fr_bio_fd_try_connect(my);
1240 if (rcode < 0) {
1241 if (error_cb) error_cb(bio);
1242 return rcode; /* it already called shutdown */
1243 }
1244
1245 return 1;
1246 }
1247
1248 /*
1249 * It's not connected, the caller has to try again.
1250 */
1251 if (!el) return 0;
1252
1253 /*
1254 * Set the callbacks to run when something happens.
1255 */
1256 my->connect.success = connected_cb;
1257 my->connect.error = error_cb;
1258 my->connect.timeout = timeout_cb;
1259
1260 /*
1261 * Set the timeout callback if asked.
1262 */
1263 if (timeout_cb) {
1264 if (fr_timer_in(my, el->tl, &my->connect.ev, *timeout, false, fr_bio_fd_el_timeout, my) < 0) {
1265 goto error;
1266 }
1267 }
1268
1269 /*
1270 * Set the FD callbacks, and tell the caller that we're not connected.
1271 */
1272 if (fr_event_fd_insert(my, NULL, el, my->info.socket.fd, NULL,
1274 goto error;
1275 }
1276 my->connect.el = el;
1277
1278 return 0;
1279}
1280
1281/** Returns a pointer to the bio-specific information.
1282 *
1283 */
1285{
1286 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1287
1288 return &my->info;
1289}
1290
1291
1292/** Discard all reads from a UDP socket.
1293 */
1294static ssize_t fr_bio_fd_read_discard_datagram(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
1295{
1296 int tries = 0;
1297 ssize_t rcode;
1298 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1299
1300retry:
1301 rcode = read(my->info.socket.fd, buffer, size);
1302 if (rcode >= 0) return 0; /* always return that we read no data */
1303
1304#undef flag_blocked
1305#define flag_blocked read_blocked
1306#include "fd_errno.h"
1307
1308 return fr_bio_error(IO);
1309}
1310
1311/** Discard all reads from a TCP socket.
1312 */
1313static ssize_t fr_bio_fd_read_discard_stream(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
1314{
1315 int tries = 0;
1316 ssize_t rcode;
1317 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1318
1319retry:
1320 rcode = read(my->info.socket.fd, buffer, size);
1321 if (rcode > 0 ) return 0; /* always return that we read no data */
1322 if (rcode == 0) {
1323 fr_bio_eof(bio);
1324 return 0;
1325 }
1326
1327#undef flag_blocked
1328#define flag_blocked read_blocked
1329#include "fd_errno.h"
1330
1331 return fr_bio_error(IO);
1332}
1333
1334/** Mark up a bio as write-only
1335 *
1336 */
1338{
1339 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1340
1341 switch (my->info.type) {
1342 case FR_BIO_FD_INVALID:
1343 return -1;
1344
1346 if (my->info.socket.type != SOCK_DGRAM) {
1347 fr_strerror_const("Only datagram sockets can be marked 'write-only'");
1348 return -1;
1349 }
1350 goto set_recv_buff_zero;
1351
1353 /*
1354 * Further reads are disallowed. However, this likely has no effect for UDP sockets.
1355 */
1356 if (shutdown(my->info.socket.fd, SHUT_RD) < 0) {
1357 fr_strerror_printf("Failed shutting down connected socket - %s", fr_syserror(errno));
1358 return -1;
1359 }
1360
1361 set_recv_buff_zero:
1362#ifdef __linux__
1363#ifdef SO_RCVBUF
1364 /*
1365 * On Linux setting the receive buffer to zero has the effect of discarding all incoming
1366 * data in the kernel. With macOS and others it's an invalid value.
1367 */
1368 {
1369 int opt = 0;
1370
1371 if (setsockopt(my->info.socket.fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
1372 fr_strerror_printf("Failed setting SO_RCVBUF: %s", fr_syserror(errno));
1373 return -1;
1374 }
1375 }
1376#endif
1377#endif
1378 break;
1379
1380 case FR_BIO_FD_LISTEN:
1381 fr_strerror_const("Only unconnected sockets can be marked 'write-only'");
1382 return -1;
1383 }
1384
1385 /*
1386 * No matter what the possibilities above, we replace the read function with a "discard"
1387 * function.
1388 */
1389 my->bio.read = (my->info.socket.type == SOCK_DGRAM) ? fr_bio_fd_read_discard_datagram : fr_bio_fd_read_discard_stream;
1390 return 0;
1391}
1392
1393#if !defined(__linux__) && !defined(__FreeBSD__)
1394static int inline accept4(int fd, struct sockaddr *sockaddr, socklen_t *salen, UNUSED int flags)
1395{
1396 fd = accept(fd, sockaddr, salen);
1397 if (fd >= 0) {
1398#ifdef FD_CLOEXEC
1399 int rcode;
1400
1401 rcode = fcntl(fd, F_GETFD);
1402 if (rcode >= 0) {
1403 if (fcntl(fd, F_SETFD, rcode | FD_CLOEXEC) < 0) {
1404 close(fd);
1405 return -1;
1406 }
1407 }
1408#endif
1409
1410 if (fr_nonblock(fd) < 0) {
1411 close(fd);
1412 }
1413 }
1414
1415 return fd;
1416}
1417#ifndef SOCK_NONBLOCK
1418#define SOCK_NONBLOCK 0
1419#endif
1420
1421#ifndef SOCK_CLOEXEC
1422#define SOCK_CLOEXEC 0
1423#endif
1424
1425#endif
1426
1427/** Accept a stream socket and initialize its flags.
1428 *
1429 */
1431{
1432 int rcode;
1433 int fd, tries = 0;
1434
1435 my->remote_sockaddr_len = sizeof(my->remote_sockaddr);
1436
1437retry:
1438 /*
1439 * Set these flags immediately on the new socket.
1440 */
1441 fd = accept4(parent->info.socket.fd, (struct sockaddr *) &my->remote_sockaddr, &my->remote_sockaddr_len,
1443 if (fd < 0) {
1444 /*
1445 * Try a few times before giving up.
1446 */
1447 if (errno == EINTR) {
1448 tries++;
1449 if (tries <= my->max_tries) goto retry;
1450 }
1451
1452 return fr_bio_error(IO);
1453 }
1454
1455 /*
1456 * Get IP addresses from the sockaddr.
1457 */
1458 if ((my->info.socket.af == AF_INET) || (my->info.socket.af == AF_INET6)) {
1459 fr_ipaddr_from_sockaddr(&my->info.socket.inet.dst_ipaddr, &my->info.socket.inet.dst_port,
1460 &my->remote_sockaddr, my->remote_sockaddr_len);
1461 }
1462
1463 /*
1464 * The socket is now open. Save the new state.
1465 */
1466 my->info.socket.fd = fd;
1467 my->info.type = FR_BIO_FD_CONNECTED;
1468
1469 rcode = fr_bio_fd_init_common(my);
1470 if (rcode < 0) {
1471 close(fd);
1472 return rcode;
1473 }
1474
1476 if (!my->info.name) {
1477 close(fd);
1478 return fr_bio_error(OOM);
1479 }
1480
1481 return 0;
1482}
1483
1484
1485/** Accept a new connection on a socket.
1486 *
1487 */
1488int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_t *bio)
1489{
1490 int rcode;
1491 fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
1493
1494 *out_p = NULL;
1495
1496 fr_assert(my->info.type == FR_BIO_FD_LISTEN);
1497
1498 /*
1499 * Allocate the base BIO and set it up.
1500 */
1501 out = (fr_bio_fd_t *) fr_bio_fd_alloc(ctx, NULL, my->offset);
1502 if (!out) return fr_bio_error(GENERIC);
1503
1504 /*
1505 * Initialize the new BIO information.
1506 */
1507 out->info.cfg = my->info.cfg;
1508
1509 /*
1510 * Copy all socket fields, including ones which will be over-written later.
1511 */
1512 out->info.socket = my->info.socket;
1513
1514 if (my->info.socket.type == SOCK_STREAM) {
1515 rcode = fr_bio_fd_accept_stream(out, my);
1516
1517 } else {
1518 fr_assert(my->info.socket.type == SOCK_DGRAM);
1519
1520 // rcode = fr_bio_fd_accept_datagram(out, my);
1521 rcode = -1;
1522 }
1523 if (rcode < 0) {
1525 return rcode;
1526 }
1527
1528 /*
1529 * The socket is now
1530 */
1531
1532 *out_p = (fr_bio_t *) out;
1533 return 1;
1534}
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:848
#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:1187
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:1091
#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:968
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:1313
static int accept4(int fd, struct sockaddr *sockaddr, socklen_t *salen, UNUSED int flags)
Definition fd.c:1394
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:1488
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:1284
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:1430
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:1159
#define SOCK_CLOEXEC
Definition fd.c:1422
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:1337
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:1294
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:1071
#define SOCK_NONBLOCK
Definition fd.c:1418
int fr_bio_fd_close(fr_bio_t *bio)
Close the FD, but leave the bio allocated and alive.
Definition fd.c:1015
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:128
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