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