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: 5e7a6033e2815cc04ce73ac0cf4ef32388fa96ee $
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#ifndef NDEBUG
30/** Free this bio.
31 *
32 * The bio can only be freed if it is not in any chain.
33 */
35{
38
39 /*
40 * It's safe to free this bio.
41 */
42 return 0;
43}
44#endif
45
46/** Internal bio function which just reads from the "next" bio.
47 *
48 * It is mainly used when the current bio needs to modify the write
49 * path, but does not need to do anything on the read path.
50 */
51ssize_t fr_bio_next_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
52{
53 ssize_t rcode;
54 fr_bio_t *next;
55
56 next = fr_bio_next(bio);
57 fr_assert(next != NULL);
58
59 rcode = next->read(next, packet_ctx, buffer, size);
60 if (rcode >= 0) return rcode;
61
62 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
63
66 return rcode;
67}
68
69/** Internal bio function which just writes to the "next" bio.
70 *
71 * It is mainly used when the current bio needs to modify the read
72 * path, but does not need to do anything on the write path.
73 */
74ssize_t fr_bio_next_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
75{
76 ssize_t rcode;
77 fr_bio_t *next;
78
79 next = fr_bio_next(bio);
80 fr_assert(next != NULL);
81
82 rcode = next->write(next, packet_ctx, buffer, size);
83 if (rcode >= 0) return rcode;
84
85 if (rcode == fr_bio_error(IO_WOULD_BLOCK)) return rcode;
86
89 return rcode;
90}
91
92/** Free this bio, and everything it calls.
93 *
94 * We unlink the bio chain, and then free it individually. If there's an error, the bio chain is relinked.
95 * That way the error can be addressed (somehow) and this function can be called again.
96 *
97 * Note that we do not support talloc_free() for the bio chain. Each individual bio has to be unlinked from
98 * the chain before the destructor will allow it to be freed. This functionality is by design.
99 *
100 * We want to have an API where bios are created "bottom up", so that it is impossible for an application to
101 * create an incorrect chain. However, creating the chain bottom up means that the lower bios not parented
102 * from the higher bios, and therefore talloc_free() won't free them. As a result, we need an explicit
103 * bio_free() function.
104 */
106{
107 fr_bio_t *next = fr_bio_next(bio);
108
109 /*
110 * We cannot free a bio in the middle of a chain. It has to be unlinked first.
111 */
112 if (fr_bio_prev(bio)) return -1;
113
114 /*
115 * Unlink our bio, and recurse to free the next one. If we can't free it, re-chain it, but reset
116 * the read/write functions to do nothing.
117 */
118 if (next) {
119 next->entry.prev = NULL;
120 if (fr_bio_free(next) < 0) {
121 next->entry.prev = &bio->entry;
122 bio->read = fr_bio_fail_read;
124 return -1;
125 }
126
127 bio->entry.next = NULL;
128 }
129
130 /*
131 * It's now safe to free this bio.
132 */
133 return talloc_free(bio);
134}
135
136static ssize_t fr_bio_shutdown_read(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void *buffer, UNUSED size_t size)
137{
138 return fr_bio_error(SHUTDOWN);
139}
140
141static ssize_t fr_bio_shutdown_write(UNUSED fr_bio_t *bio, UNUSED void *packet_ctx, UNUSED void const *buffer, UNUSED size_t size)
142{
143 return fr_bio_error(SHUTDOWN);
144}
145
146/** Shut down a set of BIOs
147 *
148 * We shut down the BIOs from the top to the bottom. This gives the TLS BIO an opportunity to
149 * call the SSL_shutdown() routine, which should then write to the FD BIO.
150 */
152{
153 fr_bio_t *this, *first;
155
156 /*
157 * Find the first bio in the chain.
158 */
159 for (this = bio; fr_bio_prev(this) != NULL; this = fr_bio_prev(this)) {
160 /* nothing */
161 }
162 first = this;
163
164 /*
165 * Walk back down the chain, calling the shutdown functions.
166 */
167 for (/* nothing */; this != NULL; this = fr_bio_next(this)) {
168 my = (fr_bio_common_t *) this;
169
170 if (my->priv_cb.shutdown) {
171 my->priv_cb.shutdown(&my->bio);
172 my->priv_cb.shutdown = NULL;
173 }
174
176 my->bio.write = fr_bio_shutdown_write;
177 talloc_set_destructor(my, NULL);
178 }
179
180 /*
181 * Call the application shutdown routine
182 */
183 my = (fr_bio_common_t *) first;
184
185 if (my->cb.shutdown) my->cb.shutdown(first);
186 my->cb.shutdown = NULL;
187
188 return 0;
189}
190
191/** Like fr_bio_shutdown(), but can be called by anyone in the chain.
192 *
193 */
195{
196 fr_bio_common_t *prev;
197
198 while ((prev = (fr_bio_common_t *) fr_bio_prev(bio)) != NULL) {
199 bio = (fr_bio_t *) prev;
200 }
201
202 return fr_bio_shutdown(bio);
203}
204
205char const *fr_bio_strerror(ssize_t error)
206{
207 switch (error) {
208 case fr_bio_error(NONE):
209 return "";
210
211 case fr_bio_error(IO_WOULD_BLOCK):
212 return "IO operation would block";
213
214 case fr_bio_error(IO):
215 return fr_syserror(errno);
216
217 case fr_bio_error(GENERIC):
218 return fr_strerror();
219
220 case fr_bio_error(VERIFY):
221 return "Packet fails verification";
222
223 case fr_bio_error(BUFFER_FULL):
224 return "Output buffer is full";
225
226 case fr_bio_error(BUFFER_TOO_SMALL):
227 return "Output buffer is too small to cache the data";
228
229 case fr_bio_error(SHUTDOWN):
230 return "The IO handler is not available. It has been shut down due to a previous error";
231
232 default:
233 return "<unknown>";
234 }
235}
236
238{
240
241 if (!cb) {
242 memset(&my->cb, 0, sizeof(my->cb));
243 } else {
244 my->cb = *cb;
245 }
246}
247
248/** Internal BIO function to run EOF callbacks.
249 *
250 * When a BIO hits EOF, it MUST call this function. This function will take care of changing the read()
251 * function to return nothing. It will also take care of walking back up the hierarchy, and calling any
252 * BIO EOF callbacks.
253 *
254 * Once all of the BIOs have been marked as blocked, it will call the application EOF callback.
255 */
257{
258 fr_bio_common_t *this = (fr_bio_common_t *) bio;
259
260 /*
261 * This BIO is at EOF. So we can't call read() any more.
262 */
263 this->bio.read = fr_bio_null_read;
264
265 while (true) {
266 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
267
268 /*
269 * There are no more BIOs. Tell the application that the entire BIO chain is at EOF.
270 */
271 if (!prev) {
272 if (this->cb.eof) {
273 this->cb.eof(&this->bio);
274 this->cb.eof = NULL;
275 }
276 break;
277 }
278
279 /*
280 * Go to the previous BIO. If it doesn't have an EOF handler, then keep going back up
281 * the chain until we're at the top.
282 */
283 this = prev;
284 if (!this->priv_cb.eof) continue;
285
286 /*
287 * The EOF handler said it's NOT at EOF, so we stop processing here.
288 */
289 if (this->priv_cb.eof((fr_bio_t *) this) == 0) break;
290
291 /*
292 * Don't run the EOF callback multiple times, and continue the loop.
293 */
294 this->priv_cb.eof = NULL;
295 }
296}
297
298/** Internal BIO function to tell all BIOs that it's blocked.
299 *
300 * When a BIO blocks on write, it MUST call this function. This function will take care of walking back up
301 * the hierarchy, and calling any write_blocked callbacks.
302 *
303 * Once all of the BIOs have been marked as blocked, it will call the application write_blocked callback.
304 */
306{
307 fr_bio_common_t *this = (fr_bio_common_t *) bio;
308 int is_blocked = 1;
309
310 while (true) {
311 fr_bio_common_t *prev = (fr_bio_common_t *) fr_bio_prev(&this->bio);
312 int rcode;
313
314 /*
315 * There are no more BIOs. Tell the application that the entire BIO chain is blocked.
316 */
317 if (!prev) {
318 if (this->cb.write_blocked) {
319 rcode = this->cb.write_blocked(&this->bio);
320 if (rcode < 0) return rcode;
321 is_blocked &= (rcode == 1);
322 }
323 break;
324 }
325
326 /*
327 * Go to the previous BIO. If it doesn't have a write_blocked handler, then keep going
328 * back up the chain until we're at the top.
329 */
330 this = prev;
331 if (!this->priv_cb.write_blocked) continue;
332
333 /*
334 * The EOF handler said it's NOT at EOF, so we stop processing here.
335 */
336 rcode = this->priv_cb.write_blocked((fr_bio_t *) this);
337 if (rcode < 0) return rcode;
338 is_blocked &= (rcode == 1);
339 }
340
341 return is_blocked;
342}
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
fr_dlist_t _CONST entry
in the linked list of multiple bios
Definition base.h:119
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:131
#define fr_bio_error(_x)
Definition base.h:193
#define UNUSED
Definition build.h:317
fr_dlist_t * next
Definition dlist.h:43
fr_dlist_t * prev
Definition dlist.h:42
fr_bio_shutdown & my
Definition fd_errno.h:70
int fr_bio_free(fr_bio_t *bio)
Free this bio, and everything it calls.
Definition base.c:105
static 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:141
char const * fr_bio_strerror(ssize_t error)
Definition base.c:205
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition base.c:305
static 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:136
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:237
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:194
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:256
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
Definition base.c:34
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:51
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:74
int fr_bio_shutdown(fr_bio_t *bio)
Shut down a set of BIOs.
Definition base.c:151
talloc_free(reap)
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
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
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
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553