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