The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
fd_errno.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/**
19 * $Id: 62c6cc2fb5aaab69922eb6ec22d0f20988cc7007 $
20 * @file lib/bio/fd_errno.h
21 * @brief Common errno handling for FD bio reads and writes.
22 *
23 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
24 */
25RCSIDH(lib_bio_fd_errno_h, "$Id: 62c6cc2fb5aaab69922eb6ec22d0f20988cc7007 $")
26
27#include <freeradius-devel/bio/fd_priv.h>
28
29/** Turn a failed read / write into a bio return code.
30 *
31 * Only called when the syscall failed, i.e. when rcode is negative.
32 *
33 * @param my the FD bio.
34 * @param[in,out] rcode_p in: the failed syscall return code. out: what to return to the application.
35 * @param[in,out] tries_p how many times we have retried on EINTR.
36 * @param is_write true for the write path, false for the read path.
37 * @return
38 * - false return *rcode_p to the application.
39 * - true the syscall was interrupted, redo it.
40 */
41static inline CC_HINT(always_inline) bool fr_bio_fd_errno_retry(fr_bio_fd_t *my, ssize_t *rcode_p, int *tries_p, bool is_write)
42{
43 bool *blocked = is_write ? &my->info.write_blocked : &my->info.read_blocked;
44 fr_bio_io_t blocked_cb = is_write ? my->cb.write_blocked : my->cb.read_blocked;
45
46 switch (errno) {
47 case EINTR:
48 /*
49 * Try a few times before giving up.
50 */
51 (*tries_p)++;
52 if (*tries_p <= my->max_tries) return true;
53
54 *rcode_p = fr_bio_error(IO);
55 return false;
56
57#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
58 case EWOULDBLOCK:
59#endif
60 case EAGAIN:
61 /*
62 * The operation would block, return that.
63 */
64 if (!*blocked) {
65 *blocked = true;
66
67 if (blocked_cb) {
68 int error;
69
70 error = blocked_cb((fr_bio_t *) my);
71 if (error < 0) {
72 *rcode_p = error;
73 return false;
74 }
75 }
76 }
77
78 *rcode_p = fr_bio_error(IO_WOULD_BLOCK);
79 return false;
80
81 /*
82 * We're reading / writing a connected UDP socket, and the other end has gone away.
83 */
84 case ENOTCONN:
85
86 /*
87 * The other end of a socket has closed the connection.
88 */
89 case ECONNRESET:
90
91 /*
92 * The other end of a pipe has closed the connection.
93 */
94 case EPIPE:
95 /*
96 * The connection is no longer usable, close it.
97 */
98 fr_bio_eof(&my->bio);
99 *rcode_p = 0;
100 return false;
101
102 /*
103 * PMTU has been exceeded. Return a generic IO error.
104 *
105 * Only a write can exceed the PMTU, so a read which somehow reports EMSGSIZE is fatal.
106 *
107 * @todo - do this only for connected UDP sockets.
108 *
109 * However, recvmsg() can also return EMSGSIZE, if the msg_iovlen field has a bad value.
110 */
111 case EMSGSIZE:
112 *rcode_p = fr_bio_error(IO);
113 return false;
114
115 /*
116 * The underlying network has gone away. This is a fatal error for connected sockets,
117 * but a recoverable one for unconnected sockets.
118 */
119 case ENETDOWN:
120 case ENETUNREACH:
121 *rcode_p = fr_bio_error(IO);
122 return false;
123
124 default:
125 /*
126 * Some other error, it's fatal.
127 */
128 break;
129 }
130
131 /*
132 * Shut down the BIO. It's no longer useable.
133 */
134 (void) fr_bio_shutdown(&my->bio);
135
136 *rcode_p = fr_bio_error(IO);
137 return false;
138}
139
140/*
141 * Common code to suppress network failures on sendto / sendfromto for unconnected UDP sockets.
142 *
143 * If the destination network is down or is unreachable, we want to simply discard the packet. The error
144 * isn't fatal, so we don't close the socket.
145 */
146#define FD_ENET_SUPPRESS \
147 do { \
148 if ((rcode == fr_bio_error(IO)) && ((errno == ENETDOWN) || (errno == ENETUNREACH))) return 0; \
149 } while (0)
int(* fr_bio_io_t)(fr_bio_t *bio)
Definition base.h:84
#define fr_bio_error(_x)
Definition base.h:200
#define RCSIDH(h, id)
Definition build.h:561
bool read_blocked
did we block on read?
Definition fd.h:134
bool write_blocked
did we block on write?
Definition fd.h:135
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
fr_bio_fd_info_t info
Definition fd_priv.h:39
Our FD bio structure.
Definition fd_priv.h:35
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:212
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:98
long int ssize_t