The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
mem.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: 117fe246f7e27a49f7a3e1d7ef1e8a81c6988949 $
19 * @file lib/bio/mem.c
20 * @brief BIO abstractions for memory buffers
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/bio/buf.h>
28
29#include <freeradius-devel/bio/mem.h>
30
31typedef enum {
33 FR_BIO_MEM_SOURCE, /* the application writes to it, something else reads */
34 FR_BIO_MEM_SINK, /* something else writes to it, the application reads */
35 FR_BIO_MEM_VERIFY, /* verification only, with no buffers */
36 FR_BIO_MEM_BUFFER, /* we manage local buffers */
38
39/** The memory buffer bio
40 *
41 * It is used to buffer reads / writes to a streaming socket.
42 */
43typedef struct fr_bio_mem_s {
45
46 fr_bio_mem_type_t type; //!< source, sink, etc.
47
48 fr_bio_verify_t verify; //!< verify data to see if we have a packet.
49 void *verify_ctx; //!< verify context
50
51 fr_bio_buf_t read_buffer; //!< buffering for reads
52 fr_bio_buf_t write_buffer; //!< buffering for writes
54
55static ssize_t fr_bio_mem_write_buffer(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size);
56
57static int fr_bio_mem_call_verify(fr_bio_t *bio, void *packet_ctx, size_t *size) CC_HINT(nonnull(1,3));
58
59/** At EOF, read data from the buffer until it is empty.
60 *
61 * When "next" bio returns EOF, there may still be pending data in the memory buffer. Return that until it's
62 * empty, and then EOF from then on.
63 */
64static ssize_t fr_bio_mem_read_eof(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
65{
66 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
67
68 /*
69 * No more data: return EOF from now on.
70 */
71 if (fr_bio_buf_used(&my->read_buffer) == 0) {
72
73 /*
74 * Don't call our EOF function. But do tell the other BIOs that we're at EOF.
75 */
76 my->priv_cb.eof = NULL;
77 fr_bio_eof(&my->bio);
78 return 0;
79 }
80
81 /*
82 * Return whatever data we have available. One the buffer is empty, the next read will get EOF.
83 */
84 return fr_bio_buf_read(&my->read_buffer, buffer, size);
85}
86
87static int fr_bio_mem_eof(fr_bio_t *bio)
88{
89 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
90
91 /*
92 * Nothing more for us to read, tell fr_bio_eof() that it can continue with poking other BIOs.
93 */
94 if (fr_bio_buf_used(&my->read_buffer) == 0) {
95 return 1;
96 }
97
98 my->bio.read = fr_bio_mem_read_eof;
99
100 return 0;
101}
102
103/** Read from a memory BIO
104 *
105 * This bio reads as much data as possible into the memory buffer. On the theory that a few memcpy() or
106 * memmove() calls are much cheaper than a system call.
107 *
108 * If the read buffer has enough data to satisfy the read, then it is returned.
109 *
110 * Otherwise the next bio is called to re-fill the buffer. The next read call will try to get as much data
111 * as possible into the buffer, even if that results in reading more than "size" bytes.
112 *
113 * Once the next read has been done, then the data from the buffer is returned, even if it is less than
114 * "size".
115 */
116static ssize_t fr_bio_mem_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
117{
118 ssize_t rcode;
119 size_t used, room;
120 uint8_t *p;
121 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
122 fr_bio_t *next;
123
124 /*
125 * We can satisfy the read from the memory buffer: do so.
126 */
127 used = fr_bio_buf_used(&my->read_buffer);
128 if (size <= used) {
129 return fr_bio_buf_read(&my->read_buffer, buffer, size);
130 }
131
132 /*
133 * There must be a next bio.
134 */
135 next = fr_bio_next(&my->bio);
136 fr_assert(next != NULL);
137
138 /*
139 * If there's no room to store more data in the buffer. Just return whatever data we have in the
140 * buffer.
141 */
142 room = fr_bio_buf_write_room(&my->read_buffer);
143 if (!room) return fr_bio_buf_read(&my->read_buffer, buffer, size);
144
145 /*
146 * We try to fill the buffer as much as possible from the network, even if that means reading
147 * more than "size" amount of data.
148 */
149 p = fr_bio_buf_write_reserve(&my->read_buffer, room);
150 fr_assert(p != NULL); /* otherwise room would be zero */
151
152 rcode = next->read(next, packet_ctx, p, room);
153
154 /*
155 * Ensure that whatever data we have read is marked as "used" in the buffer, and then return
156 * whatever data is available back to the caller.
157 */
158 if (rcode >= 0) {
159 if (rcode > 0) (void) fr_bio_buf_write_alloc(&my->read_buffer, (size_t) rcode);
160
161 return fr_bio_buf_read(&my->read_buffer, buffer, size);
162 }
163
164 /*
165 * The next bio returned an error. Whatever it is, it's fatal. We can read from the memory
166 * buffer until it's empty, but we can no longer write to the memory buffer. Any data written to
167 * the buffer is lost.
168 */
171 return rcode;
172}
173
174/** Return data only if we have a complete packet.
175 *
176 */
177static ssize_t fr_bio_mem_read_verify_stream(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
178{
179 ssize_t rcode;
180 size_t used, room, want;
181 uint8_t *p;
182 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
183 fr_bio_t *next;
184
185 /*
186 * We may be able to satisfy the read from the memory buffer.
187 */
188 used = fr_bio_buf_used(&my->read_buffer);
189 if (used) {
190 /*
191 * See if there are valid packets in the buffer.
192 */
193 rcode = fr_bio_mem_call_verify(bio, packet_ctx, &want);
194 if (rcode < 0) {
195 rcode = fr_bio_error(VERIFY);
196 goto fail;
197 }
198
199 /*
200 * There's at least one valid packet, return it.
201 */
202 if (rcode == 1) {
203 /*
204 * This isn't a fatal error. The caller should check how much room is needed by calling
205 * fr_bio_mem_call_verify(), and retry.
206 *
207 * But in general, the caller should make sure that the output buffer has enough
208 * room for at least one packet. The verify() function should also ensure that
209 * the packet is no larger than our application maximum, even if the protocol
210 * allows for it to be larger.
211 */
212 if (want > size) return fr_bio_error(BUFFER_TOO_SMALL);
213
214 return fr_bio_buf_read(&my->read_buffer, buffer, want);
215 }
216
217 /*
218 * Else we need to read more data to have a complete packet.
219 */
220 }
221
222 /*
223 * There must be a next bio.
224 */
225 next = fr_bio_next(&my->bio);
226 fr_assert(next != NULL);
227
228 /*
229 * If there's no room to store more data in the buffer, try to make some room.
230 */
231 room = fr_bio_buf_write_room(&my->read_buffer);
232 if (!room) {
233 room = fr_bio_buf_make_room(&my->read_buffer);
234
235 /*
236 * We've tried to make room and failed. Which means that the buffer is full, AND there
237 * still isn't a complete packet in the buffer. This is therefore a fatal error. The
238 * application has not supplied us with enough read_buffer space to store a complete
239 * packet.
240 */
241 if (!room) {
242 rcode = fr_bio_error(BUFFER_FULL);
243 goto fail;
244 }
245 }
246
247 /*
248 * We try to fill the buffer as much as possible from the network. The theory is that a few
249 * extra memcpy() or memmove()s are cheaper than a system call for reading each packet.
250 */
251 p = fr_bio_buf_write_reserve(&my->read_buffer, room);
252 fr_assert(p != NULL); /* otherwise room would be zero */
253
254 rcode = next->read(next, packet_ctx, p, room);
255
256 /*
257 * The next bio returned some data. See if it's a valid packet.
258 */
259 if (rcode > 0) {
260 (void) fr_bio_buf_write_alloc(&my->read_buffer, (size_t) rcode);
261
262 want = fr_bio_buf_used(&my->read_buffer);
263 if (size <= want) want = size;
264
265 /*
266 * See if there are valid packets in the buffer.
267 */
268 rcode = fr_bio_mem_call_verify(bio, packet_ctx, &want);
269 if (rcode < 0) {
270 rcode = fr_bio_error(VERIFY);
271 goto fail;
272 }
273
274 /*
275 * There's at least one valid packet, return it.
276 */
277 if (rcode == 1) return fr_bio_buf_read(&my->read_buffer, buffer, want);
278
279 /*
280 * No valid packets. The next call to read will call verify again, which will return a
281 * partial packet. And then it will try to fill the buffer from the next bio.
282 */
283 return 0;
284 }
285
286 /*
287 * No data was read from the next bio, we still don't have a packet. Return nothing.
288 */
289 if (rcode == 0) return 0;
290
291 /*
292 * The next bio returned an error either when our buffer was empty, or else it had only a partial
293 * packet in it. We can no longer read full packets from this BIO, and we can't read from the
294 * next one, either. So shut down the BIO completely.
295 */
296fail:
297 bio->read = fr_bio_fail_read;
299 return rcode;
300}
301
302/** Return data only if we have a complete packet.
303 *
304 */
305static ssize_t fr_bio_mem_read_verify_datagram(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
306{
307 ssize_t rcode;
308 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
309 fr_bio_t *next;
310
311 /*
312 * There must be a next bio.
313 */
314 next = fr_bio_next(&my->bio);
315 fr_assert(next != NULL);
316
317 rcode = next->read(next, packet_ctx, buffer, size);
318 if (rcode > 0) {
319 size_t want = rcode;
320
321 /*
322 * It's a datagram socket, there can only be one packet in the buffer.
323 *
324 * @todo - if we're allowed more than one packet in the buffer, we should just call
325 * fr_bio_mem_read_verify(), or this function should call fr_bio_mem_call_verify().
326 */
327 switch (my->verify((fr_bio_t *) my, my->verify_ctx, packet_ctx, buffer, &want)) {
328 /*
329 * The data in the buffer is exactly a packet. Return that.
330 *
331 * @todo - if there are multiple packets, return the total size of packets?
332 */
333 case FR_BIO_VERIFY_OK:
334 fr_assert(want <= (size_t) rcode);
335 return want;
336
337 /*
338 * The data in the buffer doesn't make up a complete packet, discard it. The
339 * called verify function should take care of logging.
340 */
342 return 0;
343
345 return 0;
346
347 /*
348 * Some kind of fatal validation error.
349 */
351 break;
352 }
353
354 rcode = fr_bio_error(VERIFY);
355 goto fail;
356 }
357
358 /*
359 * No data was read from the next bio, we still don't have a packet. Return nothing.
360 */
361 if (rcode == 0) return 0;
362
363 /*
364 * The next bio returned an error. Whatever it is, it's fatal. We can read from the memory
365 * buffer until it's empty, but we can no longer write to the memory buffer. Any data written to
366 * the buffer is lost.
367 */
368fail:
371 return rcode;
372}
373
374
375/** Pass writes to the next BIO
376 *
377 * For speed, we try to bypass the memory buffer and write directly to the next bio. However, if the next
378 * bio returns EWOULDBLOCK, we write the data to the memory buffer, even if it is partial data.
379 */
380static ssize_t fr_bio_mem_write_next(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
381{
382 int error;
383 ssize_t rcode;
384 size_t room, leftover;
385 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
386 fr_bio_t *next;
387
388 /*
389 * We can't call the next bio if there's still cached data to flush.
390 *
391 * There must be a next bio.
392 */
393 fr_assert(fr_bio_buf_used(&my->write_buffer) == 0);
394
395 next = fr_bio_next(&my->bio);
396 fr_assert(next != NULL);
397
398 /*
399 * The next bio may write all of the data. If so, we return that,
400 */
401 rcode = next->write(next, packet_ctx, buffer, size);
402 if ((size_t) rcode == size) return rcode;
403
404 /*
405 * The next bio returned an error. Anything other than WOULD BLOCK is fatal. We can read from
406 * the memory buffer until it's empty, but we can no longer write to the memory buffer.
407 */
408 if ((rcode < 0) && (rcode != fr_bio_error(IO_WOULD_BLOCK))) {
411 return rcode;
412 }
413
414 /*
415 * We were flushing the BIO, return however much data we managed to write.
416 *
417 * Note that flushes should never block.
418 */
419 if (!buffer) {
420 fr_assert(rcode != fr_bio_error(IO_WOULD_BLOCK));
421 return rcode;
422 }
423
424 /*
425 * Tell previous BIOs in the chain that they are blocked.
426 */
427 error = fr_bio_write_blocked(bio);
428 if (error < 0) return error;
429
430 fr_assert(error != 0); /* what to do? */
431
432 /*
433 * We had WOULD BLOCK, or wrote partial bytes. Save the data to the memory buffer, and ensure
434 * that future writes are ordered. i.e. they write to the memory buffer before writing to the
435 * next bio.
436 */
438
439 /*
440 * Clamp the write to however much data is available in the buffer.
441 */
442 leftover = size - rcode;
443 room = fr_bio_buf_write_room(&my->write_buffer);
444
445 /*
446 * If we have "used == 0" above, then we must also have "room > 0".
447 */
448 fr_assert(room > 0);
449
450 if (room < leftover) leftover = room;
451
452 /*
453 * Since we've clamped the write, this call can never fail.
454 */
455 (void) fr_bio_buf_write(&my->write_buffer, ((uint8_t const *) buffer) + rcode, leftover);
456
457 /*
458 * Some of the data base been written to the next bio, and some to our cache. The caller has to
459 * ensure that the first subsequent write will send over the rest of the data.
460 *
461 * However, we tell the caller that we wrote the entire packet. Because we are now responsible
462 * for writing the remaining bytes.
463 */
464 return size;
465}
466
467/** Flush the memory buffer.
468 *
469 */
471{
472 int rcode;
473 size_t used;
474 fr_bio_t *next;
475
476 /*
477 * Nothing to flush, don't do any writes.
478 *
479 * Instead, set the write function to write next, where data will be sent directly to the next
480 * bio, and will bypass the write buffer.
481 */
482 used = fr_bio_buf_used(&my->write_buffer);
483 if (!used) {
484 my->bio.write = fr_bio_mem_write_next;
485 return 0;
486 }
487
488 next = fr_bio_next(&my->bio);
489 fr_assert(next != NULL);
490
491 /*
492 * Clamp the amount of data written. If the caller wants to write everything, it should
493 * pass SIZE_MAX.
494 */
495 if (used < size) used = size;
496
497 /*
498 * Flush the buffer to the next bio in line. That function will write as much data as possible,
499 * but may return a partial write.
500 */
501 rcode = next->write(next, NULL, my->write_buffer.write, used);
502
503 /*
504 * We didn't write anything, the bio is blocked.
505 */
506 if ((rcode == 0) || (rcode == fr_bio_error(IO_WOULD_BLOCK))) return fr_bio_error(IO_WOULD_BLOCK);
507
508 /*
509 * All other errors are fatal. We can read from the memory buffer until it's empty, but we can
510 * no longer write to the memory buffer.
511 */
512 if (rcode < 0) return rcode;
513
514 /*
515 * Tell the buffer that we've read a certain amount of data from it.
516 */
517 (void) fr_bio_buf_read(&my->write_buffer, NULL, (size_t) rcode);
518
519 /*
520 * We haven't emptied the buffer, any further IO is blocked.
521 */
522 if ((size_t) rcode < used) return fr_bio_error(IO_WOULD_BLOCK);
523
524 /*
525 * We've flushed all of the buffer. Revert back to "pass through" writing.
526 */
527 fr_assert(fr_bio_buf_used(&my->write_buffer) == 0);
528 my->bio.write = fr_bio_mem_write_next;
529 return rcode;
530}
531
532/** Write to the memory buffer.
533 *
534 * The special buffer pointer of NULL means flush(). On flush, we call next->read(), and if that succeeds,
535 * go back to "pass through" mode for the buffers.
536 */
537static ssize_t fr_bio_mem_write_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void const *buffer, size_t size)
538{
539 size_t room;
540 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
541
542 /*
543 * Flush the output buffer.
544 */
545 if (unlikely(!buffer)) return fr_bio_mem_write_flush(my, size);
546
547 /*
548 * Clamp the write to however much data is available in the buffer.
549 */
550 room = fr_bio_buf_write_room(&my->write_buffer);
551
552 /*
553 * The buffer is full, we can't write anything.
554 */
555 if (!room) return fr_bio_error(IO_WOULD_BLOCK);
556
557 /*
558 * If we're asked to write more bytes than are available in the buffer, then tell the caller that
559 * writes are now blocked, and we can't write any more data.
560 *
561 * Return an WOULD_BLOCK error instead of breaking our promise by writing part of the data,
562 * instead of accepting a full application write.
563 */
564 if (room < size) {
565 int rcode;
566
567 rcode = fr_bio_write_blocked(bio);
568 if (rcode < 0) return rcode;
569
570 return fr_bio_error(IO_WOULD_BLOCK);
571 }
572
573 /*
574 * As we have clamped the write, we know that this call must succeed.
575 */
576 (void) fr_bio_buf_write(&my->write_buffer, buffer, size);
577
578 /*
579 * If we've filled the buffer, tell the caller that writes are now blocked, and we can't write
580 * any more data. However, we still return the amount of data we wrote.
581 */
582 if (room == size) {
583 int rcode;
584
585 rcode = fr_bio_write_blocked(bio);
586 if (rcode < 0) return rcode;
587 }
588
589 return size;
590}
591
592/** Peek at the data in the read buffer
593 *
594 * Peeking at the data allows us to avoid many memory copies.
595 */
596uint8_t const *fr_bio_mem_read_peek(fr_bio_t *bio, size_t *size)
597{
598 size_t used;
599 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
600
601 used = fr_bio_buf_used(&my->read_buffer);
602
603 if (!used) return NULL;
604
605 *size = used;
606 return my->read_buffer.read;
607}
608
609/** Discard data from the read buffer.
610 *
611 * Discarding allows the caller to silently omit packets, so that
612 * they are not passed up to previous bios.
613 */
614void fr_bio_mem_read_discard(fr_bio_t *bio, size_t size)
615{
616 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
617
618 (void) fr_bio_buf_read(&my->read_buffer, NULL, size);
619}
620
621/** Verify that a packet is OK.
622 *
623 * @todo - have this as a parameter to the read routines, so that they only return complete packets?
624 *
625 * @param bio the #fr_bio_mem_t
626 * @param packet_ctx the packet ctx
627 * @param[out] size how big the verified packet is
628 * @return
629 * - <0 for FR_BIO_VERIFY_ERROR_CLOSE, the caller should close the bio.
630 * - 0 for "we have a partial packet", the size to read is in *size
631 * - 1 for "we have at least one good packet", the size of it is in *size
632 */
633static int fr_bio_mem_call_verify(fr_bio_t *bio, void *packet_ctx, size_t *size)
634{
635 uint8_t *packet, *end;
636 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
637
638 packet = my->read_buffer.read;
639 end = my->read_buffer.write;
640
641 while (packet < end) {
642 size_t want;
643#ifndef NDEBUG
644 size_t used;
645
646 used = end - packet;
647#endif
648
649 want = end - packet;
650
651 switch (my->verify((fr_bio_t *) my, my->verify_ctx, packet_ctx, packet, &want)) {
652 /*
653 * The data in the buffer is exactly a packet. Return that.
654 *
655 * @todo - if there are multiple packets, return the total size of packets?
656 */
657 case FR_BIO_VERIFY_OK:
658 fr_assert(want <= used);
659 *size = want;
660 return 1;
661
662 /*
663 * The packet needs more data. Return how much data we need for one packet.
664 */
666 fr_assert(want > used);
667 *size = want;
668 return 0;
669
671 /*
672 * We don't call fr_bio_buf_read(), because that will move the memory around, and
673 * we want to avoid that if at all possible.
674 */
675 fr_assert(want <= used);
676 fr_assert(packet == my->read_buffer.read);
677 my->read_buffer.read += want;
678 continue;
679
680 /*
681 * Some kind of fatal validation error.
682 */
684 break;
685 }
686 }
687
688 return -1;
689}
690
691/*
692 * The application can read from the BIO until EOF, but cannot write to it.
693 */
695{
698}
699
700/** Allocate a memory buffer bio for either reading or writing.
701 */
702static bool fr_bio_mem_buf_alloc(fr_bio_mem_t *my, fr_bio_buf_t *buf, size_t size)
703{
704 if (size < 1024) size = 1024;
705 if (size > (1 << 20)) size = 1 << 20;
706
707 if (fr_bio_buf_alloc(my, buf, size) < 0) {
709 return false;
710 }
711
712 return true;
713}
714
715/** Allocate a memory buffer bio
716 *
717 * The "read buffer" will cache reads from the next bio in the chain. If the next bio returns more data than
718 * the caller asked for, the extra data is cached in the read buffer.
719 *
720 * The "write buffer" will buffer writes to the next bio in the chain. If the caller writes more data than
721 * the next bio can process, the extra data is cached in the write buffer.
722 *
723 * When the bio is closed (or freed) any pending data in the buffers is lost. The same happens if the next
724 * bio returns a fatal error.
725 *
726 * At some point during a read, the next bio may return EOF. When that happens, the caller should not rely
727 * on the next FD being readable or writable. Instead, it should keep reading from the memory bio until it
728 * returns EOF. See fr_bio_fd_eof() for details.
729 *
730 * @param ctx the talloc ctx
731 * @param read_size size of the read buffer. Must be 1024..1^20
732 * @param write_size size of the write buffer. Can be zero. If non-zero, must be 1024..1^20
733 * @param next the next bio which will perform the underlying reads and writes.
734 * - NULL on error, memory allocation failed
735 * - !NULL the bio
736 */
737fr_bio_t *fr_bio_mem_alloc(TALLOC_CTX *ctx, size_t read_size, size_t write_size, fr_bio_t *next)
738{
740
741 my = talloc_zero(ctx, fr_bio_mem_t);
742 if (!my) return NULL;
743
744 /*
745 * We can do 0-sized buffers for read, and the application should then set the verify function.
746 */
747 if (!read_size) {
748 my->type = FR_BIO_MEM_VERIFY;
749 my->bio.read = fr_bio_null_read; /* can't read anything until the verify routine is put in place */
750 my->bio.write = fr_bio_next_write;
751
752 if (write_size > 0) {
754 fr_strerror_const("Invalid write size. If read size is zero, then write size must also be zero");
755 return NULL;
756 }
757
758 } else {
759 /*
760 * We have a read buffer, and potentially a write buffer.
761 */
762 my->type = FR_BIO_MEM_BUFFER;
763
764 if (!fr_bio_mem_buf_alloc(my, &my->read_buffer, read_size)) {
765 oom:
766 fr_strerror_const("Out of memory");
767 return NULL;
768 }
769 my->bio.read = fr_bio_mem_read;
770
771 if (write_size) {
772 if (!fr_bio_mem_buf_alloc(my, &my->write_buffer, write_size)) goto oom;
773
774 /*
775 * Default to passing writes straight through, but buffer them locally if the
776 * write blocks.
777 *
778 * We also only need to resume writes if we're buffering data.
779 */
780 my->bio.write = fr_bio_mem_write_next;
781 my->priv_cb.write_resume = fr_bio_mem_write_resume;
782
783 } else {
784 my->bio.write = fr_bio_next_write;
785 }
786
787 /*
788 * EOF and shutdown are needed if there's a read buffer, but not when the memory bio is
789 * just doing packet verification/
790 */
791 my->priv_cb.eof = fr_bio_mem_eof;
792 my->priv_cb.shutdown = fr_bio_mem_shutdown;
793 }
794
795 fr_bio_chain(&my->bio, next);
796
797 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor);
798 return (fr_bio_t *) my;
799}
800
801
802/** Allocate a memory buffer which sources data from the callers application into the bio system.
803 *
804 * The caller writes data to the buffer, but never reads from it. This bio will call the "next" bio to write
805 * the data. somewhere.
806 */
807fr_bio_t *fr_bio_mem_source_alloc(TALLOC_CTX *ctx, size_t write_size, fr_bio_t *next)
808{
810
811 /*
812 * The caller has to state that the API is caching data.
813 */
814 if (!write_size) return NULL;
815
816 my = talloc_zero(ctx, fr_bio_mem_t);
817 if (!my) return NULL;
818
819 if (!fr_bio_mem_buf_alloc(my, &my->write_buffer, write_size)) {
821 return NULL;
822 }
823
824 my->type = FR_BIO_MEM_SOURCE;
825 my->bio.read = fr_bio_null_read; /* reading FROM this bio is not possible */
826 my->bio.write = fr_bio_mem_write_next;
827
828 /*
829 * @todo - have write pause / write resume callbacks?
830 */
831 my->priv_cb.shutdown = fr_bio_mem_shutdown;
832
833 fr_bio_chain(&my->bio, next);
834
835 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor);
836 return (fr_bio_t *) my;
837}
838
839/** Read from a buffer which a previous bio has filled.
840 *
841 * This function is called by the application which wants to read from a sink.
842 */
843static ssize_t fr_bio_mem_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
844{
845 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
846
847 return fr_bio_buf_read(&my->read_buffer, buffer, size);
848}
849
850/** Write to the read buffer.
851 *
852 * This function is called by an upstream function which writes into our local buffer.
853 */
854static ssize_t fr_bio_mem_write_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void const *buffer, size_t size)
855{
856 size_t room;
857 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
858
859 /*
860 * Clamp the write to however much data is available in the buffer.
861 */
862 room = fr_bio_buf_write_room(&my->read_buffer);
863
864 /*
865 * The buffer is full. We're now blocked.
866 */
867 if (!room) return fr_bio_error(IO_WOULD_BLOCK);
868
869 if (room < size) size = room;
870
871 /*
872 * As we have clamped the write, we know that this call must succeed.
873 */
874 return fr_bio_buf_write(&my->read_buffer, buffer, size);
875}
876
877/** Allocate a memory buffer which sinks data from a bio system into the callers application.
878 *
879 * The caller reads data from this bio, but never writes to it. Upstream BIOs will source the data.
880 */
881fr_bio_t *fr_bio_mem_sink_alloc(TALLOC_CTX *ctx, size_t read_size)
882{
884
885 /*
886 * The caller has to state that the API is caching data.
887 */
888 if (!read_size) return NULL;
889
890 my = talloc_zero(ctx, fr_bio_mem_t);
891 if (!my) return NULL;
892
893 if (!fr_bio_mem_buf_alloc(my, &my->read_buffer, read_size)) {
895 return NULL;
896 }
897
898 my->type = FR_BIO_MEM_SINK;
899 my->bio.read = fr_bio_mem_read_buffer;
900 my->bio.write = fr_bio_mem_write_read_buffer; /* the upstream will write to our read buffer */
901
902 talloc_set_destructor((fr_bio_t *) my, fr_bio_destructor);
903 return (fr_bio_t *) my;
904}
905
906/** Set the verification function for memory bios.
907 *
908 * It is possible to add a verification function. It is not currently possible to remove one.
909 *
910 * @param bio the binary IO handler
911 * @param verify the verification function
912 * @param datagram whether or not this bio is a datagram one.
913 * @return
914 * - <0 on error
915 * - 0 on success
916 */
917int fr_bio_mem_set_verify(fr_bio_t *bio, fr_bio_verify_t verify, void *verify_ctx, bool datagram)
918{
919 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
920
921 switch (my->type) {
923 fr_assert(0);
924 return -1;
925
927 case FR_BIO_MEM_SINK:
928 fr_strerror_const("Cannot add verify to this memory BIO");
929 return fr_bio_error(GENERIC);
930
932 fr_assert(my->bio.write == fr_bio_next_write);
933 if (!datagram) {
934 fr_strerror_const("Invalid memory BIO - we need a read buffer for verifying packets from a stream socket");
935 return -1;
936 }
938
940 break;
941 }
942
943 my->verify = verify;
944 my->verify_ctx = verify_ctx;
945
946 /*
947 * For reading datagrams, we just verify the packet in place. This works both when we have local
948 * buffers, and when we are verifying packets in the application-supplied buffer.
949 *
950 * For writing datagrams, then we cannot buffer individual datagrams. We must write
951 * either all of the datagram out, or none of it.
952 */
953 if (datagram) {
955 my->bio.write = fr_bio_next_write;
956
957 /*
958 * Might as well free the memory for the write buffer. It won't be used.
959 */
960 if (my->write_buffer.start) {
961 talloc_free(my->write_buffer.start);
962 my->write_buffer = (fr_bio_buf_t) {};
963 }
964 } else {
966 /* don't touch the write function or the write buffer. */
967 }
968
969 return 0;
970}
971
972/*
973 * There's no fr_bio_mem_write_blocked()
974 */
975
976/** See if we can resume writes to the memory bio.
977 *
978 * Note that there is no equivalent fr_bio_mem_write_blocked(), as that function wouldn't do anything.
979 * Perhaps it could swap the write function to fr_bio_mem_write_buffer(), but the fr_bio_mem_write_next()
980 * function should automatically do that when the write to the next bio only writes part of the data,
981 * or if it returns fr_bio_error(IO_WOULD_BLOCK)
982 */
984{
985 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
986 ssize_t rcode;
987
988 if (bio->write != fr_bio_mem_write_buffer) return 1;
989
991
992 /*
993 * Flush the buffer, and then reset the write routine if we were successful.
994 */
995 rcode = fr_bio_mem_write_flush(my, SIZE_MAX);
996 if (rcode <= 0) return rcode;
997
998 if (fr_bio_buf_used(&my->write_buffer) > 0) return 0;
999
1000 /*
1001 * Check for an application hook to check if we can resume writes.
1002 */
1003 if (!my->cb.write_resume) return 1;
1004
1005 return my->cb.write_resume(bio);
1006}
1007
1008/** Pause writes.
1009 *
1010 * Calls to fr_bio_write() will write to the memory buffer, and not
1011 * to the next bio. You MUST call fr_bio_mem_write_resume() after
1012 * this to flush any data.
1013 */
1015{
1016 fr_bio_mem_t *my = talloc_get_type_abort(bio, fr_bio_mem_t);
1017
1018 if (my->bio.write == fr_bio_mem_write_buffer) return 0;
1019
1020 if (my->bio.write != fr_bio_mem_write_buffer) return -1;
1021
1022 my->bio.write = fr_bio_mem_write_buffer;
1023
1024 return 0;
1025}
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:116
fr_bio_read_t _CONST read
read from the underlying bio
Definition base.h:115
static fr_bio_t * fr_bio_next(fr_bio_t *bio)
Definition base.h:130
#define fr_bio_error(_x)
Definition base.h:192
static void fr_bio_chain(fr_bio_t *first, fr_bio_t *second)
Chain one bio after another.
Definition bio_priv.h:69
size_t fr_bio_buf_make_room(fr_bio_buf_t *bio_buf)
Definition buf.c:28
size_t fr_bio_buf_read(fr_bio_buf_t *bio_buf, void *buffer, size_t size)
Definition buf.c:45
int fr_bio_buf_alloc(TALLOC_CTX *ctx, fr_bio_buf_t *bio_buf, size_t size)
Definition buf.c:114
ssize_t fr_bio_buf_write(fr_bio_buf_t *bio_buf, const void *buffer, size_t size)
Definition buf.c:81
static size_t fr_bio_buf_write_room(fr_bio_buf_t const *bio_buf)
Definition buf.h:82
static size_t fr_bio_buf_used(fr_bio_buf_t const *bio_buf)
Definition buf.h:73
static uint8_t * fr_bio_buf_write_reserve(fr_bio_buf_t *bio_buf, size_t size)
Definition buf.h:89
static int fr_bio_buf_write_alloc(fr_bio_buf_t *bio_buf, size_t size)
Definition buf.h:98
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
fr_bio_shutdown & my
Definition fd_errno.h:69
int fr_bio_write_blocked(fr_bio_t *bio)
Internal BIO function to tell all BIOs that it's blocked.
Definition base.c:291
void fr_bio_eof(fr_bio_t *bio)
Internal BIO function to run EOF callbacks.
Definition base.c:242
int fr_bio_destructor(fr_bio_t *bio)
Free this bio.
Definition base.c:34
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
fr_bio_t * fr_bio_mem_alloc(TALLOC_CTX *ctx, size_t read_size, size_t write_size, fr_bio_t *next)
Allocate a memory buffer bio.
Definition mem.c:737
static ssize_t fr_bio_mem_write_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void const *buffer, size_t size)
Write to the read buffer.
Definition mem.c:854
static ssize_t fr_bio_mem_read_verify_stream(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Return data only if we have a complete packet.
Definition mem.c:177
void * verify_ctx
verify context
Definition mem.c:49
void fr_bio_mem_read_discard(fr_bio_t *bio, size_t size)
Discard data from the read buffer.
Definition mem.c:614
fr_bio_t * fr_bio_mem_sink_alloc(TALLOC_CTX *ctx, size_t read_size)
Allocate a memory buffer which sinks data from a bio system into the callers application.
Definition mem.c:881
fr_bio_mem_type_t
Definition mem.c:31
@ FR_BIO_MEM_SINK
Definition mem.c:34
@ FR_BIO_MEM_INVALID
Definition mem.c:32
@ FR_BIO_MEM_SOURCE
Definition mem.c:33
@ FR_BIO_MEM_BUFFER
Definition mem.c:36
@ FR_BIO_MEM_VERIFY
Definition mem.c:35
fr_bio_buf_t read_buffer
buffering for reads
Definition mem.c:51
static int fr_bio_mem_eof(fr_bio_t *bio)
Definition mem.c:87
struct fr_bio_mem_s fr_bio_mem_t
The memory buffer bio.
static ssize_t fr_bio_mem_write_next(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Pass writes to the next BIO.
Definition mem.c:380
static ssize_t fr_bio_mem_read_verify_datagram(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Return data only if we have a complete packet.
Definition mem.c:305
fr_bio_t * fr_bio_mem_source_alloc(TALLOC_CTX *ctx, size_t write_size, fr_bio_t *next)
Allocate a memory buffer which sources data from the callers application into the bio system.
Definition mem.c:807
static ssize_t fr_bio_mem_read_buffer(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
Read from a buffer which a previous bio has filled.
Definition mem.c:843
int fr_bio_mem_write_resume(fr_bio_t *bio)
See if we can resume writes to the memory bio.
Definition mem.c:983
fr_bio_buf_t write_buffer
buffering for writes
Definition mem.c:52
fr_bio_verify_t verify
verify data to see if we have a packet.
Definition mem.c:48
FR_BIO_COMMON
Definition mem.c:44
static ssize_t fr_bio_mem_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read from a memory BIO.
Definition mem.c:116
int fr_bio_mem_set_verify(fr_bio_t *bio, fr_bio_verify_t verify, void *verify_ctx, bool datagram)
Set the verification function for memory bios.
Definition mem.c:917
static void fr_bio_mem_shutdown(fr_bio_t *bio)
Definition mem.c:694
fr_bio_mem_type_t type
source, sink, etc.
Definition mem.c:46
static ssize_t fr_bio_mem_read_eof(fr_bio_t *bio, UNUSED void *packet_ctx, void *buffer, size_t size)
At EOF, read data from the buffer until it is empty.
Definition mem.c:64
static bool fr_bio_mem_buf_alloc(fr_bio_mem_t *my, fr_bio_buf_t *buf, size_t size)
Allocate a memory buffer bio for either reading or writing.
Definition mem.c:702
static ssize_t fr_bio_mem_write_flush(fr_bio_mem_t *my, size_t size)
Flush the memory buffer.
Definition mem.c:470
static int fr_bio_mem_call_verify(fr_bio_t *bio, void *packet_ctx, size_t *size))
Verify that a packet is OK.
Definition mem.c:633
int fr_bio_mem_write_pause(fr_bio_t *bio)
Pause writes.
Definition mem.c:1014
uint8_t const * fr_bio_mem_read_peek(fr_bio_t *bio, size_t *size)
Peek at the data in the read buffer.
Definition mem.c:596
static ssize_t fr_bio_mem_write_buffer(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
The memory buffer bio.
Definition mem.c:43
talloc_free(reap)
@ FR_BIO_VERIFY_ERROR_CLOSE
fatal error, the bio should be closed.
Definition mem.h:36
@ FR_BIO_VERIFY_DISCARD
the packet should be discarded
Definition mem.h:34
@ FR_BIO_VERIFY_OK
packet is OK
Definition mem.h:33
@ FR_BIO_VERIFY_WANT_MORE
not enough data for one packet
Definition mem.h:35
fr_bio_verify_action_t(* fr_bio_verify_t)(fr_bio_t *bio, void *verify_ctx, void *packet_ctx, const void *buffer, size_t *size)
Verifies the packet.
Definition mem.h:51
long int ssize_t
unsigned char uint8_t
static size_t used
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 VERIFY(_x)
Definition trie.c:130
#define fr_strerror_const(_msg)
Definition strerror.h:223
int nonnull(2, 5))