The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base.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: f1dbf6378462d1f592c5f70be4ca454bb74cb654 $
19 * @file lib/bio/base.c
20 * @brief Binary IO abstractions.
21 *
22 * @copyright 2024 Network RADIUS SAS (legal@networkradius.com)
23 */
24
25#include <freeradius-devel/bio/bio_priv.h>
26#include <freeradius-devel/bio/null.h>
27#include <freeradius-devel/util/syserror.h>
28
29/** Free this bio.
30 *
31 * We allow talloc_free() to be called on just about anything in the
32 * bio chain. But we ensure that the chain is always shut down in an
33 * orderly fashion.
34 */
36{
38
40
41 return 0;
42}
43
44/** Internal bio function which just reads from the "next" bio.
45 *
46 * It is mainly used when the current bio needs to modify the write
47 * path, but does not need to do anything on the read path.
48 */
49ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
50{
51 fr_bio_t *next;
52
53 next = fr_bio_next(bio);
54 fr_assert(next != NULL);
55
56 return next->read(next, packet_ctx, buffer, size);
57}
58
59/** Internal bio function which just writes to the "next" bio.
60 *
61 * It is mainly used when the current bio needs to modify the read
62 * path, but does not need to do anything on the write path.
63 */
64ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
65{
66 fr_bio_t *next;
67
68 next = fr_bio_next(bio);
69 fr_assert(next != NULL);
70
71 return next->write(next, packet_ctx, buffer, size);
72}
73
74ssize_t fr_bio_shutdown_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
75{
76 return fr_bio_error(SHUTDOWN);
77}
78
79ssize_t fr_bio_shutdown_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
80{
81 return fr_bio_error(SHUTDOWN);
82}
83
84/** Shut down a set of BIOs
85 *
86 * We shut down the BIOs from the top to the bottom. This gives the
87 * TLS BIO an opportunity to call the SSL_shutdown() routine, which
88 * should then write to the FD BIO. Once that write is completed,
89 * the FD BIO can then close its socket.
90 *
91 * Any shutdown is "stop read / write", but is not "free all
92 * resources". A shutdown can happen when one of the intermediary
93 * BIOs hits a fatal error. It can't free the BIO, but it has to
94 * mark the entire BIO chain as being unusable.
95 *
96 * A destructor will first shutdown the BIOs, and then free all resources.
97 */
99{
100 int rcode;
101 fr_bio_t *head, *this;
103
104 /*
105 * Find the first bio in the chain.
106 */
107 head = fr_bio_head(bio);
108
109 /*
110 * We're in the process of shutting down, don't call ourselves recursively.
111 */
112 my = (fr_bio_common_t *) head;
113 if (my->bio.read == fr_bio_shutdown_read) return 0;
114
115 /*
116 * Walk back down the chain, calling the shutdown functions.
117 */
118 for (this = head; this != NULL; this = fr_bio_next(this)) {
119 my = (fr_bio_common_t *) this;
120
121 if (my->priv_cb.shutdown) {
122 rcode = my->priv_cb.shutdown(&my->bio);
123 if (rcode < 0) return rcode;
124 my->priv_cb.shutdown = NULL;
125 }
126
127 my->bio.read = fr_bio_shutdown_read;
128 my->bio.write = fr_bio_shutdown_write;
129 talloc_set_destructor(my, NULL);
130 }
131
132 /*
133 * Call the application shutdown routine to tell it that
134 * the BIO has been successfully shut down.
135 */
136 my = (fr_bio_common_t *) head;
137
138 if (my->cb.shutdown) {
139 rcode = my->cb.shutdown(head);
140 if (rcode < 0) return rcode;
141 my->cb.shutdown = NULL;
142 }
143
144 return 0;
145}
146
147/** Like fr_bio_shutdown(), but can be called by anyone in the chain.
148 *
149 */
151{
152 fr_bio_common_t *prev;
153
154 while ((prev = (fr_bio_common_t *) fr_bio_prev(bio)) != NULL) {
155 bio = (fr_bio_t *) prev;
156 }
157
158 return fr_bio_shutdown(bio);
159}
160
161char const *fr_bio_strerror(ssize_t error)
162{
163 switch (error) {
164 case fr_bio_error(NONE):
165 return "";
166
167 case fr_bio_error(IO_WOULD_BLOCK):
168 return "IO operation would block";
169
170 case fr_bio_error(IO):
171 return fr_syserror(errno);
172
173 case fr_bio_error(GENERIC):
174 return fr_strerror();
175
176 case fr_bio_error(VERIFY):
177 return "Packet fails verification";
178
179 case fr_bio_error(BUFFER_FULL):
180 return "Output buffer is full";
181
182 case fr_bio_error(BUFFER_TOO_SMALL):
183 return "Output buffer is too small to cache the data";
184
185 case fr_bio_error(SHUTDOWN):
186 return "The IO handler is not available. It has been shut down due to a previous error";
187
188 default:
189 return "<unknown>";
190 }
191}
192
194{
196
197 if (!cb) {
198 memset(&my->cb, 0, sizeof(my->cb));
199 } else {
200 my->cb = *cb;
201 }
202}
203
204/** Internal BIO function to run EOF callbacks.
205 *
206 * When a BIO hits EOF, it MUST call this function. This function will take care of changing the read()
207 * function to return nothing. It will also take care of walking back up the hierarchy, and calling any
208 * BIO EOF callbacks.
209 *
210 * Once all of the BIOs have been marked as blocked, it will call the application EOF callback.
211 */
213{
214 fr_bio_common_t *this = (fr_bio_common_t *) bio;
215
216 /*
217 * This BIO is at EOF. So we can't call read() any more.
218 */
219 this->bio.read = fr_bio_null_read;
220
221 while (true) {
222 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
223
224 /*
225 * There are no more BIOs. Tell the application that the entire BIO chain is at EOF.
226 */
227 if (!prev) {
228 if (this->cb.eof) {
229 this->cb.eof(&this->bio);
230 this->cb.eof = NULL;
231 }
232 break;
233 }
234
235 /*
236 * Go to the previous BIO. If it doesn't have an EOF handler, then keep going back up
237 * the chain until we're at the top.
238 */
239 this = prev;
240 if (!this->priv_cb.eof) continue;
241
242 /*
243 * The EOF handler said it's NOT at EOF, so we stop processing here.
244 */
245 if (this->priv_cb.eof((fr_bio_t *) this) == 0) break;
246
247 /*
248 * Don't run the EOF callback multiple times, and continue the loop.
249 */
250 this->priv_cb.eof = NULL;
251 }
252}
253
254/** Internal BIO function to tell all BIOs that it's blocked.
255 *
256 * When a BIO blocks on write, it MUST call this function. This function will take care of walking back up
257 * the hierarchy, and calling any write_blocked callbacks.
258 *
259 * Once all of the BIOs have been marked as blocked, it will call the application write_blocked callback.
260 */
262{
263 fr_bio_common_t *this = (fr_bio_common_t *) bio;
264 int is_blocked = 1;
265
266 while (true) {
267 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
268 int rcode;
269
270 /*
271 * There are no more BIOs. Tell the application that the entire BIO chain is blocked.
272 */
273 if (!prev) {
274 if (this->cb.write_blocked) {
275 rcode = this->cb.write_blocked(&this->bio);
276 if (rcode < 0) return rcode;
277 is_blocked &= (rcode == 1);
278 }
279 break;
280 }
281
282 /*
283 * Go to the previous BIO. If it doesn't have a write_blocked handler, then keep going
284 * back up the chain until we're at the top.
285 */
286 this = prev;
287 if (!this->priv_cb.write_blocked) continue;
288
289 /*
290 * The EOF handler said it's NOT at EOF, so we stop processing here.
291 */
292 rcode = this->priv_cb.write_blocked((fr_bio_t *) this);
293 if (rcode < 0) return rcode;
294 is_blocked &= (rcode == 1);
295 }
296
297 return is_blocked;
298}
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
static fr_bio_t * fr_bio_prev(fr_bio_t *bio)
Definition base.h:122
fr_bio_read_t _CONST read
read from the underlying bio
Definition base.h:116
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:131
static fr_bio_t * fr_bio_head(fr_bio_t *bio)
Definition base.h:140
#define fr_bio_error(_x)
Definition base.h:200
#define FR_BIO_DESTRUCTOR_COMMON
Define a common destructor pattern.
Definition bio_priv.h:64
#define UNUSED
Definition build.h:317
void fr_bio_shutdown & my
Definition fd_errno.h:70
char const * fr_bio_strerror(ssize_t error)
Definition base.c:161
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_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:193
int fr_bio_shutdown_intermediate(fr_bio_t *bio)
Like fr_bio_shutdown(), but can be called by anyone in the chain.
Definition base.c:150
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
ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Internal bio function which just reads from the "next" bio.
Definition base.c:49
ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Internal bio function which just writes to the "next" bio.
Definition base.c:64
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:98
long int ssize_t
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
#define fr_assert(_expr)
Definition rad_assert.h:38
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define VERIFY(_x)
Definition trie.c:130
static fr_slen_t head
Definition xlat.h:420
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553