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