The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
dbuff.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/** A generic data buffer structure for encoding and decoding
19 *
20 * Because doing manual length checks is error prone and a waste of everyone's time.
21 *
22 * @file src/lib/util/dbuff.h
23 *
24 * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
25 */
26RCSIDH(dbuff_h, "$Id: 4eba6e756204bc989ad32f6393cf49ffcbdb8d2e $")
27
28# ifdef __cplusplus
29extern "C" {
30# endif
31
32#include <errno.h>
33#include <freeradius-devel/missing.h>
34#include <freeradius-devel/util/debug.h>
35#include <freeradius-devel/util/nbo.h>
36#include <limits.h>
37#include <sys/types.h>
38
39DIAG_OFF(cast-align)
40
41/** A dbuff
42 *
43 * dbuffs wrap an underlying buffer, maintaining 'start', 'current', and 'end'
44 * position pointers.
45 *
46 * dbuffs also contain information on if and how the underlying buffer can be
47 * extended.
48 *
49 * For encoding extending means reallocing the underlying buffer so that there's
50 * addition space to write data to.
51 *
52 * For stream decoding extending means shifting out existing data and refilling
53 * the underlying buffer from a data source.
54 *
55 * dbuffs are intended to be organised into hierarchies, with one dbuff per stack
56 * frame, initialised from a parent in a higher stack frame.
57 *
58 * Each time a dbuff is copied (using one of the provided FR_DBUFF_BIND_CURRENT_* macros),
59 * the copy's 'start' position is updated to be the 'current' position of its
60 * parent. This ensures length macros report only spaced used/available in the
61 * new dbuff and not its parent.
62 * Other copy macros may move the 'end' position, to artificially limit the
63 * amount of data available.
64 */
65typedef struct fr_dbuff_s fr_dbuff_t;
66
67/** A position marker associated with a dbuff
68 *
69 * Markers are used whenever the caller needs to access part of the underlying
70 * buffer other than the 'start', 'current' or 'end' positions described by
71 * a #fr_dbuff_t.
72 *
73 * Markers are needed because if a #fr_dbuff_t is extended, pointers into the
74 * underlying buffer may be invalidated by a realloc or memmove.
75 *
76 * Markers are intended to be allocated on the stack and associated with a
77 * stack-frame-local `fr_dbuff_t`. Using a stack-frame-local dbuff ensures
78 * markers are automatically released when the stack frame is popped so that
79 * markers are not leaked.
80 */
81typedef struct fr_dbuff_marker_s fr_dbuff_marker_t;
82
83/** dbuff extension callback
84 *
85 * This callback is used to extend the underlying buffer.
86 *
87 * - Where the buffer is being used to aggregate data, this callback will
88 * usually call realloc to extend the buffer.
89 *
90 * - Where the buffer is being used for stream decoding, this callback will
91 * usually shift the existing data in the buffer to the left, and read in more
92 * data from the stream.
93 *
94 * After performing an operation on the underlying buffer, this callback should
95 * call #fr_dbuff_update to fix position pointers in the current dbuff and its
96 * parents and markers.
97 *
98 * Generally the caller will request the minimum amount the buffer should be
99 * extended by. This callback may choose to ignore the request and extend the
100 * buffer by more than the requested amount.
101 *
102 * @param[in] dbuff to extend.
103 * @param[in] req_extension How much the caller wants to extend the buffer
104 * by.
105 * @return How much the buffer was extended by.
106 * @see fr_dbuff_update
107 */
108typedef size_t(*fr_dbuff_extend_t)(fr_dbuff_t *dbuff, size_t req_extension);
109
110/** A position marker associated with a dbuff
111 * @private
112 */
113struct fr_dbuff_marker_s {
114 /** @private
115 */
116 union {
117 uint8_t const *p_i; //!< Immutable position pointer.
118 uint8_t *p; //!< Mutable position pointer.
119 };
120 fr_dbuff_marker_t *next; //!< Next marker in the list.
121 fr_dbuff_t *parent; //!< Owner of the marker.
122};
123
124#define FR_DBUFF_ADV_PARENT_CURRENT 0x01 //!< Advance current position of parent.
125 //!< Useful for nested encoders/decoders.
126#define FR_DBUFF_ADV_PARENT_END 0x02 //!< Advance end pointer of parent.
127 ///< Useful for producer/consumer
128
129/** A dbuff
130 * @private
131 */
132struct fr_dbuff_s {
133 /** @private
134 */
135 union {
136 uint8_t const *buff_i; //!< Immutable 'buffer' pointer.
137 uint8_t *buff; //!< Mutable 'buffer' pointer.
138 };
139
140 /** @private
141 */
142 union {
143 uint8_t const *start_i; //!< Immutable 'start' pointer.
144 uint8_t *start; //!< Mutable 'start' pointer.
145 };
146
147 /** @private
148 */
149 union {
150 uint8_t const *end_i; //!< Immutable 'end' pointer.
151 uint8_t *end; //!< Mutable 'end' pointer.
152 };
153
154 /** @private
155 */
156 union {
157 uint8_t const *p_i; //!< Immutable 'current' pointer.
158 uint8_t *p; //!< Mutable 'current' pointer.
159 };
160
161 unsigned int is_const : 1; //!< The buffer this dbuff wraps is const.
162 unsigned int adv_parent : 2; //!< Whether we advance the parent
163 ///< of this dbuff.
164
165 size_t shifted; //!< How many bytes this sbuff has been
166 ///< shifted since its creation.
167
168 fr_dbuff_extend_t extend; //!< Function to re-populate or extend
169 ///< the buffer.
170 void *uctx; //!< Extend uctx data.
171
172 fr_dbuff_t *parent; //!< The #fr_dbuff_t this #fr_dbuff_t was
173 ///< created from.
174 ///< This will usually be the #fr_dbuff_t
175 ///< passed into a function.
176
177 fr_dbuff_marker_t *m; //!< Pointers to update if the underlying
178 ///< buffer changes.
179};
180
181/** Generic wrapper macro to return if there's insufficient memory to satisfy the request on the dbuff
182 *
183 */
184#define FR_DBUFF_RETURN(_func, ...) \
185do { \
186 ssize_t _slen = _func(__VA_ARGS__ ); \
187 if (_slen < 0) return _slen; \
188} while (0)
189
190/** Generic wrapper to return an error and an offset from encoding.
191 *
192 * Some encoders return PAIR_ENCODE_FATAL_ERROR. Substracting an
193 * offset from that values means it wraps be be a positive number
194 * near INT64_MAX. This macro ensures that doesn't happen.
195 */
196#define FR_DBUFF_ERROR_OFFSET(_slen, _offset) ((_slen < INT32_MAX) ? _slen : _slen - (ssize_t) _offset)
197
198/** @name Initialisers
199 * @{
200 */
201
202/** @cond */
203
204/** Copy another fr_dbuff_t, modifying it.
205 *
206 * @private
207 */
208#define _FR_DBUFF(_dbuff_or_marker, _start, _adv_parent) \
209((fr_dbuff_t){ \
210 .buff = fr_dbuff_buff(_dbuff_or_marker), \
211 .start = (_start), \
212 .end = fr_dbuff_end(_dbuff_or_marker), \
213 .p = fr_dbuff_current(_dbuff_or_marker), \
214 .is_const = fr_dbuff_ptr(_dbuff_or_marker)->is_const, \
215 .adv_parent = (_adv_parent), \
216 .shifted = fr_dbuff_ptr(_dbuff_or_marker)->shifted, \
217 .extend = fr_dbuff_ptr(_dbuff_or_marker)->extend, \
218 .uctx = fr_dbuff_ptr(_dbuff_or_marker)->uctx, \
219 .parent = fr_dbuff_ptr(_dbuff_or_marker) \
220})
221/* @endcond */
222
223/** Create a new dbuff pointing to the same underlying buffer
224 *
225 * - Parent will _NOT_ be advanced by operations on its child.
226 * - Child will have its `start` pointer set to the `p` pointer of the parent.
227 *
228 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
229 */
230#define FR_DBUFF(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_current(_dbuff_or_marker), 0x00)
231
232/** Create a new dbuff pointing to the same underlying buffer
233 *
234 * - Parent will _NOT_ be advanced by operations on its child.
235 * - Child will have its `start` pointer set to the `start` pointer of the parent.
236 *
237 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
238 */
239#define FR_DBUFF_ABS(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker), 0x00)
240
241/** Create a new dbuff pointing to the same underlying buffer
242 *
243 * - Parent `p` pointer will be advanced with child's `p` pointer.
244 * - Child will have its `start` pointer set to the `p` pointer of the parent.
245 *
246 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
247 */
248#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_current(_dbuff_or_marker), FR_DBUFF_ADV_PARENT_CURRENT)
249
250/** Create a new dbuff pointing to the same underlying buffer
251 *
252 * - Parent `p` pointer will be advanced with child's `p` pointer.
253 * - Child will have its `start` pointer set to the `start` pointer of the parent.
254 *
255 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
256 */
257#define FR_DBUFF_BIND_CURRENT_ABS(_dbuff_or_marker) _FR_DBUFF(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker), FR_DBUFF_ADV_PARENT_CURRENT)
258
259/** Create a new dbuff pointing to the same underlying buffer
260 *
261 * This is used to create the producer of a producer/consumer pairs of dbuffs.
262 *
263 * - Parent `end` pointer will be advanced with child's `p` pointer.
264 * - Child will have its `start` pointer set to the `start` pointer of the parent.
265 *
266 * @param[in] _dbuff_or_marker to make an ephemeral copy of.
267 */
268#define FR_DBUFF_BIND_END_ABS(_dbuff_or_marker) \
269 _fr_dbuff_bind_end_abs(_FR_DBUFF(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker), FR_DBUFF_ADV_PARENT_END), \
270 fr_dbuff_ptr(_dbuff_or_marker))
271
272/** @cond */
273/** Bind a producer to a consumer, and start the consumer empty
274 *
275 * The parent consumes data from child.start to child.current. So the
276 * parents start is the childs start, and the parents end is the
277 * childs current. Writes to the child at "current" will then
278 * increase the parents "end", which is how the parent knows that more
279 * data is available.
280 *
281 * The producer might be extendable. The consumers buffer points to
282 * the producers buffer, and is there is not extendable. The consumer
283 * also can't write to the buffer.
284 */
285static inline fr_dbuff_t _fr_dbuff_bind_end_abs(fr_dbuff_t child, fr_dbuff_t *parent)
286{
287 parent->end = UNCONST(uint8_t *, child.p);
288 parent->is_const = true;
289 parent->extend = NULL;
290
291 return child;
292}
293/** @endcond */
294
295/** @cond */
296/** Limit available bytes in the dbuff to _max when passing it to another function
297 *
298 * @private
299 */
300#define _FR_DBUFF_MAX(_dbuff_or_marker, _max, _adv_parent) \
301((fr_dbuff_t){ \
302 .buff = fr_dbuff_buff(_dbuff_or_marker), \
303 .start = fr_dbuff_current(_dbuff_or_marker), \
304 .end = (((fr_dbuff_end(_dbuff_or_marker) - (_max) < fr_dbuff_current(_dbuff_or_marker))) ? fr_dbuff_end(_dbuff_or_marker) : (fr_dbuff_current(_dbuff_or_marker) + (_max))), \
305 .p = fr_dbuff_current(_dbuff_or_marker), \
306 .is_const = fr_dbuff_ptr(_dbuff_or_marker)->is_const, \
307 .adv_parent = _adv_parent, \
308 .shifted = fr_dbuff_ptr(_dbuff_or_marker)->shifted, \
309 .extend = NULL, \
310 .uctx = NULL, \
311 .parent = fr_dbuff_ptr(_dbuff_or_marker) \
312})
313/* @endcond */
314
315/** Limit the maximum number of bytes available in the dbuff when passing it to another function
316 *
317 @code{.c}
318 fr_dbuff_t tlv = FR_DBUFF_MAX(dbuff, UINT8_MAX);
319
320 if (my_child_encoder(&tlv, vp) < 0) return -1;
321
322 return fr_dbuff_advance(dbuff, fr_dbuff_used(tlv))
323 @endcode
324 *
325 * @note Do not use to re-initialise the contents of _dbuff, i.e. to
326 * permanently shrink the exiting dbuff. The parent pointer will loop.
327 *
328 * @note Do not modify the "child" dbuff directly. Use the functions
329 * supplied as part of this API.
330 *
331 * @param[in] _dbuff_or_marker to reserve bytes in.
332 * @param[in] _max The maximum number of bytes the caller is allowed to write to.
333 */
334#define FR_DBUFF_MAX(_dbuff_or_marker, _max) _FR_DBUFF_MAX(_dbuff_or_marker, _max, 0x00)
335
336/** Limit the maximum number of bytes available in the dbuff when passing it to another function
337 *
338 @code{.c}
339 my_child_encoder(&FR_DBUFF_MAX_BIND_CURRENT(dbuff, 253), vp);
340 @endcode
341 *
342 * @note Do not use to re-initialise the contents of _dbuff, i.e. to
343 * permanently shrink the exiting dbuff. The parent pointer will loop.
344 *
345 * @note Do not modify the "child" dbuff directly. Use the functions
346 * supplied as part of this API.
347 *
348 * @param[in] _dbuff_or_marker to reserve bytes in.
349 * @param[in] _max The maximum number of bytes the caller is allowed to write to.
350 */
351#define FR_DBUFF_MAX_BIND_CURRENT(_dbuff_or_marker, _max) _FR_DBUFF_MAX(_dbuff_or_marker, _max, FR_DBUFF_ADV_PARENT_CURRENT)
352
353/*
354 * GCC is stupid and will warn about output variables
355 * being unnitialised, even if they're not dereferenced.
356 */
357#if defined(__GNUC__) && __GNUC__ >= 11
358DIAG_OFF(maybe-uninitialized)
359#endif
360/** Does the actual work of initialising a dbuff
361 * @private
362 */
363static inline
364#ifndef __COVERITY__
365CC_HINT(nonnull)
366#endif
367void _fr_dbuff_init(fr_dbuff_t *out, uint8_t const *start, uint8_t const *end, bool is_const)
368{
369 if (unlikely(end < start)) end = start; /* Could be an assert? */
370
371 *out = (fr_dbuff_t){
372 .buff_i = start,
373 .start_i = start,
374 .p_i = start,
375 .end_i = end,
376 .is_const = is_const
377 };
378}
379
380/** Initialise an dbuff for encoding or decoding
381 *
382 * @param[out] _out Pointer to buffer to parse
383 * @param[in] _start Start of the buffer to parse.
384 * @param[in] _len_or_end Either an end pointer or the length
385 * of the buffer we're decoding.
386 */
387#define fr_dbuff_init(_out, _start, _len_or_end) \
388_fr_dbuff_init(_out, \
389 (uint8_t const *)(_start), \
390 _Generic((_len_or_end), \
391 size_t : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
392 long : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
393 int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
394 unsigned int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
395 uint8_t * : (uint8_t const *)(_len_or_end), \
396 uint8_t const * : (uint8_t const *)(_len_or_end), \
397 char * : (uint8_t const *)(_len_or_end), \
398 char const * : (uint8_t const *)(_len_or_end) \
399 ), \
400 _Generic((_start), \
401 uint8_t * : false, \
402 uint8_t const * : true, \
403 char * : false, \
404 char const * : true \
405 ))
406#if defined(__GNUC__) && __GNUC__ >= 11
407DIAG_ON(maybe-uninitialized)
408#endif
409
410#define FR_DBUFF_INIT(_out, _start, _len_or_end) do { \
411 fr_dbuff_init(_out, _start, _len_or_end); \
412 *(unsigned char *) _start = '\0'; \
413 } while (0)
414
415size_t _fr_dbuff_extend_talloc(fr_dbuff_t *dbuff, size_t extension);
416
417int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len);
418
420
421/** Talloc extension structure use by #fr_dbuff_init_talloc
422 * @private
423 *
424 * Holds the data necessary for creating dynamically
425 * extensible buffers.
426 */
427typedef struct {
428 TALLOC_CTX *ctx; //!< Context to alloc new buffers in.
429 size_t init; //!< How much to allocate initially.
430 size_t max; //!< Maximum size of the buffer.
431} fr_dbuff_uctx_talloc_t;
432
433/** Initialise a special dbuff which automatically extends as additional data is written
434 *
435 * @param[in] ctx to allocate buffer in.
436 * @param[out] dbuff to initialise.
437 * @param[out] tctx to initialise. Must have a lifetime >= to the dbuff.
438 * @param[in] init The length of the initial buffer.
439 * @param[in] max The maximum length of the buffer.
440 * @return
441 * - The passed dbuff on success.
442 * - NULL on failure.
443 */
444static inline fr_dbuff_t *fr_dbuff_init_talloc(TALLOC_CTX *ctx,
445 fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx,
446 size_t init, size_t max)
447{
448 uint8_t *buff;
449
450 *tctx = (fr_dbuff_uctx_talloc_t){
451 .ctx = ctx,
452 .init = init,
453 .max = max
454 };
455
456 /*
457 * Allocate the initial buffer
458 *
459 * We always allocate a buffer so we don't trigger ubsan
460 * errors by performing arithmetic on NULL pointers.
461 *
462 * Note that unlike sbuffs, we don't need space for a trailing '\0'.
463 */
464 buff = talloc_zero_array(ctx, uint8_t, init);
465 if (!buff) {
466 fr_strerror_printf("Failed allocating buffer of %zu bytes", init);
467 memset(dbuff, 0, sizeof(*dbuff)); /* clang scan */
468 return NULL;
469 }
470
471 *dbuff = (fr_dbuff_t){
472 .buff = buff,
473 .start = buff,
474 .p = buff,
475 .end = buff + init,
476 .extend = _fr_dbuff_extend_talloc,
477 .uctx = tctx
478 };
479
480 return dbuff;
481}
482
483/** Free the talloc buffer associated with a dbuff
484 *
485 */
486static inline void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
487{
488 TALLOC_FREE(dbuff->buff);
489}
490
491size_t _fr_dbuff_extend_fd(fr_dbuff_t *dbuff, size_t extension);
492
493/** File sbuff extension structure use by #fr_dbuff_init_fd
494 * @private
495 *
496 * Holds the data necessary for creating dynamically
497 * extensible file buffers.
498 */
499typedef struct {
500 int fd; //!< fd of file we're reading from.
501 uint8_t *buff_end; //!< The true end of the buffer.
502 size_t max; //!< Maximum number of bytes to read.
503} fr_dbuff_uctx_fd_t;
504
505
506/** Initialise a special dbuff which automatically reads in more data as the buffer is exhausted
507 *
508 * @param[out] dbuff to initialise.
509 * @param[out] fctx to initialise. Must have a lifetime >= to the dbuff.
510 * @param[in] buff Temporary buffer to use for storing file contents.
511 * @param[in] len Length of the temporary buffer.
512 * @param[in] fd descriptor of an open file to read from.
513 * @param[in] max The maximum length of data to read from the file.
514 * @return
515 * - The passed dbuff on success.
516 * - NULL on failure.
517 */
518static inline fr_dbuff_t *fr_dbuff_init_fd(fr_dbuff_t *dbuff, fr_dbuff_uctx_fd_t *fctx,
519 uint8_t *buff, size_t len, int fd, size_t max)
520{
521 *fctx = (fr_dbuff_uctx_fd_t){
522 .fd = fd,
523 .max = max,
524 .buff_end = buff + len //!< Store the real end
525 };
526
527 *dbuff = (fr_dbuff_t){
528 .buff = buff,
529 .start = buff,
530 .p = buff,
531 .end = buff, //!< Starts with 0 bytes available
532 .extend = _fr_dbuff_extend_fd,
533 .uctx = fctx
534 };
535
536 return dbuff;
537}
538
539/** Creates a compound literal to pass into functions which accept a dbuff
540 *
541 * @note The return value of the function should be used to determine how much
542 * data was written to the buffer.
543 *
544 * @param[in] _start of the buffer.
545 * @param[in] _len_or_end Length of the buffer or the end pointer.
546 */
547#define FR_DBUFF_TMP(_start, _len_or_end) \
548(fr_dbuff_t){ \
549 .buff_i = (uint8_t const *)(_start), \
550 .start_i = (uint8_t const *)(_start), \
551 .end_i = _Generic((_len_or_end), \
552 size_t : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
553 long : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
554 int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
555 unsigned int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
556 uint8_t * : (uint8_t const *)(_len_or_end), \
557 uint8_t const * : (uint8_t const *)(_len_or_end), \
558 char * : (uint8_t const *)(_len_or_end), \
559 char const * : (uint8_t const *)(_len_or_end) \
560 ), \
561 .p_i = _start, \
562 .is_const = _Generic((_start), \
563 uint8_t * : false, \
564 uint8_t const * : true, \
565 char * : false, \
566 char const * : true \
567 ) \
568}
569
570/** Structure to encapsulate a thread local dbuff information
571 *
572 */
573typedef struct {
574 fr_dbuff_t dbuff; //!< Thread local dbuff.
575 fr_dbuff_uctx_talloc_t tctx; //!< Thread local tctx.
577
578static inline int _dbuff_thread_local_free(void *dbtl)
579{
580 return talloc_free(dbtl);
581}
582
583/** Create a function local and thread local extensible dbuff
584 *
585 * @param[out] _out Where to write a pointer to the thread local dbuff
586 * @param[in] _init Initial size for the dbuff buffer.
587 * @param[in] _max Maximum size of the dbuff buffer.
588 */
589#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max) \
590do { \
591 static _Thread_local fr_dbuff_thread_local_t *_dbuff_t_local; \
592 if (!_dbuff_t_local) { \
593 fr_dbuff_thread_local_t *dbtl = talloc_zero(NULL, fr_dbuff_thread_local_t); \
594 fr_dbuff_init_talloc(dbtl, &dbtl->dbuff, &dbtl->tctx, _init, _max); \
595 fr_atexit_thread_local(_dbuff_t_local, _dbuff_thread_local_free, dbtl); \
596 *(_out) = &_dbuff_t_local->dbuff; \
597 } else { \
598 fr_dbuff_reset_talloc(&_dbuff_t_local->dbuff); \
599 *(_out) = &_dbuff_t_local->dbuff; \
600 } \
601} while (0)
602/** @} */
603
604/** @name Extension requests
605 *
606 * These functions/macros may be used to request that the underlying buffer is
607 * either extended to accommodate more data, or that data is shifted out of the
608 * buffer, and that the buffer is refilled.
609 *
610 * @{
611 */
612
613/** Flag indicating a dbuff is extendable
614 */
615#define FR_DBUFF_FLAG_EXTENDABLE 0x01
616
617/** Flag indicating that during the last extend call the dbuff was extended
618 */
619#define FR_DBUFF_FLAG_EXTENDED 0x02
620
621/** Whether the buffer is currently extendable and whether it was extended
622 */
623typedef enum {
624 /** dbuff cannot be extended
625 */
627
628 /** dbuff can be extended
629 */
631
632 /** dbuff was extended in the last extend call and may be extended again
633 */
635
636 /** dbuff was extended in the last extend call but cannot be extended again
637 */
640
641/** Check if a dbuff can be extended again
642 */
643#define fr_dbuff_is_extendable(_status) ((_status) & FR_DBUFF_FLAG_EXTENDABLE)
644
645/** Check if the dbuff was extended during the last extend call
646 */
647#define fr_dbuff_was_extended(_status) ((_status) & FR_DBUFF_FLAG_EXTENDED)
648
649/** Internal function - do not call directly
650 * @private
651 */
652static inline size_t _fr_dbuff_extend_lowat(fr_dbuff_extend_status_t *status, fr_dbuff_t *in,
653 size_t remaining, size_t lowat)
654{
655 size_t extended = 0;
656
657 /*
658 * A 'const' dbuff cannot be extended. A dbuff without
659 * an 'extend' function cannot be extended.
660 *
661 * Return how many bytes remain in the buffer.
662 */
663 if (in->is_const || !in->extend || (status && (*status = FR_DBUFF_NOT_EXTENDABLE))) {
664 not_extendable:
665 if (status) *status = FR_DBUFF_NOT_EXTENDABLE;
666 return remaining;
667 }
668
669 if (remaining >= lowat) {
670 if (status) *status = FR_DBUFF_EXTENDABLE;
671 return remaining;
672 }
673
674 /*
675 * If we can't extend the buffer, return that it's not extendible.
676 */
677 extended = in->extend(in, lowat - remaining);
678 if (!extended) goto not_extendable;
679
680 if (status) *status = FR_DBUFF_EXTENDABLE_EXTENDED;
681
682 return remaining + extended;
683}
684
685/** Extend if we're below _lowat
686 *
687 * @param[out] _status May be NULL. If fr_dbuff_extend_lowat is used
688 * in a copy loop, the caller should pass a pointer
689 * to a #fr_dbuff_extend_status_t. The initial
690 * value of the #fr_dbuff_extend_status_t variable
691 * should be #FR_DBUFF_EXTENDABLE, and will be updated
692 * to indicate whether the dbuff is extensible,
693 * whether it was extended, and whether it may be
694 * extended again. This information
695 * is used the loop condition to prevent spurious
696 * extension calls.
697 * @param[in] _dbuff_or_marker to extend.
698 * @param[in] _lowat If bytes remaining are below the amount, extend.
699 * @return
700 * - 0 if there are no bytes left in the buffer and we couldn't extend.
701 * - >0 the number of bytes in the buffer after extending.
702 */
703#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat) \
704 _fr_dbuff_extend_lowat(_status, \
705 fr_dbuff_ptr(_dbuff_or_marker), \
706 fr_dbuff_remaining(_dbuff_or_marker), _lowat)
707
708/** Extend if we're below _lowat and return if we can't extend above _lowat
709 *
710 * @param[in] _dbuff_or_marker to extend.
711 * @param[in] _lowat If bytes remaining are below the amount, extend.
712 * @return
713 * - 0 if there are no bytes left in the buffer and we couldn't extend.
714 * - >0 the number of bytes in the buffer after extending.
715 */
716#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat) \
717do { \
718 size_t _remaining = fr_dbuff_extend_lowat(NULL, _dbuff_or_marker, _lowat); \
719 if (_remaining < _lowat) return -(_lowat - _remaining); \
720} while (0)
721
722/** @cond */
723/** Extend if we're below _lowat and return if we can't extend above _lowat
724 *
725 * @private
726 *
727 * @param[in,out] _pos_p the position pointer to use.
728 * @param[in] _dbuff_or_marker to extend.
729 * @param[in] _lowat The minimum amount the dbuff should be extended by.
730 * @return The number of bytes we would need to satisfy _lowat as a negative integer.
731 */
732#define _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(_pos_p, _dbuff_or_marker, _lowat) \
733do { \
734 size_t _remaining = _fr_dbuff_extend_lowat(NULL, \
735 fr_dbuff_ptr(_dbuff_or_marker), \
736 fr_dbuff_end(_dbuff_or_marker) - (*(_pos_p)), _lowat); \
737 if (_remaining < _lowat) return -(_lowat - _remaining); \
738} while (0)
739/** @endcond */
740
741/** Extend if no space remains
742 *
743 * @param[in] _dbuff to extend.
744 * @return
745 * - 0 if there are no bytes left in the buffer and we couldn't extend.
746 * - >0 the number of bytes in the buffer after extending.
747 */
748#define fr_dbuff_extend(_dbuff) fr_dbuff_extend_lowat(NULL, _dbuff, 1)
749/** @} */
750
751/** @name Extension callback helpers
752 *
753 * These public functions are intended to be called by extension callbacks
754 * to fixup dbuffs after the underlying buffer or its contents has been altered.
755 * @{
756 */
757void fr_dbuff_update(fr_dbuff_t *dbuff, uint8_t *new_buff, size_t new_len);
758
759size_t fr_dbuff_shift(fr_dbuff_t *dbuff, size_t shift);
760/** @} */
761
762/** @name Length checks
763 *
764 * These macros return the amount of data used/remaining relative to the dbuff
765 * or marker's 'start', 'current', and 'end' pointers.
766 *
767 * In the majority of cases these macros should not be used and the extension
768 * request functions should be used instead. The only exception to this is if
769 * the caller is certain the #fr_dbuff_t is not extensible.
770 *
771 * @{
772 */
773/** Return the number of bytes remaining between the dbuff or marker and the end of the buffer
774 *
775 * @note Do not use this in functions that may be used for stream decoding
776 * unless you're sure you know what you're doing.
777 * The value return does not reflect the number of bytes that may
778 * be potentially read from the stream, only the number of bytes
779 * until the end of the current chunk.
780 *
781 * @param[in] _dbuff_or_marker to return the number of bytes remaining for.
782 * @return
783 * - >0 the number of bytes remaining before we reach the end of the buffer.
784 * - -0 we're at the end of the buffer.
785 */
786#define fr_dbuff_remaining(_dbuff_or_marker) \
787 ((size_t)(fr_dbuff_end(_dbuff_or_marker) < fr_dbuff_current(_dbuff_or_marker) ? \
788 0 : (fr_dbuff_end(_dbuff_or_marker) - fr_dbuff_current(_dbuff_or_marker))))
789
790/** Check if _len bytes are available in the dbuff and if not return the number of bytes we'd need
791 *
792 * @note Do not use this in functions that may be used for stream decoding
793 * unless you're sure you know what you're doing.
794 * The value return does not reflect the number of bytes that may
795 * be potentially read from the stream, only the number of bytes
796 * until the end of the current chunk.
797 *
798 * @param[in] _dbuff_or_marker to return the number of bytes remaining for.
799 * @param[in] _len Minimum remaining bytes.
800 * @return
801 * - >0 the number of bytes remaining before we reach the end of the buffer.
802 * - -0 we're at the end of the buffer.
803 */
804#define FR_DBUFF_REMAINING_RETURN(_dbuff_or_marker, _len) \
805 if ((_len) > fr_dbuff_remaining(_dbuff_or_marker)) return -((_len) - fr_dbuff_remaining(_dbuff_or_marker))
806
807/** Return the number of bytes remaining between the start of the dbuff or marker and the current position
808 *
809 */
810#define fr_dbuff_used(_dbuff_or_marker) \
811 ((size_t)(fr_dbuff_start(_dbuff_or_marker) > fr_dbuff_current(_dbuff_or_marker) ? \
812 0 : (fr_dbuff_current(_dbuff_or_marker) - fr_dbuff_start(_dbuff_or_marker))))
813
814/** The length of the underlying buffer
815 *
816 * @param[in] _dbuff_or_marker to return the length of.
817 * @return The length of the underlying buffer.
818 */
819#define fr_dbuff_len(_dbuff_or_marker) \
820 ((size_t)(fr_dbuff_end(_dbuff_or_marker) - fr_dbuff_start(_dbuff_or_marker)))
821
822/** How many bytes the dbuff or marker is behind its parent
823 *
824 * @param[in] _dbuff_or_marker
825 * @return
826 * - 0 the dbuff or marker is ahead of its parent.
827 * - >0 the number of bytes the marker is behind its parent.
828 */
829#define fr_dbuff_behind(_dbuff_or_marker) \
830 (fr_dbuff_current(_dbuff_or_marker) > fr_dbuff_current((_dbuff_or_marker)->parent) ? \
831 0 : fr_dbuff_current((_dbuff_or_marker)->parent) - fr_dbuff_current(_dbuff_or_marker))
832
833/** How many bytes the dbuff or marker is ahead of its parent
834 *
835 * @return
836 * - 0 the dbuff or marker is behind its parent.
837 * - >0 the number of bytes the marker is ahead of its parent.
838 */
839#define fr_dbuff_ahead(_dbuff_or_marker) \
840 (fr_dbuff_current((_dbuff_or_marker)->parent) > fr_dbuff_current(_dbuff_or_marker) ? \
841 0 : fr_dbuff_current(_dbuff_or_marker) - fr_dbuff_current((_dbuff_or_marker)->parent))
842/** @} */
843
844/** @name Accessors
845 *
846 * Caching the pointers returned by the accessors is strongly discouraged.
847 * Cached pointers can become invalidated if the #fr_dbuff_t is extended, as
848 * the extensions callback may use realloc or memmove on the underlying buffer.
849 *
850 @code{.c}
851 fr_dbuff_t dbuff;
852 fr_dbuff_uctx_talloc_t tctx;
853 uint8_t *p;
854
855 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, SIZE_MAX);
856
857 p = fr_dbuff_current(&dbuff); // Cache the start pointer
858 fr_dbuff_extend_lowat(&dbuff, 1024); // Extension call triggers realloc
859
860 printf("%s", p); // Should print an empty string but may
861 // SEGV as p may now be invalid.
862 @endcode
863 *
864 * If offsets of a #fr_dbuff_t need to be accessed, markers should be used.
865 * If a dbuff is extended all markers associated with it will be updated so that the
866 * content they point to remains constant.
867 *
868 @code{.c}
869 fr_dbuff_t dbuff;
870 fr_dbuff_uctx_talloc_t tctx;
871 fr_dbuff_marker_t m;
872
873 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, SIZE_MAX);
874 fr_dbuff_marker(&m, &dbuff);
875
876 fr_dbuff_extend_lowat(&dbuff, 1024); // Extension call triggers realloc
877
878 printf("%s", fr_dbuff_current(&m)); // Marker was updated when the dbuff
879 // was extended. All is well.
880 @endcode
881 *
882 * Using offsets of the pointers returned by accessor functions is also strongly
883 * discouraged as it invalidates many of the protections dbuffs give.
884 *
885 @code{.c}
886 uint8_t buff[2];
887 fr_dbuff_t dbuff;
888
889 fr_dbuff_init(&dbuff, buff, sizeof(buff));
890 fr_dbuff_current(&dbuff)[2] = 0x00; // Write to invalid memory
891 @endcode
892 *
893 * @{
894 */
895
896/** Return a pointer to the dbuff
897 *
898 * @param[in] _dbuff_or_marker to return a pointer to.
899 * @return A pointer to the dbuff.
900 */
901#define fr_dbuff_ptr(_dbuff_or_marker) \
902 _Generic((_dbuff_or_marker), \
903 fr_dbuff_t * : ((fr_dbuff_t *)(_dbuff_or_marker)), \
904 fr_dbuff_marker_t * : (((fr_dbuff_marker_t *)(_dbuff_or_marker))->parent) \
905 )
906
907/** Return a const pointer to the dbuff
908 *
909 * @param[in] _dbuff_or_marker to return a pointer to.
910 * @return A pointer to the dbuff.
911 */
912#define fr_dbuff_ptr_const(_dbuff_or_marker) \
913 _Generic((_dbuff_or_marker), \
914 fr_dbuff_t * : ((fr_dbuff_t const *)(_dbuff_or_marker)), \
915 fr_dbuff_t const * : ((fr_dbuff_t const *)(_dbuff_or_marker)), \
916 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent), \
917 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent) \
918 )
919
920/** Return the underlying buffer in a dbuff or one of marker
921 *
922 * @param[in] _dbuff_or_marker to return the buffer for.
923 * @return A pointer to the start of the buffer.
924 */
925#define fr_dbuff_buff(_dbuff_or_marker) \
926 _Generic((_dbuff_or_marker), \
927 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->buff), \
928 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->buff), \
929 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->buff), \
930 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->buff) \
931 )
932
933/** Return the 'start' position of a dbuff or marker
934 *
935 * The start position is not necessarily the start of the buffer, and is
936 * advanced every time a dbuff is copied.
937 *
938 * @param[in] _dbuff_or_marker to return the start position of.
939 * @return A pointer to the start position of the buffer.
940 */
941#define fr_dbuff_start(_dbuff_or_marker) \
942 (_Generic((_dbuff_or_marker), \
943 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->start), \
944 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->start), \
945 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->start), \
946 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->start) \
947 ))
948
949/** Return the 'current' position of a dbuff or marker
950 *
951 * @param[in] _dbuff_or_marker to return the current position of.
952 * @return A pointer to the current position of the buffer or marker.
953 */
954#define fr_dbuff_current(_dbuff_or_marker) \
955 (_Generic((_dbuff_or_marker), \
956 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->p), \
957 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->p), \
958 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->p), \
959 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->p) \
960 ))
961
962/** @cond */
963/** Return a pointer to the 'current' position in a dbuff or marker
964 * @private
965 *
966 * @param[in] _dbuff_or_marker to return a pointer to the position pointer for.
967 * @return A pointer to the position pointer in the dbuff or marker.
968 */
969#define _fr_dbuff_current_ptr(_dbuff_or_marker) \
970 (_Generic((_dbuff_or_marker), \
971 fr_dbuff_t * : &(((fr_dbuff_t *)(_dbuff_or_marker))->p), \
972 fr_dbuff_marker_t * : &(((fr_dbuff_marker_t *)(_dbuff_or_marker))->p) \
973 ))
974/** @endcond */
975
976/** Return the current 'end' position of a dbuff or marker
977 *
978 * @param[in] _dbuff_or_marker to return the end position of.
979 * @return A pointer to the end position of the buffer or marker.
980 */
981#define fr_dbuff_end(_dbuff_or_marker) \
982 (_Generic((_dbuff_or_marker), \
983 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->end), \
984 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->end), \
985 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->end), \
986 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->end) \
987 ))
988/** @} */
989
990/** @name Position modification (recursive)
991 *
992 * Modify the 'current' position pointer of a dbuff or marker.
993 * @{
994 */
995
996/** Set a new 'current' position in a dbuff or marker
997 * @private
998 */
999static inline void _fr_dbuff_set_recurse(fr_dbuff_t *dbuff, uint8_t adv_parent_flags, uint8_t const *p)
1000{
1001 if (adv_parent_flags & FR_DBUFF_ADV_PARENT_CURRENT) dbuff->p_i = p;
1002 if (adv_parent_flags & FR_DBUFF_ADV_PARENT_END) dbuff->end_i = p;
1003
1004 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, p);
1005}
1006
1007/** Set a new 'current' position in a dbuff or marker
1008 * @private
1009 *
1010 * @param[in,out] pos_p position pointer to modify.
1011 * @param[out] dbuff dbuff to use for constraints checks.
1012 * @param[in] p Position to set.
1013 * @return
1014 * - 0 not advanced (p before dbuff start) or after dbuff end.
1015 * - >0 the number of bytes the dbuff advanced by.
1016 * - <0 the number of bytes the dbuff retreated by.
1017 *
1018 */
1019static inline ssize_t _fr_dbuff_set(uint8_t **pos_p, fr_dbuff_t *dbuff, uint8_t const *p)
1020{
1021 uint8_t *c;
1022
1023 if (unlikely(p > dbuff->end)) return -(p - dbuff->end);
1024 if (unlikely(p < dbuff->start)) return 0;
1025
1026 c = *pos_p;
1027 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, p);
1028 *pos_p = UNCONST(uint8_t *, p);
1029
1030 return p - c;
1031}
1032
1033/** Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer, or a length value
1034 *
1035 * @param[in] _dst dbuff or marker to set the position for.
1036 * @param[in] _src Variable to glean new position from. Behaviour here
1037 * depends on the type of the variable.
1038 * - dbuff, the current position of the dbuff.
1039 * - marker, the current position of the marker.
1040 * - pointer, the position of the pointer.
1041 * - size_t, _dst->start + _src.
1042 * @return
1043 * - 0 not advanced.
1044 * - >0 the number of bytes the dbuff was advanced by.
1045 * - <0 the number of bytes required to complete the advancement
1046 */
1047#define fr_dbuff_set(_dst, _src) \
1048_fr_dbuff_set(\
1049 _fr_dbuff_current_ptr(_dst), fr_dbuff_ptr(_dst), \
1050 _Generic((_src), \
1051 fr_dbuff_t * : fr_dbuff_current((fr_dbuff_t const *)(_src)), \
1052 fr_dbuff_marker_t * : fr_dbuff_current((fr_dbuff_marker_t const *)(_src)), \
1053 uint8_t const * : (uint8_t const *)(_src), \
1054 uint8_t * : (uint8_t const *)(_src), \
1055 size_t : (fr_dbuff_start(_dst) + (uintptr_t)(_src)), \
1056 long : (fr_dbuff_start(_dst) + (uintptr_t)(_src)), \
1057 int : (fr_dbuff_start(_dst) + (uintptr_t)(_src)) \
1058 ) \
1059)
1060
1061/** Set the 'current' position in a dbuff or marker returning if _src is out of range
1062 *
1063 * @copydetails fr_dbuff_set
1064 */
1065#define FR_DBUFF_SET_RETURN(_dst, _src) FR_DBUFF_RETURN(fr_dbuff_set, _dst, _src)
1066
1067/** Set a new 'end' position in a dbuff or marker
1068 * @private
1069 *
1070 * @param[out] dbuff dbuff to use for constraints checks.
1071 * @param[in] p Position to set.
1072 */
1073static inline void _fr_dbuff_set_end(fr_dbuff_t *dbuff, uint8_t const *p)
1074{
1075#ifndef NDEBUG
1076 fr_assert(p >= dbuff->start);
1077 fr_assert(p <= dbuff->end);
1078#else
1079 if (!((p >= dbuff->start) && (p <= dbuff->end))) return;
1080#endif
1081
1082 dbuff->end = UNCONST(uint8_t *, p);
1083}
1084
1085/** Set a new 'end' position in a dbuff or marker
1086 *
1087 * @param[out] _dst dbuff to use for constraints checks.
1088 * @param[in] _end Position to set.
1089 */
1090#define fr_dbuff_set_end(_dst, _end) \
1091_fr_dbuff_set_end(\
1092 fr_dbuff_ptr(_dst), \
1093 _Generic((_end), \
1094 fr_dbuff_t * : fr_dbuff_current((fr_dbuff_t const *)(_end)), \
1095 fr_dbuff_marker_t * : fr_dbuff_current((fr_dbuff_marker_t const *)(_end)), \
1096 uint8_t const * : (uint8_t const *)(_end), \
1097 uint8_t * : (uint8_t const *)(_end) \
1098 ) \
1099)
1100
1101
1102/** Advance 'current' position in dbuff or marker by _len bytes
1103 *
1104 * @param[in] _dbuff_or_marker to advance.
1105 * @param[in] _len How much to advance dbuff by.
1106 * Must be a positive integer.
1107 * @return
1108 * - 0 not advanced.
1109 * - >0 the number of bytes the dbuff or marker was advanced by.
1110 * - <0 the number of bytes required to complete the advancement
1111 */
1112#define fr_dbuff_advance(_dbuff_or_marker, _len) \
1113 fr_dbuff_set(_dbuff_or_marker, \
1114 (fr_dbuff_current(_dbuff_or_marker) + \
1115 (_Generic((_len), \
1116 unsigned char : (size_t)(_len), \
1117 unsigned short : (size_t)(_len), \
1118 unsigned int : (size_t)(_len), \
1119 unsigned long : (size_t)(_len), \
1120 unsigned long long : (size_t)(_len), \
1121 int : (size_t)(_len) \
1122 ))))
1123
1124/** Advance the 'current' position in dbuff or marker by _len bytes returning if _len is out of range
1125 *
1126 * @copydetails fr_dbuff_advance
1127 */
1128#define FR_DBUFF_ADVANCE_RETURN(_dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_advance, _dbuff_or_marker, _len)
1129
1130/** Advance a dbuff or marker potentially extending it
1131 * @private
1132 *
1133 * @param[in,out] pos_p position pointer to modify.
1134 * @param[out] dbuff dbuff to use for constraints checks.
1135 * @param[in] len Number of bytes to advance by.
1136 * @return
1137 * - 0 not advanced, specified length would take us
1138 * past the end of the buffer, and we couldn't extend
1139 * by enough bytes.
1140 * - >0 the number of bytes the dbuff advanced by.
1141 * - <0 the number of bytes we'd need to complete the advance.
1142 *
1143 */
1144static inline ssize_t _fr_dbuff_advance_extend(uint8_t **pos_p, fr_dbuff_t *dbuff, size_t len)
1145{
1146 uint8_t *p = *pos_p + len;
1147
1148 if (p > dbuff->end) {
1149 size_t rel = p - dbuff->start; /* Get relative position to the start */
1150
1151 if (!dbuff->extend) {
1152 oos:
1153 return -((dbuff->start + rel) - dbuff->end);
1154 }
1155
1156 dbuff->extend(dbuff, p - dbuff->end); /* Try and extend by the number of bytes over */
1157 if ((dbuff->start + rel) > dbuff->end) goto oos;
1158
1159 *pos_p = dbuff->start + rel; /* Update pos_p */
1160 } else {
1161 *pos_p += len;
1162 }
1163
1164 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, *pos_p);
1165
1166 return len;
1167}
1168
1169/** Advance current'position in dbuff or marker by _len bytes (extending if necessary)
1170 *
1171 * @param[in] _dbuff_or_marker to advance.
1172 * @param[in] _len How much to advance dbuff by.
1173 * Must be a positive integer.
1174 * @return
1175 * - 0 not advanced.
1176 * - >0 the number of bytes the dbuff or marker was advanced by.
1177 * - <0 the number of bytes we'd need to complete the advance.
1178 */
1179#define fr_dbuff_advance_extend(_dbuff_or_marker, _len) \
1180 _fr_dbuff_advance_extend(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), \
1181 (_Generic((_len), \
1182 unsigned char : (size_t)(_len), \
1183 unsigned short : (size_t)(_len), \
1184 unsigned int : (size_t)(_len), \
1185 unsigned long : (size_t)(_len), \
1186 unsigned long long : (size_t)(_len), \
1187 int : (size_t)(_len) \
1188 )))
1189
1190#define FR_DBUFF_BIND_EXTEND_RETURN(_dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_advance_extend, _dbuff_or_marker, _len)
1191
1192/** Reset the 'current' position of the dbuff or marker to the 'start' of the buffer
1193 *
1194 */
1195#define fr_dbuff_set_to_start(_dbuff_or_marker) \
1196 fr_dbuff_set(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker))
1197
1198/** Reset the 'current' position of the dbuff or marker to the 'end' of the buffer
1199 *
1200 */
1201#define fr_dbuff_set_to_end(_dbuff_or_marker) \
1202 fr_dbuff_set(_dbuff_or_marker, fr_dbuff_end(_dbuff_or_marker))
1203/** @} */
1204
1205/** @name Marker management
1206 *
1207 * Markers serve two purposes:
1208 *
1209 * - Markers allow the caller to track content in a dbuff as the dbuff is extended.
1210 * If the caller referred to content using a pointer into the underlying buffer,
1211 * that pointer may be invalidated if the buffer were extended.
1212 *
1213 * - Markers prevent content being shifted out of the buffer during an extension.
1214 *
1215 * Most operations that can be performed on an #fr_dbuff_t can also be performed
1216 * on a #fr_dbuff_marker_t.
1217 *
1218 * It is recommended that markers be created against a stack-frame-local dbuff so
1219 * that they are automatically released when the framed is popped.
1220 *
1221 * @see fr_dbuff_marker_t
1222 *
1223 * @{
1224 */
1225
1226/** Initialises a new marker pointing to the 'current' position of the dbuff
1227 *
1228 * @param[out] m to initialise.
1229 * @param[in] dbuff to associate marker with.
1230 * @return The position the marker was set to.
1231 */
1233{
1234 *m = (fr_dbuff_marker_t){
1235 .next = dbuff->m, /* Link into the head */
1236 .p = dbuff->p, /* Set the current position in the dbuff */
1237 .parent = dbuff /* Record which dbuff this marker was associated with */
1238 };
1239 dbuff->m = m;
1240
1241 return dbuff->p;
1242}
1243
1244/** Releases the specified marker and any markers added before it
1245 *
1246 * Pointers should be released in the inverse order to allocation.
1247 *
1248 * @param[in] m to release.
1249 */
1251{
1252 m->parent->m = m->next;
1253
1254#ifndef NDEBUG
1255 memset(m, 0, sizeof(*m)); /* Use after release */
1256#endif
1257}
1258
1259/** Trims the linked list back to the specified pointer and return how many bytes marker was behind p
1260 *
1261 * Pointers should be released in the inverse order to allocation.
1262 *
1263 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1264 * also being removed from the list.
1265 *
1266 * @param[in] m to release.
1267 * @return
1268 * - 0 marker is ahead of p.
1269 * - >0 the number of bytes the marker is behind p.
1270 */
1272{
1273 size_t len = fr_dbuff_behind(m);
1275 return len;
1276}
1277
1278/** Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p
1279 *
1280 * Pointers should be released in the inverse order to allocation.
1281 *
1282 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1283 * also being removed from the list.
1284 *
1285 * @param[in] m to release.
1286 * @return
1287 * - 0 marker is ahead of p.
1288 * - >0 the number of bytes the marker is behind p.
1289 */
1291{
1292 size_t len = fr_dbuff_ahead(m);
1294 return len;
1295}
1296/** @} */
1297
1298/** @name "in" functions (copy data into a dbuff)
1299 * @{
1300 */
1301
1302/** Internal copy function to switch between memcpy and memmove - do not call directly
1303 *
1304 * @private
1305 *
1306 * @param[out] o_start Where to copy data to.
1307 * @param[in] o_end end of the output buffer.
1308 * @param[in] i_start Where to copy data from.
1309 * @param[in] i_end end of the source buffer.
1310 * @return
1311 * - 0 on sanity check error.
1312 * - >0 the number of bytes copied.
1313 */
1314static inline CC_HINT(always_inline) size_t _fr_dbuff_safecpy(uint8_t *o_start, uint8_t *o_end,
1315 uint8_t const *i_start, uint8_t const *i_end)
1316{
1317 ssize_t diff;
1318 size_t i_len = i_end - i_start;
1319
1320 if (unlikely((o_end < o_start) || (i_end < i_start))) return 0; /* sanity check */
1321
1322 diff = (o_end - o_start) - (i_len);
1323 if (diff < 0) return 0;
1324
1325 if ((i_start > o_end) || (i_end < o_start)) { /* no-overlap */
1326 memcpy(o_start, i_start, i_len);
1327 } else { /* overlap */
1328 memmove(o_start, i_start, i_len);
1329 }
1330
1331 return (i_len);
1332}
1333
1334/** Internal function - do not call directly
1335 *
1336 * @private
1337 */
1338static inline ssize_t _fr_dbuff_in_memcpy(uint8_t **pos_p, fr_dbuff_t *out,
1339 uint8_t const *in, size_t inlen)
1340{
1341 fr_assert(!out->is_const);
1342
1343 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, out, inlen);
1344
1345 return _fr_dbuff_set(pos_p, out, (*pos_p) + _fr_dbuff_safecpy((*pos_p), (*pos_p) + inlen, in, in + inlen)); /* Advance out */
1346}
1347
1348/** Internal function - do not call directly
1349 *
1350 * @private
1351 */
1352static inline ssize_t _fr_dbuff_in_memcpy_dbuff(uint8_t **pos_p, fr_dbuff_t *out,
1353 uint8_t * const *in_p, fr_dbuff_t const *in, size_t inlen)
1354{
1355 fr_dbuff_t *our_in;
1356 uint8_t **our_in_p;
1357 size_t ext_len;
1358
1359 memcpy(&our_in, &in, sizeof(our_in)); /* Stupid const issues caused by generics */
1360 memcpy(&our_in_p, &in_p, sizeof(our_in_p)); /* Stupid const issues caused by generics */
1361
1362 if (inlen == SIZE_MAX) {
1363 ext_len = _fr_dbuff_extend_lowat(NULL, our_in, fr_dbuff_end(our_in) - (*our_in_p), inlen);
1364 if (ext_len < inlen) inlen = ext_len;
1365 } else {
1366 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(our_in_p, our_in, inlen); /* Extend in or return */
1367 }
1368 return _fr_dbuff_in_memcpy(pos_p, out, *our_in_p, inlen); /* Copy _in to _out */
1369}
1370
1371/** Copy exactly _inlen bytes into a dbuff or marker
1372 *
1373 * If _in is a dbuff and _inlen is greater than the number of bytes available
1374 * in that dbuff, the copy operation will fail.
1375 *
1376 * @note _in will not be advanced. If this is required #fr_dbuff_move should be used.
1377 *
1378 * @param[in] _dbuff_or_marker to copy data to.
1379 * @param[in] _in data to copy in to the dbuff or marker.
1380 * @param[in] _inlen How much data we need to copy.
1381 * If _in is a `char *` or `dbuff *` and SIZE_MAX
1382 * is passed, then _inlen will be substituted
1383 * for the length of the data in the dbuff.
1384 * @return
1385 * - 0 no data copied.
1386 * - >0 the number of bytes copied to the dbuff.
1387 * - <0 the number of bytes we would have needed
1388 * to complete the copy operation.
1389 */
1390#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen) \
1391 _Generic((_in), \
1392 uint8_t * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1393 fr_dbuff_ptr(_dbuff_or_marker), \
1394 (uint8_t const *)(_in), \
1395 _inlen), \
1396 uint8_t const * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1397 fr_dbuff_ptr(_dbuff_or_marker), \
1398 (uint8_t const *)(_in), \
1399 _inlen), \
1400 char * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1401 fr_dbuff_ptr(_dbuff_or_marker), \
1402 (uint8_t const *)(_in), \
1403 (size_t)(_inlen) == SIZE_MAX ? strlen((char const *)(_in)) : (_inlen)), \
1404 char const * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1405 fr_dbuff_ptr(_dbuff_or_marker), \
1406 (uint8_t const *)(_in), \
1407 (size_t)(_inlen) == SIZE_MAX ? strlen((char const *)(_in)) : (_inlen)), \
1408 fr_dbuff_t * : _fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1409 fr_dbuff_ptr(_dbuff_or_marker), \
1410 &((fr_dbuff_t const *)(_in))->p, \
1411 ((fr_dbuff_t const *)(_in)), \
1412 _inlen), \
1413 fr_dbuff_marker_t * : _fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1414 fr_dbuff_ptr(_dbuff_or_marker), \
1415 &((fr_dbuff_marker_t const *)(_in))->p, \
1416 ((fr_dbuff_marker_t const *)(_in))->parent, _inlen) \
1417 )
1418
1419/** Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space
1420 * @copydetails fr_dbuff_in_memcpy
1421 */
1422#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen) FR_DBUFF_RETURN(fr_dbuff_in_memcpy, _dbuff_or_marker, _in, _inlen)
1423
1424/** Internal function - do not call directly
1425 *
1426 * @private
1427 */
1428static inline size_t _fr_dbuff_in_memcpy_partial(uint8_t **pos_p, fr_dbuff_t *out,
1429 uint8_t const *in, size_t inlen)
1430{
1431 size_t ext_len;
1432
1433 fr_assert(!out->is_const);
1434
1435 ext_len = _fr_dbuff_extend_lowat(NULL, out, fr_dbuff_end(out) - (*pos_p), inlen);
1436 if (ext_len < inlen) inlen = ext_len;
1437
1438 return _fr_dbuff_set(pos_p, out, (*pos_p) + _fr_dbuff_safecpy((*pos_p), (*pos_p) + inlen, in, in + inlen));
1439}
1440
1441/** Internal function - do not call directly
1442 *
1443 * @private
1444 */
1445static inline size_t _fr_dbuff_in_memcpy_partial_dbuff(uint8_t **pos_p, fr_dbuff_t *out,
1446 uint8_t * const *in_p, fr_dbuff_t const *in, size_t inlen)
1447{
1448 fr_dbuff_t *our_in = UNCONST(fr_dbuff_t *, in); /* Stupid const issues caused by generics */
1449 uint8_t **our_in_p = UNCONST(uint8_t **, in_p); /* Stupid const issues caused by generics */
1450 size_t ext_len;
1451
1452 ext_len = _fr_dbuff_extend_lowat(NULL, our_in, fr_dbuff_end(our_in) - (*our_in_p), inlen);
1453 if (ext_len < inlen) inlen = ext_len;
1454
1455 return _fr_dbuff_in_memcpy_partial(pos_p, out, (*our_in_p), inlen);
1456}
1457
1458/** Copy at most _inlen bytes into the dbuff
1459 *
1460 * Use this variant when writing data to a streaming buffer where
1461 * partial writes will be tracked.
1462 *
1463 * If _in is a #fr_dbuff_t and _inlen is greater than the number of bytes
1464 * available in that dbuff, the copy operation will truncated.
1465 *
1466 * @note _in will not be advanced. If this is required #fr_dbuff_move should be used.
1467 *
1468 * @param[in] _out to copy data to.
1469 * @param[in] _in Data to copy to dbuff.
1470 * @param[in] _inlen How much data we need to copy.
1471 * If _in is a char * or dbuff * and SIZE_MAX
1472 * is passed, then _inlen will be substituted
1473 * for the length of the buffer.
1474 * @return
1475 * - 0 no data copied.
1476 * - >0 the number of bytes copied to the dbuff.
1477 */
1478#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen) \
1479 _Generic((_in), \
1480 uint8_t * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen), \
1481 uint8_t const * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen), \
1482 char * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen == SIZE_MAX ? strlen((char const *)(_in)) : _inlen), \
1483 char const * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen == SIZE_MAX ? strlen((char const *)(_in)) : _inlen), \
1484 fr_dbuff_t * : _fr_dbuff_in_memcpy_partial_dbuff(_fr_dbuff_current_ptr(_out), fr_dbuff_ptr(_out), &((fr_dbuff_t const *)(_in))->p, ((fr_dbuff_t const *)(_in)), _inlen), \
1485 fr_dbuff_marker_t * : _fr_dbuff_in_memcpy_partial_dbuff(_fr_dbuff_current_ptr(_out), fr_dbuff_ptr(_out), &((fr_dbuff_marker_t const *)(_in))->p, ((fr_dbuff_marker_t const *)(_in))->parent, _inlen) \
1486 )
1487
1488/** Copy a partial byte sequence into a dbuff
1489 *
1490 * @copybrief fr_dbuff_in_memcpy_partial
1491 *
1492 * @param[in] _dbuff to copy byte sequence into.
1493 * @param[in] ... bytes to copy.
1494 */
1495#define fr_dbuff_in_bytes_partial(_dbuff, ...) \
1496 fr_dbuff_in_memcpy_partial(_dbuff, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1497
1498/** Copy a byte sequence into a dbuff or marker
1499 *
1500 * @copybrief fr_dbuff_in_memcpy
1501 *
1502 * @param[in] _dbuff_or_marker to copy byte sequence into.
1503 * @param[in] ... bytes to copy.
1504 */
1505#define fr_dbuff_in_bytes(_dbuff_or_marker, ...) \
1506 fr_dbuff_in_memcpy(_dbuff_or_marker, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1507
1508/** Copy a byte sequence into a dbuff or marker returning if there's insufficient space
1509 *
1510 * @copydetails fr_dbuff_in_bytes
1511 */
1512#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker, ...) \
1513 FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1514
1515/** Internal function - do not call directly
1516 *
1517 * @private
1518 */
1519static inline ssize_t _fr_dbuff_memset(uint8_t **pos_p, fr_dbuff_t *dbuff, uint8_t c, size_t inlen)
1520{
1521 fr_assert(!dbuff->is_const);
1522
1523 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, dbuff, inlen);
1524
1525 memset((*pos_p), c, inlen);
1526
1527 return _fr_dbuff_set(pos_p, dbuff, (*pos_p) + inlen);
1528}
1529
1530/** Set _inlen bytes of a dbuff or marker to _c
1531 *
1532 * @param[in] _dbuff_or_marker to copy data to.
1533 * Will be advanced by _inlen bytes.
1534 * @param[in] _c Value to set.
1535 * @param[in] _inlen How much data we need to copy.
1536 * @return
1537 * - 0 no data set.
1538 * - >0 the number of bytes set in the dbuff.
1539 * - <0 the number of bytes required.
1540 */
1541#define fr_dbuff_memset(_dbuff_or_marker, _c, _inlen) \
1542 _fr_dbuff_memset(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _c, _inlen)
1543
1544/** Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space
1545 *
1546 * @copydetails fr_dbuff_memset
1547 */
1548#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen) FR_DBUFF_RETURN(fr_dbuff_memset, _dbuff_or_marker, _c, _inlen)
1549
1550/** @cond */
1551/** Define integer decoding functions
1552 * @private
1553 */
1554#define FR_DBUFF_PARSE_INT_DEF(_type) \
1555static inline ssize_t _fr_dbuff_in_##_type(uint8_t **pos_p, fr_dbuff_t *out, _type##_t num) \
1556{ \
1557 fr_assert(!out->is_const); \
1558 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, out, sizeof(_type##_t)); \
1559 fr_nbo_from_##_type((*pos_p), num); \
1560 return _fr_dbuff_set(pos_p, out, (*pos_p) + sizeof(_type##_t)); \
1561}
1562FR_DBUFF_PARSE_INT_DEF(uint16)
1563FR_DBUFF_PARSE_INT_DEF(uint32)
1564FR_DBUFF_PARSE_INT_DEF(uint64)
1565FR_DBUFF_PARSE_INT_DEF(int16)
1566FR_DBUFF_PARSE_INT_DEF(int32)
1567FR_DBUFF_PARSE_INT_DEF(int64)
1568/** @endcond */
1569
1570/*
1571
1572 */
1573
1574/** Internal function - do not call directly
1575 *
1576 * The fr_dbuff_in_<type>() functions take rvalues, so to implement float and
1577 * double in terms of the same-sized integers, we need a layer that gives us an
1578 * lvalue whose address we can cast.
1579 *
1580 * @private
1581 */
1582static inline ssize_t _fr_dbuff_in_float(uint8_t **pos_p, fr_dbuff_t *out, float num)
1583{
1584 return _fr_dbuff_in_uint32(pos_p, out, *(uint32_t *)(&num));
1585}
1586
1587/** Internal function - do not call directly
1588 *
1589 * @copydetails _fr_dbuff_in_float
1590 *
1591 * @private
1592 */
1593static inline ssize_t _fr_dbuff_in_double(uint8_t **pos_p, fr_dbuff_t *out, double num)
1594{
1595 return _fr_dbuff_in_uint64(pos_p, out, *(uint64_t *)(&num));
1596}
1597
1598/** Copy data from a fixed sized C type into a dbuff or marker
1599 *
1600 * @param[out] _dbuff_or_marker to write to. Integer types will be automatically
1601 converted to big endian byte order.
1602 * @param[in] _in Value to copy.
1603 * @return
1604 * - <0 the number of bytes we would have needed to complete the conversion.
1605 * - >0 the number of bytes _dbuff_or_marker was advanced by.
1606 */
1607#define fr_dbuff_in(_dbuff_or_marker, _in) \
1608 _Generic((_in), \
1609 int8_t : fr_dbuff_in_bytes(_dbuff_or_marker, (int8_t)_in), \
1610 int16_t : _fr_dbuff_in_int16(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int16_t)_in), \
1611 int32_t : _fr_dbuff_in_int32(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int32_t)_in), \
1612 int64_t : _fr_dbuff_in_int64(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int64_t)_in), \
1613 uint8_t : fr_dbuff_in_bytes(_dbuff_or_marker, (uint8_t)_in), \
1614 uint16_t : _fr_dbuff_in_uint16(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint16_t)_in), \
1615 uint32_t : _fr_dbuff_in_uint32(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint32_t)_in), \
1616 uint64_t : _fr_dbuff_in_uint64(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint64_t)_in), \
1617 float : _fr_dbuff_in_float(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (float)_in), \
1618 double : _fr_dbuff_in_double(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (double)_in) \
1619 )
1620
1621/** Copy data from a fixed sized C type into a dbuff returning if there is insufficient space
1622 *
1623 * @copydetails fr_dbuff_in
1624 */
1625#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in) FR_DBUFF_RETURN(fr_dbuff_in, _dbuff_or_marker, _in)
1626
1627/** Internal function - do not call directly
1628 * @private
1629 */
1630static inline ssize_t _fr_dbuff_in_uint64v(uint8_t **pos_p, fr_dbuff_t *dbuff, uint64_t num)
1631{
1632 size_t ret;
1633 uint8_t swapped[sizeof(uint64_t)];
1634
1635 ret = ROUND_UP_DIV((size_t)fr_high_bit_pos(num | 0x08), 8);
1636#ifdef __COVERITY__
1637 if (ret > sizeof(uint64_t)) return -1;
1638#endif
1639 fr_nbo_from_uint64(swapped, num);
1640
1641 return _fr_dbuff_in_memcpy(pos_p, dbuff, (swapped + (sizeof(uint64_t) - ret)), ret);
1642}
1643
1644/** Copy an integer value into a dbuff or marker using our internal variable length encoding
1645 *
1646 * @param[out] _dbuff_or_marker to copy integer value to.
1647 * @param[in] _num to copy.
1648 * @return
1649 * - <0 the number of bytes we would have needed to encode the integer value.
1650 * - >0 the number of bytes used to represent the integer value.
1651 */
1652#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num) \
1653 _fr_dbuff_in_uint64v(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _num)
1654
1655/** Copy an integer value into a dbuff or marker using our internal variable length encoding returning if there is insufficient space
1656 *
1657 * @copydetails fr_dbuff_in_uint64v
1658 */
1659#define FR_DBUFF_IN_UINT64V(_dbuff_or_marker, _num) FR_DBUFF_RETURN(fr_dbuff_in_uint64v, _dbuff_or_marker, _num)
1660/** @} */
1661
1662/** @name "move" functions (copy data between dbuffs and markers)
1663 * @{
1664 */
1665/** Internal function - do not call directly
1666 * @private
1667 */
1668size_t _fr_dbuff_move_dbuff_to_dbuff(fr_dbuff_t *out, fr_dbuff_t *in, size_t len);
1669
1670/** Internal function - do not call directly
1671 * @private
1672 */
1673size_t _fr_dbuff_move_dbuff_to_dbuff_marker(fr_dbuff_marker_t *out, fr_dbuff_t *in, size_t len);
1674
1675/** Internal function - do not call directly
1676 * @private
1677 */
1678size_t _fr_dbuff_move_dbuff_marker_to_dbuff(fr_dbuff_t *out, fr_dbuff_marker_t *in, size_t len);
1679
1680/** Internal function - do not call directly
1681 * @private
1682 */
1683size_t _fr_dbuff_move_dbuff_marker_to_dbuff_marker(fr_dbuff_marker_t *out, fr_dbuff_marker_t *in, size_t len);
1684
1685/** Copy in as many bytes as possible from one dbuff or marker to another
1686 *
1687 * @warning Advances both _in and _out by _len, this may not be what you want.
1688 * If you only want _out to be advanced use fr_dbuff_in_memcpy(_out, _in, _len).
1689 * If you only want _in to be advanced use fr_dbuff_out_memcpy(_out, _in, _len).
1690 *
1691 * @param[in] _out to copy into.
1692 * @param[in] _in to copy from.
1693 * @param[in] _len The maximum length to copy.
1694 * @return Number of bytes to copy.
1695 */
1696#define fr_dbuff_move(_out, _in, _len) \
1697 _Generic((_out), \
1698 fr_dbuff_t * : \
1699 _Generic((_in), \
1700 fr_dbuff_t * : _fr_dbuff_move_dbuff_to_dbuff((fr_dbuff_t *)_out, \
1701 (fr_dbuff_t *)_in, \
1702 _len), \
1703 fr_dbuff_marker_t * : _fr_dbuff_move_dbuff_marker_to_dbuff((fr_dbuff_t *)_out, \
1704 (fr_dbuff_marker_t *)_in, \
1705 _len) \
1706 ), \
1707 fr_dbuff_marker_t * : \
1708 _Generic((_in), \
1709 fr_dbuff_t * : _fr_dbuff_move_dbuff_to_dbuff_marker((fr_dbuff_marker_t *)_out, \
1710 (fr_dbuff_t *)_in, \
1711 _len), \
1712 fr_dbuff_marker_t * : _fr_dbuff_move_dbuff_marker_to_dbuff_marker((fr_dbuff_marker_t *)_out, \
1713 (fr_dbuff_marker_t *)_in, \
1714 _len) \
1715 ) \
1716 )
1717/** @} */
1718
1719/** @name "out" functions (copy data out of a dbuff)
1720 * @{
1721 */
1722
1723/** Internal function - do not call directly
1724 *
1725 * @private
1726 */
1727static inline ssize_t _fr_dbuff_out_memcpy(uint8_t *out, uint8_t **pos_p, fr_dbuff_t *in, size_t outlen)
1728{
1729 size_t ext_len, to_copy, remaining;
1730
1731 for (remaining = outlen; remaining > 0; remaining -= to_copy) {
1732 to_copy = remaining;
1733 ext_len = _fr_dbuff_extend_lowat(NULL, in, fr_dbuff_end(in) - (*pos_p), 1);
1734 if (ext_len == 0) return -remaining;
1735 if (ext_len < to_copy) to_copy = ext_len;
1736 out += _fr_dbuff_set(pos_p, in,
1737 (*pos_p) + _fr_dbuff_safecpy(out, out + to_copy, (*pos_p), (*pos_p) + to_copy));
1738 }
1739
1740 return outlen;
1741}
1742/** Internal function - do not call directly
1743 *
1744 * @private
1745 */
1746static inline ssize_t _fr_dbuff_out_memcpy_dbuff(uint8_t **out_p, fr_dbuff_t *out, uint8_t **pos_p, fr_dbuff_t *in, size_t outlen)
1747{
1748 if (outlen == SIZE_MAX) outlen = _fr_dbuff_extend_lowat(NULL, out, fr_dbuff_end(out) - (*out_p), outlen);
1749
1750 return _fr_dbuff_out_memcpy((*out_p), pos_p, in, outlen);
1751}
1752
1753/** Copy exactly _outlen bytes from the dbuff
1754 *
1755 * If _out is a dbuff and _outlen is greater than the number of bytes
1756 * available in that dbuff, the copy operation will fail.
1757 *
1758 * @note _out will not be advanced. If this is required #fr_dbuff_move should be used.
1759 *
1760 * @param[in] _out either a buffer, or another dbuff/marker to copy data to.
1761 * @param[in] _dbuff_or_marker to copy data from.
1762 * @param[in] _outlen How much data we need to copy.
1763 * If _out is `fr_dbuff_t *` and SIZE_MAX
1764 * is passed, then _inlen will be substituted
1765 * for the length of the buffer.
1766 * @return
1767 * - 0 no data copied.
1768 * - >0 the number of bytes copied.
1769 * - <0 the number of bytes we would have needed
1770 * to complete the copy operation.
1771 */
1772#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen) \
1773 _Generic((_out), \
1774 uint8_t * : _fr_dbuff_out_memcpy((uint8_t *)(_out), \
1775 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1776 fr_dbuff_ptr(_dbuff_or_marker), \
1777 _outlen), \
1778 fr_dbuff_t * : _fr_dbuff_out_memcpy_dbuff(_fr_dbuff_current_ptr((fr_dbuff_t *)_out), \
1779 fr_dbuff_ptr((fr_dbuff_t *)(_out)), \
1780 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1781 fr_dbuff_ptr(_dbuff_or_marker), _outlen), \
1782 fr_dbuff_marker_t * : _fr_dbuff_out_memcpy_dbuff(_fr_dbuff_current_ptr((fr_dbuff_marker_t *)_out), \
1783 fr_dbuff_ptr((fr_dbuff_marker_t *)(_out)), \
1784 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1785 fr_dbuff_ptr(_dbuff_or_marker), _outlen) \
1786 )
1787
1788/** Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff
1789 *
1790 * @copydetails fr_dbuff_out_memcpy
1791 */
1792#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen) FR_DBUFF_RETURN(fr_dbuff_out_memcpy, _out, _dbuff_or_marker, _outlen)
1793
1794/** @cond */
1795/** Define integer encoding functions
1796 * @private
1797 */
1798#define FR_DBUFF_OUT_DEF(_type) \
1799static inline ssize_t _fr_dbuff_out_##_type(_type##_t *out, uint8_t **pos_p, fr_dbuff_t *in) \
1800{ \
1801 fr_assert(out); \
1802 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(in, sizeof(_type##_t)); \
1803 *out = fr_nbo_to_##_type((*pos_p)); \
1804 return _fr_dbuff_set(pos_p, in, (*pos_p) + sizeof(_type##_t)); \
1805}
1806
1807FR_DBUFF_OUT_DEF(uint16)
1808FR_DBUFF_OUT_DEF(uint32)
1809FR_DBUFF_OUT_DEF(uint64)
1810FR_DBUFF_OUT_DEF(int16)
1811FR_DBUFF_OUT_DEF(int32)
1812FR_DBUFF_OUT_DEF(int64)
1813
1814#define FR_DBUFF_OUT_DEF_NO_SWAP(_type) \
1815static inline ssize_t _fr_dbuff_out_##_type(_type##_t *out, uint8_t **pos_p, fr_dbuff_t *in) \
1816{ \
1817 fr_assert(out); \
1818 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(in, sizeof(_type##_t)); \
1819 *out = **pos_p; \
1820 return _fr_dbuff_set(pos_p, in, (*pos_p) + sizeof(_type##_t)); \
1821}
1822
1823FR_DBUFF_OUT_DEF_NO_SWAP(uint8)
1824FR_DBUFF_OUT_DEF_NO_SWAP(int8)
1825/** @endcond */
1826
1827/** Copy data from a dbuff or marker to a fixed sized C type
1828 *
1829 * @param[out] _out Where to write the data. If out is an integer type
1830 * a byteswap will be performed if native endianness
1831 * is not big endian.
1832 * @param[in] _dbuff_or_marker to copy data from. Will be advanced by the number
1833 * of bytes consumed, i.e. if out is a uin16_t *,
1834 * _dbuff_or_marker will be advanced by two bytes.
1835 * @return
1836 * - <0 the number of bytes we would have needed to complete the conversion.
1837 * - >0 the number of bytes _in was advanced by.
1838 */
1839#define fr_dbuff_out(_out, _dbuff_or_marker) \
1840 _Generic((_out), \
1841 uint8_t * : _fr_dbuff_out_uint8((uint8_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1842 uint16_t * : _fr_dbuff_out_uint16((uint16_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1843 uint32_t * : _fr_dbuff_out_uint32((uint32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1844 uint64_t * : _fr_dbuff_out_uint64((uint64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1845 int8_t * : _fr_dbuff_out_int8((int8_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1846 int16_t * : _fr_dbuff_out_int16((int16_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1847 int32_t * : _fr_dbuff_out_int32((int32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1848 int64_t * : _fr_dbuff_out_int64((int64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1849 float * : _fr_dbuff_out_uint32((uint32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1850 double * : _fr_dbuff_out_uint64((uint64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)) \
1851 )
1852
1853/** Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data
1854 *
1855 * @copydetails fr_dbuff_out
1856 */
1857#ifndef STATIC_ANALYZER
1858#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker) FR_DBUFF_RETURN(fr_dbuff_out, _out, _dbuff_or_marker)
1859#else
1860#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker) do { *_out = 0; FR_DBUFF_RETURN(fr_dbuff_out, _out, _dbuff_or_marker); } while (0)
1861#endif
1862
1863/** Internal function - do not call directly
1864 * @private
1865 */
1866static inline ssize_t _fr_dbuff_out_uint64v(uint64_t *num, uint8_t **pos_p, fr_dbuff_t *dbuff, size_t length)
1867{
1868 ssize_t slen;
1869
1870 fr_assert(length > 0 && length <= sizeof(uint64_t));
1871
1872 *num = 0;
1873 slen = _fr_dbuff_out_memcpy(((uint8_t *) num) + (8 - length), pos_p, dbuff, length);
1874 if (slen <= 0) return slen;
1875
1876 *num = fr_nbo_to_uint64((uint8_t const *)num);
1877 return length;
1878}
1879
1880/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1881 * @param[in] _num points to a uint64_t to store the integer in
1882 * @param[in] _dbuff_or_marker data to copy bytes from
1883 * @param[in] _len number of bytes to read (must be positive and less than eight)
1884 *
1885 * @return
1886 * - 0 no data read.
1887 * - >0 the number of bytes read.
1888 * - <0 the number of bytes we would have needed
1889 * to complete the read operation.
1890 */
1891#define fr_dbuff_out_uint64v(_num, _dbuff_or_marker, _len) \
1892 _fr_dbuff_out_uint64v(_num, _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _len)
1893
1894/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1895 *
1896 * @copydetails fr_dbuff_out_uint64v
1897 */
1898#define FR_DBUFF_OUT_UINT64V_RETURN(_num, _dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_out_uint64v, _num, _dbuff_or_marker, _len)
1899
1900/** Internal function - do not call directly
1901 * @private
1902 */
1903static inline ssize_t _fr_dbuff_out_int64v(int64_t *num, uint8_t **pos_p, fr_dbuff_t *dbuff, size_t length)
1904{
1905 ssize_t slen;
1906 uint8_t msb = **pos_p;
1907
1908 fr_assert(length > 0 && length <= sizeof(uint64_t));
1909
1910 *num = 0;
1911 slen = _fr_dbuff_out_memcpy(((uint8_t *) num) + (8 - length), pos_p, dbuff, length);
1912 if (slen <= 0) return slen;
1913
1914 if (msb & 0x80) memset(((uint8_t *)num), 0xff, sizeof(*num) - length);
1915 *num = fr_nbo_to_int64((uint8_t const *)num);
1916
1917 return length;
1918}
1919
1920/** Read bytes from a dbuff or marker and interpret them as a network order signed integer
1921 * @param[in] _num points to an int64_t to store the integer in
1922 * @param[in] _dbuff_or_marker data to copy bytes from
1923 * @param[in] _len number of bytes to read (must be positive and less than eight)
1924 *
1925 * @return
1926 * - 0 no data read.
1927 * - >0 the number of bytes read.
1928 * - <0 the number of bytes we would have needed
1929 * to complete the read operation.
1930 */
1931#define fr_dbuff_out_int64v(_num, _dbuff_or_marker, _len) \
1932 _fr_dbuff_out_int64v(_num, _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _len)
1933
1934/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1935 *
1936 * @copydetails fr_dbuff_out_int64v
1937 */
1938#define FR_DBUFF_OUT_INT64V_RETURN(_num, _dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_out_int64v, _num, _dbuff_or_marker, _len)
1939
1940/** @} */
1941#ifdef __cplusplus
1942}
1943#endif
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define DIAG_ON(_x)
Definition build.h:535
#define RCSIDH(h, id)
Definition build.h:561
#define unlikely(_x)
Definition build.h:455
#define DIAG_OFF(_x)
Definition build.h:534
struct fr_dbuff_s fr_dbuff_t
A dbuff.
Definition dbuff.h:65
#define fr_dbuff_behind(_dbuff_or_marker)
How many bytes the dbuff or marker is behind its parent.
Definition dbuff.h:829
#define FR_DBUFF_FLAG_EXTENDED
Flag indicating that during the last extend call the dbuff was extended.
Definition dbuff.h:619
fr_dbuff_uctx_talloc_t tctx
Thread local tctx.
Definition dbuff.h:575
int fr_dbuff_reset_talloc(fr_dbuff_t *dbuff)
Reset a talloced buffer to its initial length, clearing any data stored.
Definition dbuff.c:332
static void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
Free the talloc buffer associated with a dbuff.
Definition dbuff.h:486
static fr_dbuff_t * fr_dbuff_init_fd(fr_dbuff_t *dbuff, fr_dbuff_uctx_fd_t *fctx, uint8_t *buff, size_t len, int fd, size_t max)
Initialise a special dbuff which automatically reads in more data as the buffer is exhausted.
Definition dbuff.h:518
static int _dbuff_thread_local_free(void *dbtl)
Definition dbuff.h:578
static size_t fr_dbuff_marker_release_behind(fr_dbuff_marker_t *m)
Trims the linked list back to the specified pointer and return how many bytes marker was behind p.
Definition dbuff.h:1271
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition dbuff.h:81
fr_dbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
Definition dbuff.h:623
@ FR_DBUFF_NOT_EXTENDABLE
dbuff cannot be extended
Definition dbuff.h:626
@ FR_DBUFF_EXTENDED
dbuff was extended in the last extend call but cannot be extended again
Definition dbuff.h:638
@ FR_DBUFF_EXTENDABLE
dbuff can be extended
Definition dbuff.h:630
@ FR_DBUFF_EXTENDABLE_EXTENDED
dbuff was extended in the last extend call and may be extended again
Definition dbuff.h:634
size_t _fr_dbuff_extend_talloc(fr_dbuff_t *dbuff, size_t extension)
Reallocate the current buffer.
Definition dbuff.c:235
#define fr_dbuff_end(_dbuff_or_marker)
Return the current 'end' position of a dbuff or marker.
Definition dbuff.h:981
#define FR_DBUFF_ADV_PARENT_CURRENT
Advance current position of parent.
Definition dbuff.h:124
int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len)
Trim a talloced dbuff to the minimum length required to represent the contained string.
Definition dbuff.c:297
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
Definition dbuff.h:1232
#define FR_DBUFF_FLAG_EXTENDABLE
Flag indicating a dbuff is extendable.
Definition dbuff.h:615
size_t _fr_dbuff_extend_fd(fr_dbuff_t *dbuff, size_t extension)
Refresh the buffer with more data from the file.
Definition dbuff.c:175
fr_dbuff_t dbuff
Thread local dbuff.
Definition dbuff.h:574
void fr_dbuff_update(fr_dbuff_t *dbuff, uint8_t *new_buff, size_t new_len)
Update all markers and pointers in the set of dbuffs to point to new_buff.
Definition dbuff.c:79
static void fr_dbuff_marker_release(fr_dbuff_marker_t *m)
Releases the specified marker and any markers added before it.
Definition dbuff.h:1250
#define fr_dbuff_ahead(_dbuff_or_marker)
How many bytes the dbuff or marker is ahead of its parent.
Definition dbuff.h:839
static size_t fr_dbuff_marker_release_ahead(fr_dbuff_marker_t *m)
Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p.
Definition dbuff.h:1290
#define FR_DBUFF_ADV_PARENT_END
Advance end pointer of parent.
Definition dbuff.h:126
static fr_dbuff_t * fr_dbuff_init_talloc(TALLOC_CTX *ctx, fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx, size_t init, size_t max)
Initialise a special dbuff which automatically extends as additional data is written.
Definition dbuff.h:444
size_t(* fr_dbuff_extend_t)(fr_dbuff_t *dbuff, size_t req_extension)
dbuff extension callback
Definition dbuff.h:108
size_t fr_dbuff_shift(fr_dbuff_t *dbuff, size_t shift)
Shift the contents of the dbuff, returning the number of bytes we managed to shift.
Definition dbuff.c:116
Structure to encapsulate a thread local dbuff information.
Definition dbuff.h:573
static fr_slen_t in
Definition dict.h:904
talloc_free(hp)
#define ROUND_UP_DIV(_x, _y)
Get the ceiling value of integer division.
Definition math.h:211
static uint8_t fr_high_bit_pos(uint64_t num)
Find the highest order high bit in an unsigned 64 bit integer.
Definition math.h:94
uint8_t * p
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
static uint64_t fr_nbo_to_uint64(uint8_t const data[static sizeof(uint64_t)])
Read an unsigned 64bit integer from wire format (big endian)
Definition nbo.h:177
static void fr_nbo_from_uint64(uint8_t out[static sizeof(uint64_t)], uint64_t num)
Write out an unsigned 64bit integer in wire format (big endian)
Definition nbo.h:72
#define fr_nbo_to_int64(_x)
Definition nbo.h:187
#define fr_assert(_expr)
Definition rad_assert.h:37
static char buff[sizeof("18446744073709551615")+3]
Definition size_tests.c:37
init
Enter the EAP-IDENTITY state.
static fr_slen_t parent
Definition pair.h:860
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1062
static fr_sbuff_err_t char ** out
Definition value.h:1062
static fr_sbuff_err_t char size_t * len
Definition value.h:1062
int nonnull(2, 5))