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: 26d553848e66e0670393df601d8c644c8d83a917 $")
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/** Initialise a dbuff for encoding, and define the first byte of the output buffer
411 *
412 * Callers which read the output buffer after a failed encode would otherwise read
413 * uninitialised memory. A zero length buffer has no first byte to define, so the write
414 * is skipped rather than running off the end of the buffer.
415 *
416 * @param[out] _out dbuff to initialise.
417 * @param[in] _start Start of the buffer to write to.
418 * @param[in] _len_or_end Either an end pointer or the length of the buffer.
419 */
420#define FR_DBUFF_INIT(_out, _start, _len_or_end) do { \
421 fr_dbuff_init(_out, _start, _len_or_end); \
422 } while (0)
423
424size_t _fr_dbuff_extend_talloc(fr_dbuff_t *dbuff, size_t extension);
425
426int fr_dbuff_trim_talloc(fr_dbuff_t *dbuff, size_t len);
427
429
430/** Talloc extension structure use by #fr_dbuff_init_talloc
431 * @private
432 *
433 * Holds the data necessary for creating dynamically
434 * extensible buffers.
435 */
436typedef struct {
437 TALLOC_CTX *ctx; //!< Context to alloc new buffers in.
438 size_t init; //!< How much to allocate initially.
439 size_t max; //!< Maximum size of the buffer.
440} fr_dbuff_uctx_talloc_t;
441
442/** Initialise a special dbuff which automatically extends as additional data is written
443 *
444 * @param[in] ctx to allocate buffer in.
445 * @param[out] dbuff to initialise.
446 * @param[out] tctx to initialise. Must have a lifetime >= to the dbuff.
447 * @param[in] init The length of the initial buffer.
448 * @param[in] max The maximum length of the buffer.
449 * @return
450 * - The passed dbuff on success.
451 * - NULL on failure.
452 */
453static inline fr_dbuff_t *fr_dbuff_init_talloc(TALLOC_CTX *ctx,
454 fr_dbuff_t *dbuff, fr_dbuff_uctx_talloc_t *tctx,
455 size_t init, size_t max)
456{
457 uint8_t *buff;
458
459 *tctx = (fr_dbuff_uctx_talloc_t){
460 .ctx = ctx,
461 .init = init,
462 .max = max
463 };
464
465 /*
466 * Allocate the initial buffer
467 *
468 * We always allocate a buffer so we don't trigger ubsan
469 * errors by performing arithmetic on NULL pointers.
470 *
471 * Note that unlike sbuffs, we don't need space for a trailing '\0'.
472 */
473 buff = talloc_zero_array(ctx, uint8_t, init);
474 if (!buff) {
475 fr_strerror_printf("Failed allocating buffer of %zu bytes", init);
476 memset(dbuff, 0, sizeof(*dbuff)); /* clang scan */
477 return NULL;
478 }
479
480 *dbuff = (fr_dbuff_t){
481 .buff = buff,
482 .start = buff,
483 .p = buff,
484 .end = buff + init,
485 .extend = _fr_dbuff_extend_talloc,
486 .uctx = tctx
487 };
488
489 return dbuff;
490}
491
492/** Free the talloc buffer associated with a dbuff
493 *
494 */
495static inline void fr_dbuff_free_talloc(fr_dbuff_t *dbuff)
496{
497 TALLOC_FREE(dbuff->buff);
498}
499
500size_t _fr_dbuff_extend_fd(fr_dbuff_t *dbuff, size_t extension);
501
502/** File sbuff extension structure use by #fr_dbuff_init_fd
503 * @private
504 *
505 * Holds the data necessary for creating dynamically
506 * extensible file buffers.
507 */
508typedef struct {
509 int fd; //!< fd of file we're reading from.
510 uint8_t *buff_end; //!< The true end of the buffer.
511 size_t max; //!< Maximum number of bytes to read.
512} fr_dbuff_uctx_fd_t;
513
514
515/** Initialise a special dbuff which automatically reads in more data as the buffer is exhausted
516 *
517 * @param[out] dbuff to initialise.
518 * @param[out] fctx to initialise. Must have a lifetime >= to the dbuff.
519 * @param[in] buff Temporary buffer to use for storing file contents.
520 * @param[in] len Length of the temporary buffer.
521 * @param[in] fd descriptor of an open file to read from.
522 * @param[in] max The maximum length of data to read from the file.
523 * @return
524 * - The passed dbuff on success.
525 * - NULL on failure.
526 */
527static inline fr_dbuff_t *fr_dbuff_init_fd(fr_dbuff_t *dbuff, fr_dbuff_uctx_fd_t *fctx,
528 uint8_t *buff, size_t len, int fd, size_t max)
529{
530 *fctx = (fr_dbuff_uctx_fd_t){
531 .fd = fd,
532 .max = max,
533 .buff_end = buff + len //!< Store the real end
534 };
535
536 *dbuff = (fr_dbuff_t){
537 .buff = buff,
538 .start = buff,
539 .p = buff,
540 .end = buff, //!< Starts with 0 bytes available
541 .extend = _fr_dbuff_extend_fd,
542 .uctx = fctx
543 };
544
545 return dbuff;
546}
547
548/** Creates a compound literal to pass into functions which accept a dbuff
549 *
550 * @note The return value of the function should be used to determine how much
551 * data was written to the buffer.
552 *
553 * @param[in] _start of the buffer.
554 * @param[in] _len_or_end Length of the buffer or the end pointer.
555 */
556#define FR_DBUFF_TMP(_start, _len_or_end) \
557(fr_dbuff_t){ \
558 .buff_i = (uint8_t const *)(_start), \
559 .start_i = (uint8_t const *)(_start), \
560 .end_i = _Generic((_len_or_end), \
561 size_t : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
562 long : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
563 int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
564 unsigned int : (uint8_t const *)(_start) + (size_t)(_len_or_end), \
565 uint8_t * : (uint8_t const *)(_len_or_end), \
566 uint8_t const * : (uint8_t const *)(_len_or_end), \
567 char * : (uint8_t const *)(_len_or_end), \
568 char const * : (uint8_t const *)(_len_or_end) \
569 ), \
570 .p_i = _start, \
571 .is_const = _Generic((_start), \
572 uint8_t * : false, \
573 uint8_t const * : true, \
574 char * : false, \
575 char const * : true \
576 ) \
577}
578
579/** Structure to encapsulate a thread local dbuff information
580 *
581 */
582typedef struct {
583 fr_dbuff_t dbuff; //!< Thread local dbuff.
584 fr_dbuff_uctx_talloc_t tctx; //!< Thread local tctx.
586
587static inline int _dbuff_thread_local_free(void *dbtl)
588{
589 return talloc_free(dbtl);
590}
591
592/** Create a function local and thread local extensible dbuff
593 *
594 * @param[out] _out Where to write a pointer to the thread local dbuff
595 * @param[in] _init Initial size for the dbuff buffer.
596 * @param[in] _max Maximum size of the dbuff buffer.
597 */
598#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max) \
599do { \
600 static _Thread_local fr_dbuff_thread_local_t *_dbuff_t_local; \
601 if (!_dbuff_t_local) { \
602 fr_dbuff_thread_local_t *dbtl = talloc_zero(NULL, fr_dbuff_thread_local_t); \
603 fr_dbuff_init_talloc(dbtl, &dbtl->dbuff, &dbtl->tctx, _init, _max); \
604 fr_atexit_thread_local(_dbuff_t_local, _dbuff_thread_local_free, dbtl); \
605 *(_out) = &_dbuff_t_local->dbuff; \
606 } else { \
607 fr_dbuff_reset_talloc(&_dbuff_t_local->dbuff); \
608 *(_out) = &_dbuff_t_local->dbuff; \
609 } \
610} while (0)
611/** @} */
612
613/** @name Extension requests
614 *
615 * These functions/macros may be used to request that the underlying buffer is
616 * either extended to accommodate more data, or that data is shifted out of the
617 * buffer, and that the buffer is refilled.
618 *
619 * @{
620 */
621
622/** Flag indicating a dbuff is extendable
623 */
624#define FR_DBUFF_FLAG_EXTENDABLE 0x01
625
626/** Flag indicating that during the last extend call the dbuff was extended
627 */
628#define FR_DBUFF_FLAG_EXTENDED 0x02
629
630/** Whether the buffer is currently extendable and whether it was extended
631 */
632typedef enum {
633 /** dbuff cannot be extended
634 */
636
637 /** dbuff can be extended
638 */
640
641 /** dbuff was extended in the last extend call and may be extended again
642 */
644
645 /** dbuff was extended in the last extend call but cannot be extended again
646 */
649
650/** Check if a dbuff can be extended again
651 */
652#define fr_dbuff_is_extendable(_status) ((_status) & FR_DBUFF_FLAG_EXTENDABLE)
653
654/** Check if the dbuff was extended during the last extend call
655 */
656#define fr_dbuff_was_extended(_status) ((_status) & FR_DBUFF_FLAG_EXTENDED)
657
658/** Internal function - do not call directly
659 * @private
660 */
661static inline size_t _fr_dbuff_extend_lowat(fr_dbuff_extend_status_t *status, fr_dbuff_t *in,
662 size_t remaining, size_t lowat)
663{
664 size_t extended = 0;
665
666 /*
667 * A 'const' dbuff cannot be extended. A dbuff without
668 * an 'extend' function cannot be extended.
669 *
670 * Return how many bytes remain in the buffer.
671 */
672 if (in->is_const || !in->extend || (status && (*status = FR_DBUFF_NOT_EXTENDABLE))) {
673 not_extendable:
674 if (status) *status = FR_DBUFF_NOT_EXTENDABLE;
675 return remaining;
676 }
677
678 if (remaining >= lowat) {
679 if (status) *status = FR_DBUFF_EXTENDABLE;
680 return remaining;
681 }
682
683 /*
684 * If we can't extend the buffer, return that it's not extendible.
685 */
686 extended = in->extend(in, lowat - remaining);
687 if (!extended) goto not_extendable;
688
689 if (status) *status = FR_DBUFF_EXTENDABLE_EXTENDED;
690
691 return remaining + extended;
692}
693
694/** Extend if we're below _lowat
695 *
696 * @param[out] _status May be NULL. If fr_dbuff_extend_lowat is used
697 * in a copy loop, the caller should pass a pointer
698 * to a #fr_dbuff_extend_status_t. The initial
699 * value of the #fr_dbuff_extend_status_t variable
700 * should be #FR_DBUFF_EXTENDABLE, and will be updated
701 * to indicate whether the dbuff is extensible,
702 * whether it was extended, and whether it may be
703 * extended again. This information
704 * is used the loop condition to prevent spurious
705 * extension calls.
706 * @param[in] _dbuff_or_marker to extend.
707 * @param[in] _lowat If bytes remaining are below the amount, extend.
708 * @return
709 * - 0 if there are no bytes left in the buffer and we couldn't extend.
710 * - >0 the number of bytes in the buffer after extending.
711 */
712#define fr_dbuff_extend_lowat(_status, _dbuff_or_marker, _lowat) \
713 _fr_dbuff_extend_lowat(_status, \
714 fr_dbuff_ptr(_dbuff_or_marker), \
715 fr_dbuff_remaining(_dbuff_or_marker), _lowat)
716
717/** Extend if we're below _lowat and return if we can't extend above _lowat
718 *
719 * @param[in] _dbuff_or_marker to extend.
720 * @param[in] _lowat If bytes remaining are below the amount, extend.
721 * @return
722 * - 0 if there are no bytes left in the buffer and we couldn't extend.
723 * - >0 the number of bytes in the buffer after extending.
724 */
725#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat) \
726do { \
727 size_t _remaining = fr_dbuff_extend_lowat(NULL, _dbuff_or_marker, _lowat); \
728 if (_remaining < _lowat) return -(_lowat - _remaining); \
729} while (0)
730
731/** @cond */
732/** Extend if we're below _lowat and return if we can't extend above _lowat
733 *
734 * @private
735 *
736 * @param[in,out] _pos_p the position pointer to use.
737 * @param[in] _dbuff_or_marker to extend.
738 * @param[in] _lowat The minimum amount the dbuff should be extended by.
739 * @return The number of bytes we would need to satisfy _lowat as a negative integer.
740 */
741#define _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(_pos_p, _dbuff_or_marker, _lowat) \
742do { \
743 size_t _remaining = _fr_dbuff_extend_lowat(NULL, \
744 fr_dbuff_ptr(_dbuff_or_marker), \
745 fr_dbuff_end(_dbuff_or_marker) - (*(_pos_p)), _lowat); \
746 if (_remaining < _lowat) return -(_lowat - _remaining); \
747} while (0)
748/** @endcond */
749
750/** Extend if no space remains
751 *
752 * @param[in] _dbuff to extend.
753 * @return
754 * - 0 if there are no bytes left in the buffer and we couldn't extend.
755 * - >0 the number of bytes in the buffer after extending.
756 */
757#define fr_dbuff_extend(_dbuff) fr_dbuff_extend_lowat(NULL, _dbuff, 1)
758/** @} */
759
760/** @name Extension callback helpers
761 *
762 * These public functions are intended to be called by extension callbacks
763 * to fixup dbuffs after the underlying buffer or its contents has been altered.
764 * @{
765 */
766void fr_dbuff_update(fr_dbuff_t *dbuff, uint8_t *new_buff, size_t new_len);
767
768size_t fr_dbuff_shift(fr_dbuff_t *dbuff, size_t shift);
769/** @} */
770
771/** @name Length checks
772 *
773 * These macros return the amount of data used/remaining relative to the dbuff
774 * or marker's 'start', 'current', and 'end' pointers.
775 *
776 * In the majority of cases these macros should not be used and the extension
777 * request functions should be used instead. The only exception to this is if
778 * the caller is certain the #fr_dbuff_t is not extensible.
779 *
780 * @{
781 */
782/** Return the number of bytes remaining between the dbuff or marker and the end of the buffer
783 *
784 * @note Do not use this in functions that may be used for stream decoding
785 * unless you're sure you know what you're doing.
786 * The value return does not reflect the number of bytes that may
787 * be potentially read from the stream, only the number of bytes
788 * until the end of the current chunk.
789 *
790 * @param[in] _dbuff_or_marker to return the number of bytes remaining for.
791 * @return
792 * - >0 the number of bytes remaining before we reach the end of the buffer.
793 * - -0 we're at the end of the buffer.
794 */
795#define fr_dbuff_remaining(_dbuff_or_marker) \
796 ((size_t)(fr_dbuff_end(_dbuff_or_marker) < fr_dbuff_current(_dbuff_or_marker) ? \
797 0 : (fr_dbuff_end(_dbuff_or_marker) - fr_dbuff_current(_dbuff_or_marker))))
798
799/** Check if _len bytes are available in the dbuff and if not return the number of bytes we'd need
800 *
801 * @note Do not use this in functions that may be used for stream decoding
802 * unless you're sure you know what you're doing.
803 * The value return does not reflect the number of bytes that may
804 * be potentially read from the stream, only the number of bytes
805 * until the end of the current chunk.
806 *
807 * @param[in] _dbuff_or_marker to return the number of bytes remaining for.
808 * @param[in] _len Minimum remaining bytes.
809 * @return
810 * - >0 the number of bytes remaining before we reach the end of the buffer.
811 * - -0 we're at the end of the buffer.
812 */
813#define FR_DBUFF_REMAINING_RETURN(_dbuff_or_marker, _len) \
814 if ((_len) > fr_dbuff_remaining(_dbuff_or_marker)) return -((_len) - fr_dbuff_remaining(_dbuff_or_marker))
815
816/** Return the number of bytes remaining between the start of the dbuff or marker and the current position
817 *
818 */
819#define fr_dbuff_used(_dbuff_or_marker) \
820 ((size_t)(fr_dbuff_start(_dbuff_or_marker) > fr_dbuff_current(_dbuff_or_marker) ? \
821 0 : (fr_dbuff_current(_dbuff_or_marker) - fr_dbuff_start(_dbuff_or_marker))))
822
823/** The length of the underlying buffer
824 *
825 * @param[in] _dbuff_or_marker to return the length of.
826 * @return The length of the underlying buffer.
827 */
828#define fr_dbuff_len(_dbuff_or_marker) \
829 ((size_t)(fr_dbuff_end(_dbuff_or_marker) - fr_dbuff_start(_dbuff_or_marker)))
830
831/** How many bytes the dbuff or marker is behind its parent
832 *
833 * @param[in] _dbuff_or_marker
834 * @return
835 * - 0 the dbuff or marker is ahead of its parent.
836 * - >0 the number of bytes the marker is behind its parent.
837 */
838#define fr_dbuff_behind(_dbuff_or_marker) \
839 (fr_dbuff_current(_dbuff_or_marker) > fr_dbuff_current((_dbuff_or_marker)->parent) ? \
840 0 : fr_dbuff_current((_dbuff_or_marker)->parent) - fr_dbuff_current(_dbuff_or_marker))
841
842/** How many bytes the dbuff or marker is ahead of its parent
843 *
844 * @return
845 * - 0 the dbuff or marker is behind its parent.
846 * - >0 the number of bytes the marker is ahead of its parent.
847 */
848#define fr_dbuff_ahead(_dbuff_or_marker) \
849 (fr_dbuff_current((_dbuff_or_marker)->parent) > fr_dbuff_current(_dbuff_or_marker) ? \
850 0 : fr_dbuff_current(_dbuff_or_marker) - fr_dbuff_current((_dbuff_or_marker)->parent))
851/** @} */
852
853/** @name Accessors
854 *
855 * Caching the pointers returned by the accessors is strongly discouraged.
856 * Cached pointers can become invalidated if the #fr_dbuff_t is extended, as
857 * the extensions callback may use realloc or memmove on the underlying buffer.
858 *
859 @code{.c}
860 fr_dbuff_t dbuff;
861 fr_dbuff_uctx_talloc_t tctx;
862 uint8_t *p;
863
864 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, SIZE_MAX);
865
866 p = fr_dbuff_current(&dbuff); // Cache the start pointer
867 fr_dbuff_extend_lowat(&dbuff, 1024); // Extension call triggers realloc
868
869 printf("%s", p); // Should print an empty string but may
870 // SEGV as p may now be invalid.
871 @endcode
872 *
873 * If offsets of a #fr_dbuff_t need to be accessed, markers should be used.
874 * If a dbuff is extended all markers associated with it will be updated so that the
875 * content they point to remains constant.
876 *
877 @code{.c}
878 fr_dbuff_t dbuff;
879 fr_dbuff_uctx_talloc_t tctx;
880 fr_dbuff_marker_t m;
881
882 fr_dbuff_init_talloc(NULL, &dbuff, &tctx, 512, SIZE_MAX);
883 fr_dbuff_marker(&m, &dbuff);
884
885 fr_dbuff_extend_lowat(&dbuff, 1024); // Extension call triggers realloc
886
887 printf("%s", fr_dbuff_current(&m)); // Marker was updated when the dbuff
888 // was extended. All is well.
889 @endcode
890 *
891 * Using offsets of the pointers returned by accessor functions is also strongly
892 * discouraged as it invalidates many of the protections dbuffs give.
893 *
894 @code{.c}
895 uint8_t buff[2];
896 fr_dbuff_t dbuff;
897
898 fr_dbuff_init(&dbuff, buff, sizeof(buff));
899 fr_dbuff_current(&dbuff)[2] = 0x00; // Write to invalid memory
900 @endcode
901 *
902 * @{
903 */
904
905/** Return a pointer to the dbuff
906 *
907 * @param[in] _dbuff_or_marker to return a pointer to.
908 * @return A pointer to the dbuff.
909 */
910#define fr_dbuff_ptr(_dbuff_or_marker) \
911 _Generic((_dbuff_or_marker), \
912 fr_dbuff_t * : ((fr_dbuff_t *)(_dbuff_or_marker)), \
913 fr_dbuff_marker_t * : (((fr_dbuff_marker_t *)(_dbuff_or_marker))->parent) \
914 )
915
916/** Return a const pointer to the dbuff
917 *
918 * @param[in] _dbuff_or_marker to return a pointer to.
919 * @return A pointer to the dbuff.
920 */
921#define fr_dbuff_ptr_const(_dbuff_or_marker) \
922 _Generic((_dbuff_or_marker), \
923 fr_dbuff_t * : ((fr_dbuff_t const *)(_dbuff_or_marker)), \
924 fr_dbuff_t const * : ((fr_dbuff_t const *)(_dbuff_or_marker)), \
925 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent), \
926 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent) \
927 )
928
929/** Return the underlying buffer in a dbuff or one of marker
930 *
931 * @param[in] _dbuff_or_marker to return the buffer for.
932 * @return A pointer to the start of the buffer.
933 */
934#define fr_dbuff_buff(_dbuff_or_marker) \
935 _Generic((_dbuff_or_marker), \
936 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->buff), \
937 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->buff), \
938 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->buff), \
939 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->buff) \
940 )
941
942/** Return the 'start' position of a dbuff or marker
943 *
944 * The start position is not necessarily the start of the buffer, and is
945 * advanced every time a dbuff is copied.
946 *
947 * @param[in] _dbuff_or_marker to return the start position of.
948 * @return A pointer to the start position of the buffer.
949 */
950#define fr_dbuff_start(_dbuff_or_marker) \
951 (_Generic((_dbuff_or_marker), \
952 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->start), \
953 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->start), \
954 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->start), \
955 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->start) \
956 ))
957
958/** Return the 'current' position of a dbuff or marker
959 *
960 * @param[in] _dbuff_or_marker to return the current position of.
961 * @return A pointer to the current position of the buffer or marker.
962 */
963#define fr_dbuff_current(_dbuff_or_marker) \
964 (_Generic((_dbuff_or_marker), \
965 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->p), \
966 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->p), \
967 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->p), \
968 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->p) \
969 ))
970
971/** @cond */
972/** Return a pointer to the 'current' position in a dbuff or marker
973 * @private
974 *
975 * @param[in] _dbuff_or_marker to return a pointer to the position pointer for.
976 * @return A pointer to the position pointer in the dbuff or marker.
977 */
978#define _fr_dbuff_current_ptr(_dbuff_or_marker) \
979 (_Generic((_dbuff_or_marker), \
980 fr_dbuff_t * : &(((fr_dbuff_t *)(_dbuff_or_marker))->p), \
981 fr_dbuff_marker_t * : &(((fr_dbuff_marker_t *)(_dbuff_or_marker))->p) \
982 ))
983/** @endcond */
984
985/** Return the current 'end' position of a dbuff or marker
986 *
987 * @param[in] _dbuff_or_marker to return the end position of.
988 * @return A pointer to the end position of the buffer or marker.
989 */
990#define fr_dbuff_end(_dbuff_or_marker) \
991 (_Generic((_dbuff_or_marker), \
992 fr_dbuff_t * : (((fr_dbuff_t const *)(_dbuff_or_marker))->end), \
993 fr_dbuff_t const * : (((fr_dbuff_t const *)(_dbuff_or_marker))->end), \
994 fr_dbuff_marker_t * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->end), \
995 fr_dbuff_marker_t const * : (((fr_dbuff_marker_t const *)(_dbuff_or_marker))->parent->end) \
996 ))
997/** @} */
998
999/** @name Position modification (recursive)
1000 *
1001 * Modify the 'current' position pointer of a dbuff or marker.
1002 * @{
1003 */
1004
1005/** Set a new 'current' position in a dbuff or marker
1006 * @private
1007 */
1008static inline void _fr_dbuff_set_recurse(fr_dbuff_t *dbuff, uint8_t adv_parent_flags, uint8_t const *p)
1009{
1010 if (adv_parent_flags & FR_DBUFF_ADV_PARENT_CURRENT) dbuff->p_i = p;
1011 if (adv_parent_flags & FR_DBUFF_ADV_PARENT_END) dbuff->end_i = p;
1012
1013 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, p);
1014}
1015
1016/** Set a new 'current' position in a dbuff or marker
1017 * @private
1018 *
1019 * @param[in,out] pos_p position pointer to modify.
1020 * @param[out] dbuff dbuff to use for constraints checks.
1021 * @param[in] p Position to set.
1022 * @return
1023 * - 0 not advanced (p before dbuff start) or after dbuff end.
1024 * - >0 the number of bytes the dbuff advanced by.
1025 * - <0 the number of bytes the dbuff retreated by.
1026 *
1027 */
1028static inline ssize_t _fr_dbuff_set(uint8_t **pos_p, fr_dbuff_t *dbuff, uint8_t const *p)
1029{
1030 uint8_t *c;
1031
1032 if (unlikely(p > dbuff->end)) return -(p - dbuff->end);
1033 if (unlikely(p < dbuff->start)) return 0;
1034
1035 c = *pos_p;
1036 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, p);
1037 *pos_p = UNCONST(uint8_t *, p);
1038
1039 return p - c;
1040}
1041
1042/** Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer, or a length value
1043 *
1044 * @param[in] _dst dbuff or marker to set the position for.
1045 * @param[in] _src Variable to glean new position from. Behaviour here
1046 * depends on the type of the variable.
1047 * - dbuff, the current position of the dbuff.
1048 * - marker, the current position of the marker.
1049 * - pointer, the position of the pointer.
1050 * - size_t, _dst->start + _src.
1051 * @return
1052 * - 0 not advanced.
1053 * - >0 the number of bytes the dbuff was advanced by.
1054 * - <0 the number of bytes required to complete the advancement
1055 */
1056#define fr_dbuff_set(_dst, _src) \
1057_fr_dbuff_set(\
1058 _fr_dbuff_current_ptr(_dst), fr_dbuff_ptr(_dst), \
1059 _Generic((_src), \
1060 fr_dbuff_t * : fr_dbuff_current((fr_dbuff_t const *)(_src)), \
1061 fr_dbuff_marker_t * : fr_dbuff_current((fr_dbuff_marker_t const *)(_src)), \
1062 uint8_t const * : (uint8_t const *)(_src), \
1063 uint8_t * : (uint8_t const *)(_src), \
1064 size_t : (fr_dbuff_start(_dst) + (uintptr_t)(_src)), \
1065 long : (fr_dbuff_start(_dst) + (uintptr_t)(_src)), \
1066 int : (fr_dbuff_start(_dst) + (uintptr_t)(_src)) \
1067 ) \
1068)
1069
1070/** Set the 'current' position in a dbuff or marker returning if _src is out of range
1071 *
1072 * @copydetails fr_dbuff_set
1073 */
1074#define FR_DBUFF_SET_RETURN(_dst, _src) FR_DBUFF_RETURN(fr_dbuff_set, _dst, _src)
1075
1076/** Set a new 'end' position in a dbuff or marker
1077 * @private
1078 *
1079 * @param[out] dbuff dbuff to use for constraints checks.
1080 * @param[in] p Position to set.
1081 */
1082static inline void _fr_dbuff_set_end(fr_dbuff_t *dbuff, uint8_t const *p)
1083{
1084#ifndef NDEBUG
1085 fr_assert(p >= dbuff->start);
1086 fr_assert(p <= dbuff->end);
1087#else
1088 if (!((p >= dbuff->start) && (p <= dbuff->end))) return;
1089#endif
1090
1091 dbuff->end = UNCONST(uint8_t *, p);
1092}
1093
1094/** Set a new 'end' position in a dbuff or marker
1095 *
1096 * @param[out] _dst dbuff to use for constraints checks.
1097 * @param[in] _end Position to set.
1098 */
1099#define fr_dbuff_set_end(_dst, _end) \
1100_fr_dbuff_set_end(\
1101 fr_dbuff_ptr(_dst), \
1102 _Generic((_end), \
1103 fr_dbuff_t * : fr_dbuff_current((fr_dbuff_t const *)(_end)), \
1104 fr_dbuff_marker_t * : fr_dbuff_current((fr_dbuff_marker_t const *)(_end)), \
1105 uint8_t const * : (uint8_t const *)(_end), \
1106 uint8_t * : (uint8_t const *)(_end) \
1107 ) \
1108)
1109
1110
1111/** Advance 'current' position in dbuff or marker by _len bytes
1112 *
1113 * @param[in] _dbuff_or_marker to advance.
1114 * @param[in] _len How much to advance dbuff by.
1115 * Must be a positive integer.
1116 * @return
1117 * - 0 not advanced.
1118 * - >0 the number of bytes the dbuff or marker was advanced by.
1119 * - <0 the number of bytes required to complete the advancement
1120 */
1121#define fr_dbuff_advance(_dbuff_or_marker, _len) \
1122 fr_dbuff_set(_dbuff_or_marker, \
1123 (fr_dbuff_current(_dbuff_or_marker) + \
1124 (_Generic((_len), \
1125 unsigned char : (size_t)(_len), \
1126 unsigned short : (size_t)(_len), \
1127 unsigned int : (size_t)(_len), \
1128 unsigned long : (size_t)(_len), \
1129 unsigned long long : (size_t)(_len), \
1130 int : (size_t)(_len) \
1131 ))))
1132
1133/** Advance the 'current' position in dbuff or marker by _len bytes returning if _len is out of range
1134 *
1135 * @copydetails fr_dbuff_advance
1136 */
1137#define FR_DBUFF_ADVANCE_RETURN(_dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_advance, _dbuff_or_marker, _len)
1138
1139/** Advance a dbuff or marker potentially extending it
1140 * @private
1141 *
1142 * @param[in,out] pos_p position pointer to modify.
1143 * @param[out] dbuff dbuff to use for constraints checks.
1144 * @param[in] len Number of bytes to advance by.
1145 * @return
1146 * - 0 not advanced, specified length would take us
1147 * past the end of the buffer, and we couldn't extend
1148 * by enough bytes.
1149 * - >0 the number of bytes the dbuff advanced by.
1150 * - <0 the number of bytes we'd need to complete the advance.
1151 *
1152 */
1153static inline ssize_t _fr_dbuff_advance_extend(uint8_t **pos_p, fr_dbuff_t *dbuff, size_t len)
1154{
1155 uint8_t *p = *pos_p + len;
1156
1157 if (p > dbuff->end) {
1158 size_t rel = p - dbuff->start; /* Get relative position to the start */
1159
1160 if (!dbuff->extend) {
1161 oos:
1162 return -((dbuff->start + rel) - dbuff->end);
1163 }
1164
1165 dbuff->extend(dbuff, p - dbuff->end); /* Try and extend by the number of bytes over */
1166 if ((dbuff->start + rel) > dbuff->end) goto oos;
1167
1168 *pos_p = dbuff->start + rel; /* Update pos_p */
1169 } else {
1170 *pos_p += len;
1171 }
1172
1173 if (dbuff->adv_parent && dbuff->parent) _fr_dbuff_set_recurse(dbuff->parent, dbuff->adv_parent, *pos_p);
1174
1175 return len;
1176}
1177
1178/** Advance current'position in dbuff or marker by _len bytes (extending if necessary)
1179 *
1180 * @param[in] _dbuff_or_marker to advance.
1181 * @param[in] _len How much to advance dbuff by.
1182 * Must be a positive integer.
1183 * @return
1184 * - 0 not advanced.
1185 * - >0 the number of bytes the dbuff or marker was advanced by.
1186 * - <0 the number of bytes we'd need to complete the advance.
1187 */
1188#define fr_dbuff_advance_extend(_dbuff_or_marker, _len) \
1189 _fr_dbuff_advance_extend(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), \
1190 (_Generic((_len), \
1191 unsigned char : (size_t)(_len), \
1192 unsigned short : (size_t)(_len), \
1193 unsigned int : (size_t)(_len), \
1194 unsigned long : (size_t)(_len), \
1195 unsigned long long : (size_t)(_len), \
1196 int : (size_t)(_len) \
1197 )))
1198
1199/** Advance the 'current' position in dbuff or marker by _len bytes (extending if necessary) returning if _len is out of range
1200 *
1201 * @copydetails fr_dbuff_advance_extend
1202 */
1203#define FR_DBUFF_ADVANCE_EXTEND_RETURN(_dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_advance_extend, _dbuff_or_marker, _len)
1204
1205/** Reset the 'current' position of the dbuff or marker to the 'start' of the buffer
1206 *
1207 */
1208#define fr_dbuff_set_to_start(_dbuff_or_marker) \
1209 fr_dbuff_set(_dbuff_or_marker, fr_dbuff_start(_dbuff_or_marker))
1210
1211/** Reset the 'current' position of the dbuff or marker to the 'end' of the buffer
1212 *
1213 */
1214#define fr_dbuff_set_to_end(_dbuff_or_marker) \
1215 fr_dbuff_set(_dbuff_or_marker, fr_dbuff_end(_dbuff_or_marker))
1216/** @} */
1217
1218/** @name Marker management
1219 *
1220 * Markers serve two purposes:
1221 *
1222 * - Markers allow the caller to track content in a dbuff as the dbuff is extended.
1223 * If the caller referred to content using a pointer into the underlying buffer,
1224 * that pointer may be invalidated if the buffer were extended.
1225 *
1226 * - Markers prevent content being shifted out of the buffer during an extension.
1227 *
1228 * Most operations that can be performed on an #fr_dbuff_t can also be performed
1229 * on a #fr_dbuff_marker_t.
1230 *
1231 * It is recommended that markers be created against a stack-frame-local dbuff so
1232 * that they are automatically released when the framed is popped.
1233 *
1234 * @see fr_dbuff_marker_t
1235 *
1236 * @{
1237 */
1238
1239/** Initialises a new marker pointing to the 'current' position of the dbuff
1240 *
1241 * @param[out] m to initialise.
1242 * @param[in] dbuff to associate marker with.
1243 * @return The position the marker was set to.
1244 */
1246{
1247 *m = (fr_dbuff_marker_t){
1248 .next = dbuff->m, /* Link into the head */
1249 .p = dbuff->p, /* Set the current position in the dbuff */
1250 .parent = dbuff /* Record which dbuff this marker was associated with */
1251 };
1252 dbuff->m = m;
1253
1254 return dbuff->p;
1255}
1256
1257/** Releases the specified marker and any markers added before it
1258 *
1259 * Pointers should be released in the inverse order to allocation.
1260 *
1261 * @param[in] m to release.
1262 */
1264{
1265 m->parent->m = m->next;
1266
1267#ifndef NDEBUG
1268 memset(m, 0, sizeof(*m)); /* Use after release */
1269#endif
1270}
1271
1272/** Trims the linked list back to the specified pointer and return how many bytes marker was behind p
1273 *
1274 * Pointers should be released in the inverse order to allocation.
1275 *
1276 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1277 * also being removed from the list.
1278 *
1279 * @param[in] m to release.
1280 * @return
1281 * - 0 marker is ahead of p.
1282 * - >0 the number of bytes the marker is behind p.
1283 */
1285{
1286 size_t len = fr_dbuff_behind(m);
1288 return len;
1289}
1290
1291/** Trims the linked list back to the specified pointer and return how many bytes marker was ahead of p
1292 *
1293 * Pointers should be released in the inverse order to allocation.
1294 *
1295 * Alternatively the oldest pointer can be released, resulting in any newer pointer
1296 * also being removed from the list.
1297 *
1298 * @param[in] m to release.
1299 * @return
1300 * - 0 marker is ahead of p.
1301 * - >0 the number of bytes the marker is behind p.
1302 */
1304{
1305 size_t len = fr_dbuff_ahead(m);
1307 return len;
1308}
1309/** @} */
1310
1311/** @name "in" functions (copy data into a dbuff)
1312 * @{
1313 */
1314
1315/** Internal copy function to switch between memcpy and memmove - do not call directly
1316 *
1317 * @private
1318 *
1319 * @param[out] o_start Where to copy data to.
1320 * @param[in] o_end end of the output buffer.
1321 * @param[in] i_start Where to copy data from.
1322 * @param[in] i_end end of the source buffer.
1323 * @return
1324 * - 0 on sanity check error.
1325 * - >0 the number of bytes copied.
1326 */
1327static inline CC_HINT(always_inline) size_t _fr_dbuff_safecpy(uint8_t *o_start, uint8_t *o_end,
1328 uint8_t const *i_start, uint8_t const *i_end)
1329{
1330 ssize_t diff;
1331 size_t i_len = i_end - i_start;
1332
1333 if (unlikely((o_end < o_start) || (i_end < i_start))) return 0; /* sanity check */
1334
1335 diff = (o_end - o_start) - (i_len);
1336 if (diff < 0) return 0;
1337
1338 if ((i_start > o_end) || (i_end < o_start)) { /* no-overlap */
1339 memcpy(o_start, i_start, i_len);
1340 } else { /* overlap */
1341 memmove(o_start, i_start, i_len);
1342 }
1343
1344 return (i_len);
1345}
1346
1347/** Internal function - do not call directly
1348 *
1349 * @private
1350 */
1351static inline ssize_t _fr_dbuff_in_memcpy(uint8_t **pos_p, fr_dbuff_t *out,
1352 uint8_t const *in, size_t inlen)
1353{
1354 fr_assert(!out->is_const);
1355
1356 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, out, inlen);
1357
1358 return _fr_dbuff_set(pos_p, out, (*pos_p) + _fr_dbuff_safecpy((*pos_p), (*pos_p) + inlen, in, in + inlen)); /* Advance out */
1359}
1360
1361/** Internal function - do not call directly
1362 *
1363 * @private
1364 */
1365static inline ssize_t _fr_dbuff_in_memcpy_dbuff(uint8_t **pos_p, fr_dbuff_t *out,
1366 uint8_t * const *in_p, fr_dbuff_t const *in, size_t inlen)
1367{
1368 fr_dbuff_t *our_in;
1369 uint8_t **our_in_p;
1370 size_t ext_len;
1371
1372 memcpy(&our_in, &in, sizeof(our_in)); /* Stupid const issues caused by generics */
1373 memcpy(&our_in_p, &in_p, sizeof(our_in_p)); /* Stupid const issues caused by generics */
1374
1375 if (inlen == SIZE_MAX) {
1376 ext_len = _fr_dbuff_extend_lowat(NULL, our_in, fr_dbuff_end(our_in) - (*our_in_p), inlen);
1377 if (ext_len < inlen) inlen = ext_len;
1378 } else {
1379 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(our_in_p, our_in, inlen); /* Extend in or return */
1380 }
1381 return _fr_dbuff_in_memcpy(pos_p, out, *our_in_p, inlen); /* Copy _in to _out */
1382}
1383
1384/** Copy exactly _inlen bytes into a dbuff or marker
1385 *
1386 * If _in is a dbuff and _inlen is greater than the number of bytes available
1387 * in that dbuff, the copy operation will fail.
1388 *
1389 * @note _in will not be advanced. If this is required #fr_dbuff_move should be used.
1390 *
1391 * @param[in] _dbuff_or_marker to copy data to.
1392 * @param[in] _in data to copy in to the dbuff or marker.
1393 * @param[in] _inlen How much data we need to copy.
1394 * If _in is a `char *` or `dbuff *` and SIZE_MAX
1395 * is passed, then _inlen will be substituted
1396 * for the length of the data in the dbuff.
1397 * @return
1398 * - 0 no data copied.
1399 * - >0 the number of bytes copied to the dbuff.
1400 * - <0 the number of bytes we would have needed
1401 * to complete the copy operation.
1402 */
1403#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen) \
1404 _Generic((_in), \
1405 uint8_t * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1406 fr_dbuff_ptr(_dbuff_or_marker), \
1407 (uint8_t const *)(_in), \
1408 _inlen), \
1409 uint8_t const * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1410 fr_dbuff_ptr(_dbuff_or_marker), \
1411 (uint8_t const *)(_in), \
1412 _inlen), \
1413 char * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1414 fr_dbuff_ptr(_dbuff_or_marker), \
1415 (uint8_t const *)(_in), \
1416 (size_t)(_inlen) == SIZE_MAX ? strlen((char const *)(_in)) : (_inlen)), \
1417 char const * : _fr_dbuff_in_memcpy(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1418 fr_dbuff_ptr(_dbuff_or_marker), \
1419 (uint8_t const *)(_in), \
1420 (size_t)(_inlen) == SIZE_MAX ? strlen((char const *)(_in)) : (_inlen)), \
1421 fr_dbuff_t * : _fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1422 fr_dbuff_ptr(_dbuff_or_marker), \
1423 &((fr_dbuff_t const *)(_in))->p, \
1424 ((fr_dbuff_t const *)(_in)), \
1425 _inlen), \
1426 fr_dbuff_marker_t * : _fr_dbuff_in_memcpy_dbuff(_fr_dbuff_current_ptr(_dbuff_or_marker), \
1427 fr_dbuff_ptr(_dbuff_or_marker), \
1428 &((fr_dbuff_marker_t const *)(_in))->p, \
1429 ((fr_dbuff_marker_t const *)(_in))->parent, _inlen) \
1430 )
1431
1432/** Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space
1433 * @copydetails fr_dbuff_in_memcpy
1434 */
1435#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen) FR_DBUFF_RETURN(fr_dbuff_in_memcpy, _dbuff_or_marker, _in, _inlen)
1436
1437/** Internal function - do not call directly
1438 *
1439 * @private
1440 */
1441static inline size_t _fr_dbuff_in_memcpy_partial(uint8_t **pos_p, fr_dbuff_t *out,
1442 uint8_t const *in, size_t inlen)
1443{
1444 size_t ext_len;
1445
1446 fr_assert(!out->is_const);
1447
1448 ext_len = _fr_dbuff_extend_lowat(NULL, out, fr_dbuff_end(out) - (*pos_p), inlen);
1449 if (ext_len < inlen) inlen = ext_len;
1450
1451 return _fr_dbuff_set(pos_p, out, (*pos_p) + _fr_dbuff_safecpy((*pos_p), (*pos_p) + inlen, in, in + inlen));
1452}
1453
1454/** Internal function - do not call directly
1455 *
1456 * @private
1457 */
1458static inline size_t _fr_dbuff_in_memcpy_partial_dbuff(uint8_t **pos_p, fr_dbuff_t *out,
1459 uint8_t * const *in_p, fr_dbuff_t const *in, size_t inlen)
1460{
1461 fr_dbuff_t *our_in = UNCONST(fr_dbuff_t *, in); /* Stupid const issues caused by generics */
1462 uint8_t **our_in_p = UNCONST(uint8_t **, in_p); /* Stupid const issues caused by generics */
1463 size_t ext_len;
1464
1465 ext_len = _fr_dbuff_extend_lowat(NULL, our_in, fr_dbuff_end(our_in) - (*our_in_p), inlen);
1466 if (ext_len < inlen) inlen = ext_len;
1467
1468 return _fr_dbuff_in_memcpy_partial(pos_p, out, (*our_in_p), inlen);
1469}
1470
1471/** Copy at most _inlen bytes into the dbuff
1472 *
1473 * Use this variant when writing data to a streaming buffer where
1474 * partial writes will be tracked.
1475 *
1476 * If _in is a #fr_dbuff_t and _inlen is greater than the number of bytes
1477 * available in that dbuff, the copy operation will truncated.
1478 *
1479 * @note _in will not be advanced. If this is required #fr_dbuff_move should be used.
1480 *
1481 * @param[in] _out to copy data to.
1482 * @param[in] _in Data to copy to dbuff.
1483 * @param[in] _inlen How much data we need to copy.
1484 * If _in is a char * or dbuff * and SIZE_MAX
1485 * is passed, then _inlen will be substituted
1486 * for the length of the buffer.
1487 * @return
1488 * - 0 no data copied.
1489 * - >0 the number of bytes copied to the dbuff.
1490 */
1491#define fr_dbuff_in_memcpy_partial(_out, _in, _inlen) \
1492 _Generic((_in), \
1493 uint8_t * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen), \
1494 uint8_t const * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen), \
1495 char * : _fr_dbuff_in_memcpy_partial(_fr_dbuff_current_ptr(_out), _out, (uint8_t const *)(_in), _inlen == SIZE_MAX ? strlen((char const *)(_in)) : _inlen), \
1496 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), \
1497 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), \
1498 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) \
1499 )
1500
1501/** Copy a partial byte sequence into a dbuff
1502 *
1503 * @copybrief fr_dbuff_in_memcpy_partial
1504 *
1505 * @param[in] _dbuff to copy byte sequence into.
1506 * @param[in] ... bytes to copy.
1507 */
1508#define fr_dbuff_in_bytes_partial(_dbuff, ...) \
1509 fr_dbuff_in_memcpy_partial(_dbuff, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1510
1511/** Copy a byte sequence into a dbuff or marker
1512 *
1513 * @copybrief fr_dbuff_in_memcpy
1514 *
1515 * @param[in] _dbuff_or_marker to copy byte sequence into.
1516 * @param[in] ... bytes to copy.
1517 */
1518#define fr_dbuff_in_bytes(_dbuff_or_marker, ...) \
1519 fr_dbuff_in_memcpy(_dbuff_or_marker, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1520
1521/** Copy a byte sequence into a dbuff or marker returning if there's insufficient space
1522 *
1523 * @copydetails fr_dbuff_in_bytes
1524 */
1525#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker, ...) \
1526 FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, ((uint8_t []){ __VA_ARGS__ }), sizeof((uint8_t []){ __VA_ARGS__ }))
1527
1528/** Internal function - do not call directly
1529 *
1530 * @private
1531 */
1532static inline ssize_t _fr_dbuff_memset(uint8_t **pos_p, fr_dbuff_t *dbuff, uint8_t c, size_t inlen)
1533{
1534 fr_assert(!dbuff->is_const);
1535
1536 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, dbuff, inlen);
1537
1538 memset((*pos_p), c, inlen);
1539
1540 return _fr_dbuff_set(pos_p, dbuff, (*pos_p) + inlen);
1541}
1542
1543/** Set _inlen bytes of a dbuff or marker to _c
1544 *
1545 * @param[in] _dbuff_or_marker to copy data to.
1546 * Will be advanced by _inlen bytes.
1547 * @param[in] _c Value to set.
1548 * @param[in] _inlen How much data we need to copy.
1549 * @return
1550 * - 0 no data set.
1551 * - >0 the number of bytes set in the dbuff.
1552 * - <0 the number of bytes required.
1553 */
1554#define fr_dbuff_memset(_dbuff_or_marker, _c, _inlen) \
1555 _fr_dbuff_memset(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _c, _inlen)
1556
1557/** Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space
1558 *
1559 * @copydetails fr_dbuff_memset
1560 */
1561#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen) FR_DBUFF_RETURN(fr_dbuff_memset, _dbuff_or_marker, _c, _inlen)
1562
1563/** @cond */
1564/** Define integer decoding functions
1565 * @private
1566 */
1567#define FR_DBUFF_PARSE_INT_DEF(_type) \
1568static inline ssize_t _fr_dbuff_in_##_type(uint8_t **pos_p, fr_dbuff_t *out, _type##_t num) \
1569{ \
1570 fr_assert(!out->is_const); \
1571 _FR_DBUFF_EXTEND_LOWAT_POS_OR_RETURN(pos_p, out, sizeof(_type##_t)); \
1572 fr_nbo_from_##_type((*pos_p), num); \
1573 return _fr_dbuff_set(pos_p, out, (*pos_p) + sizeof(_type##_t)); \
1574}
1575FR_DBUFF_PARSE_INT_DEF(uint16)
1576FR_DBUFF_PARSE_INT_DEF(uint32)
1577FR_DBUFF_PARSE_INT_DEF(uint64)
1578FR_DBUFF_PARSE_INT_DEF(int16)
1579FR_DBUFF_PARSE_INT_DEF(int32)
1580FR_DBUFF_PARSE_INT_DEF(int64)
1581/** @endcond */
1582
1583/*
1584
1585 */
1586
1587/** Internal function - do not call directly
1588 *
1589 * The fr_dbuff_in_<type>() functions take rvalues, so to implement float and
1590 * double in terms of the same-sized integers, we need a layer that gives us an
1591 * lvalue whose address we can cast.
1592 *
1593 * @private
1594 */
1595static inline ssize_t _fr_dbuff_in_float(uint8_t **pos_p, fr_dbuff_t *out, float num)
1596{
1597 return _fr_dbuff_in_uint32(pos_p, out, *(uint32_t *)(&num));
1598}
1599
1600/** Internal function - do not call directly
1601 *
1602 * @copydetails _fr_dbuff_in_float
1603 *
1604 * @private
1605 */
1606static inline ssize_t _fr_dbuff_in_double(uint8_t **pos_p, fr_dbuff_t *out, double num)
1607{
1608 return _fr_dbuff_in_uint64(pos_p, out, *(uint64_t *)(&num));
1609}
1610
1611/** Copy data from a fixed sized C type into a dbuff or marker
1612 *
1613 * @param[out] _dbuff_or_marker to write to. Integer types will be automatically
1614 converted to big endian byte order.
1615 * @param[in] _in Value to copy.
1616 * @return
1617 * - <0 the number of bytes we would have needed to complete the conversion.
1618 * - >0 the number of bytes _dbuff_or_marker was advanced by.
1619 */
1620#define fr_dbuff_in(_dbuff_or_marker, _in) \
1621 _Generic((_in), \
1622 int8_t : fr_dbuff_in_bytes(_dbuff_or_marker, (int8_t)_in), \
1623 int16_t : _fr_dbuff_in_int16(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int16_t)_in), \
1624 int32_t : _fr_dbuff_in_int32(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int32_t)_in), \
1625 int64_t : _fr_dbuff_in_int64(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (int64_t)_in), \
1626 uint8_t : fr_dbuff_in_bytes(_dbuff_or_marker, (uint8_t)_in), \
1627 uint16_t : _fr_dbuff_in_uint16(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint16_t)_in), \
1628 uint32_t : _fr_dbuff_in_uint32(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint32_t)_in), \
1629 uint64_t : _fr_dbuff_in_uint64(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (uint64_t)_in), \
1630 float : _fr_dbuff_in_float(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (float)_in), \
1631 double : _fr_dbuff_in_double(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), (double)_in) \
1632 )
1633
1634/** Copy data from a fixed sized C type into a dbuff returning if there is insufficient space
1635 *
1636 * @copydetails fr_dbuff_in
1637 */
1638#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in) FR_DBUFF_RETURN(fr_dbuff_in, _dbuff_or_marker, _in)
1639
1640/** Internal function - do not call directly
1641 * @private
1642 */
1643static inline ssize_t _fr_dbuff_in_uint64v(uint8_t **pos_p, fr_dbuff_t *dbuff, uint64_t num)
1644{
1645 size_t ret;
1646 uint8_t swapped[sizeof(uint64_t)];
1647
1648 ret = ROUND_UP_DIV((size_t)fr_high_bit_pos(num | 0x08), 8);
1649#ifdef __COVERITY__
1650 if (ret > sizeof(uint64_t)) return -1;
1651#endif
1652 fr_nbo_from_uint64(swapped, num);
1653
1654 return _fr_dbuff_in_memcpy(pos_p, dbuff, (swapped + (sizeof(uint64_t) - ret)), ret);
1655}
1656
1657/** Copy an integer value into a dbuff or marker using our internal variable length encoding
1658 *
1659 * @param[out] _dbuff_or_marker to copy integer value to.
1660 * @param[in] _num to copy.
1661 * @return
1662 * - <0 the number of bytes we would have needed to encode the integer value.
1663 * - >0 the number of bytes used to represent the integer value.
1664 */
1665#define fr_dbuff_in_uint64v(_dbuff_or_marker, _num) \
1666 _fr_dbuff_in_uint64v(_fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _num)
1667
1668/** Copy an integer value into a dbuff or marker using our internal variable length encoding returning if there is insufficient space
1669 *
1670 * @copydetails fr_dbuff_in_uint64v
1671 */
1672#define FR_DBUFF_IN_UINT64V(_dbuff_or_marker, _num) FR_DBUFF_RETURN(fr_dbuff_in_uint64v, _dbuff_or_marker, _num)
1673/** @} */
1674
1675/** @name "move" functions (copy data between dbuffs and markers)
1676 * @{
1677 */
1678/** Internal function - do not call directly
1679 * @private
1680 */
1681size_t _fr_dbuff_move_dbuff_to_dbuff(fr_dbuff_t *out, fr_dbuff_t *in, size_t len);
1682
1683/** Internal function - do not call directly
1684 * @private
1685 */
1686size_t _fr_dbuff_move_dbuff_to_dbuff_marker(fr_dbuff_marker_t *out, fr_dbuff_t *in, size_t len);
1687
1688/** Internal function - do not call directly
1689 * @private
1690 */
1691size_t _fr_dbuff_move_dbuff_marker_to_dbuff(fr_dbuff_t *out, fr_dbuff_marker_t *in, size_t len);
1692
1693/** Internal function - do not call directly
1694 * @private
1695 */
1696size_t _fr_dbuff_move_dbuff_marker_to_dbuff_marker(fr_dbuff_marker_t *out, fr_dbuff_marker_t *in, size_t len);
1697
1698/** Copy in as many bytes as possible from one dbuff or marker to another
1699 *
1700 * @warning Advances both _in and _out by _len, this may not be what you want.
1701 * If you only want _out to be advanced use fr_dbuff_in_memcpy(_out, _in, _len).
1702 * If you only want _in to be advanced use fr_dbuff_out_memcpy(_out, _in, _len).
1703 *
1704 * @param[in] _out to copy into.
1705 * @param[in] _in to copy from.
1706 * @param[in] _len The maximum length to copy.
1707 * @return Number of bytes to copy.
1708 */
1709#define fr_dbuff_move(_out, _in, _len) \
1710 _Generic((_out), \
1711 fr_dbuff_t * : \
1712 _Generic((_in), \
1713 fr_dbuff_t * : _fr_dbuff_move_dbuff_to_dbuff((fr_dbuff_t *)_out, \
1714 (fr_dbuff_t *)_in, \
1715 _len), \
1716 fr_dbuff_marker_t * : _fr_dbuff_move_dbuff_marker_to_dbuff((fr_dbuff_t *)_out, \
1717 (fr_dbuff_marker_t *)_in, \
1718 _len) \
1719 ), \
1720 fr_dbuff_marker_t * : \
1721 _Generic((_in), \
1722 fr_dbuff_t * : _fr_dbuff_move_dbuff_to_dbuff_marker((fr_dbuff_marker_t *)_out, \
1723 (fr_dbuff_t *)_in, \
1724 _len), \
1725 fr_dbuff_marker_t * : _fr_dbuff_move_dbuff_marker_to_dbuff_marker((fr_dbuff_marker_t *)_out, \
1726 (fr_dbuff_marker_t *)_in, \
1727 _len) \
1728 ) \
1729 )
1730/** @} */
1731
1732/** @name "out" functions (copy data out of a dbuff)
1733 * @{
1734 */
1735
1736/** Internal function - do not call directly
1737 *
1738 * @private
1739 */
1740static inline ssize_t _fr_dbuff_out_memcpy(uint8_t *out, uint8_t **pos_p, fr_dbuff_t *in, size_t outlen)
1741{
1742 size_t ext_len, to_copy, remaining;
1743
1744 for (remaining = outlen; remaining > 0; remaining -= to_copy) {
1745 to_copy = remaining;
1746 ext_len = _fr_dbuff_extend_lowat(NULL, in, fr_dbuff_end(in) - (*pos_p), 1);
1747 if (ext_len == 0) return -remaining;
1748 if (ext_len < to_copy) to_copy = ext_len;
1749 out += _fr_dbuff_set(pos_p, in,
1750 (*pos_p) + _fr_dbuff_safecpy(out, out + to_copy, (*pos_p), (*pos_p) + to_copy));
1751 }
1752
1753 return outlen;
1754}
1755/** Internal function - do not call directly
1756 *
1757 * @private
1758 */
1759static 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)
1760{
1761 if (outlen == SIZE_MAX) outlen = _fr_dbuff_extend_lowat(NULL, out, fr_dbuff_end(out) - (*out_p), outlen);
1762
1763 return _fr_dbuff_out_memcpy((*out_p), pos_p, in, outlen);
1764}
1765
1766/** Copy exactly _outlen bytes from the dbuff
1767 *
1768 * If _out is a dbuff and _outlen is greater than the number of bytes
1769 * available in that dbuff, the copy operation will fail.
1770 *
1771 * @note _out will not be advanced. If this is required #fr_dbuff_move should be used.
1772 *
1773 * @param[in] _out either a buffer, or another dbuff/marker to copy data to.
1774 * @param[in] _dbuff_or_marker to copy data from.
1775 * @param[in] _outlen How much data we need to copy.
1776 * If _out is `fr_dbuff_t *` and SIZE_MAX
1777 * is passed, then _inlen will be substituted
1778 * for the length of the buffer.
1779 * @return
1780 * - 0 no data copied.
1781 * - >0 the number of bytes copied.
1782 * - <0 the number of bytes we would have needed
1783 * to complete the copy operation.
1784 */
1785#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen) \
1786 _Generic((_out), \
1787 uint8_t * : _fr_dbuff_out_memcpy((uint8_t *)(_out), \
1788 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1789 fr_dbuff_ptr(_dbuff_or_marker), \
1790 _outlen), \
1791 fr_dbuff_t * : _fr_dbuff_out_memcpy_dbuff(_fr_dbuff_current_ptr((fr_dbuff_t *)_out), \
1792 fr_dbuff_ptr((fr_dbuff_t *)(_out)), \
1793 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1794 fr_dbuff_ptr(_dbuff_or_marker), _outlen), \
1795 fr_dbuff_marker_t * : _fr_dbuff_out_memcpy_dbuff(_fr_dbuff_current_ptr((fr_dbuff_marker_t *)_out), \
1796 fr_dbuff_ptr((fr_dbuff_marker_t *)(_out)), \
1797 _fr_dbuff_current_ptr(_dbuff_or_marker), \
1798 fr_dbuff_ptr(_dbuff_or_marker), _outlen) \
1799 )
1800
1801/** Copy outlen bytes from the dbuff returning if there's insufficient data in the dbuff
1802 *
1803 * @copydetails fr_dbuff_out_memcpy
1804 */
1805#define FR_DBUFF_OUT_MEMCPY_RETURN(_out, _dbuff_or_marker, _outlen) FR_DBUFF_RETURN(fr_dbuff_out_memcpy, _out, _dbuff_or_marker, _outlen)
1806
1807/** @cond */
1808/** Define integer encoding functions
1809 * @private
1810 */
1811#define FR_DBUFF_OUT_DEF(_type) \
1812static inline ssize_t _fr_dbuff_out_##_type(_type##_t *out, uint8_t **pos_p, fr_dbuff_t *in) \
1813{ \
1814 fr_assert(out); \
1815 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(in, sizeof(_type##_t)); \
1816 *out = fr_nbo_to_##_type((*pos_p)); \
1817 return _fr_dbuff_set(pos_p, in, (*pos_p) + sizeof(_type##_t)); \
1818}
1819
1820FR_DBUFF_OUT_DEF(uint16)
1821FR_DBUFF_OUT_DEF(uint32)
1822FR_DBUFF_OUT_DEF(uint64)
1823FR_DBUFF_OUT_DEF(int16)
1824FR_DBUFF_OUT_DEF(int32)
1825FR_DBUFF_OUT_DEF(int64)
1826
1827#define FR_DBUFF_OUT_DEF_NO_SWAP(_type) \
1828static inline ssize_t _fr_dbuff_out_##_type(_type##_t *out, uint8_t **pos_p, fr_dbuff_t *in) \
1829{ \
1830 fr_assert(out); \
1831 FR_DBUFF_EXTEND_LOWAT_OR_RETURN(in, sizeof(_type##_t)); \
1832 *out = **pos_p; \
1833 return _fr_dbuff_set(pos_p, in, (*pos_p) + sizeof(_type##_t)); \
1834}
1835
1836FR_DBUFF_OUT_DEF_NO_SWAP(uint8)
1837FR_DBUFF_OUT_DEF_NO_SWAP(int8)
1838/** @endcond */
1839
1840/** Copy data from a dbuff or marker to a fixed sized C type
1841 *
1842 * @param[out] _out Where to write the data. If out is an integer type
1843 * a byteswap will be performed if native endianness
1844 * is not big endian.
1845 * @param[in] _dbuff_or_marker to copy data from. Will be advanced by the number
1846 * of bytes consumed, i.e. if out is a uin16_t *,
1847 * _dbuff_or_marker will be advanced by two bytes.
1848 * @return
1849 * - <0 the number of bytes we would have needed to complete the conversion.
1850 * - >0 the number of bytes _in was advanced by.
1851 */
1852#define fr_dbuff_out(_out, _dbuff_or_marker) \
1853 _Generic((_out), \
1854 uint8_t * : _fr_dbuff_out_uint8((uint8_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1855 uint16_t * : _fr_dbuff_out_uint16((uint16_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1856 uint32_t * : _fr_dbuff_out_uint32((uint32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1857 uint64_t * : _fr_dbuff_out_uint64((uint64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1858 int8_t * : _fr_dbuff_out_int8((int8_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1859 int16_t * : _fr_dbuff_out_int16((int16_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1860 int32_t * : _fr_dbuff_out_int32((int32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1861 int64_t * : _fr_dbuff_out_int64((int64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1862 float * : _fr_dbuff_out_uint32((uint32_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)), \
1863 double * : _fr_dbuff_out_uint64((uint64_t *)(_out), _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker)) \
1864 )
1865
1866/** Copy data from a dbuff or marker to a fixed sized C type returning if there is insufficient data
1867 *
1868 * @copydetails fr_dbuff_out
1869 */
1870#ifndef STATIC_ANALYZER
1871#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker) FR_DBUFF_RETURN(fr_dbuff_out, _out, _dbuff_or_marker)
1872#else
1873#define FR_DBUFF_OUT_RETURN(_out, _dbuff_or_marker) do { *_out = 0; FR_DBUFF_RETURN(fr_dbuff_out, _out, _dbuff_or_marker); } while (0)
1874#endif
1875
1876/** Internal function - do not call directly
1877 * @private
1878 */
1879static inline ssize_t _fr_dbuff_out_uint64v(uint64_t *num, uint8_t **pos_p, fr_dbuff_t *dbuff, size_t length)
1880{
1881 ssize_t slen;
1882
1883 fr_assert(length > 0 && length <= sizeof(uint64_t));
1884
1885 *num = 0;
1886 slen = _fr_dbuff_out_memcpy(((uint8_t *) num) + (8 - length), pos_p, dbuff, length);
1887 if (slen <= 0) return slen;
1888
1889 *num = fr_nbo_to_uint64((uint8_t const *)num);
1890 return length;
1891}
1892
1893/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1894 * @param[in] _num points to a uint64_t to store the integer in
1895 * @param[in] _dbuff_or_marker data to copy bytes from
1896 * @param[in] _len number of bytes to read (must be positive and less than eight)
1897 *
1898 * @return
1899 * - 0 no data read.
1900 * - >0 the number of bytes read.
1901 * - <0 the number of bytes we would have needed
1902 * to complete the read operation.
1903 */
1904#define fr_dbuff_out_uint64v(_num, _dbuff_or_marker, _len) \
1905 _fr_dbuff_out_uint64v(_num, _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _len)
1906
1907/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1908 *
1909 * @copydetails fr_dbuff_out_uint64v
1910 */
1911#define FR_DBUFF_OUT_UINT64V_RETURN(_num, _dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_out_uint64v, _num, _dbuff_or_marker, _len)
1912
1913/** Internal function - do not call directly
1914 * @private
1915 */
1916static inline ssize_t _fr_dbuff_out_int64v(int64_t *num, uint8_t **pos_p, fr_dbuff_t *dbuff, size_t length)
1917{
1918 ssize_t slen;
1919 uint8_t msb = **pos_p;
1920
1921 fr_assert(length > 0 && length <= sizeof(uint64_t));
1922
1923 *num = 0;
1924 slen = _fr_dbuff_out_memcpy(((uint8_t *) num) + (8 - length), pos_p, dbuff, length);
1925 if (slen <= 0) return slen;
1926
1927 if (msb & 0x80) memset(((uint8_t *)num), 0xff, sizeof(*num) - length);
1928 *num = fr_nbo_to_int64((uint8_t const *)num);
1929
1930 return length;
1931}
1932
1933/** Read bytes from a dbuff or marker and interpret them as a network order signed integer
1934 * @param[in] _num points to an int64_t to store the integer in
1935 * @param[in] _dbuff_or_marker data to copy bytes from
1936 * @param[in] _len number of bytes to read (must be positive and less than eight)
1937 *
1938 * @return
1939 * - 0 no data read.
1940 * - >0 the number of bytes read.
1941 * - <0 the number of bytes we would have needed
1942 * to complete the read operation.
1943 */
1944#define fr_dbuff_out_int64v(_num, _dbuff_or_marker, _len) \
1945 _fr_dbuff_out_int64v(_num, _fr_dbuff_current_ptr(_dbuff_or_marker), fr_dbuff_ptr(_dbuff_or_marker), _len)
1946
1947/** Read bytes from a dbuff or marker and interpret them as a network order unsigned integer
1948 *
1949 * @copydetails fr_dbuff_out_int64v
1950 */
1951#define FR_DBUFF_OUT_INT64V_RETURN(_num, _dbuff_or_marker, _len) FR_DBUFF_RETURN(fr_dbuff_out_int64v, _num, _dbuff_or_marker, _len)
1952
1953/** @} */
1954#ifdef __cplusplus
1955}
1956#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:838
#define FR_DBUFF_FLAG_EXTENDED
Flag indicating that during the last extend call the dbuff was extended.
Definition dbuff.h:628
fr_dbuff_uctx_talloc_t tctx
Thread local tctx.
Definition dbuff.h:584
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:495
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:527
static int _dbuff_thread_local_free(void *dbtl)
Definition dbuff.h:587
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:1284
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:632
@ FR_DBUFF_NOT_EXTENDABLE
dbuff cannot be extended
Definition dbuff.h:635
@ FR_DBUFF_EXTENDED
dbuff was extended in the last extend call but cannot be extended again
Definition dbuff.h:647
@ FR_DBUFF_EXTENDABLE
dbuff can be extended
Definition dbuff.h:639
@ FR_DBUFF_EXTENDABLE_EXTENDED
dbuff was extended in the last extend call and may be extended again
Definition dbuff.h:643
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:990
#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:1245
#define FR_DBUFF_FLAG_EXTENDABLE
Flag indicating a dbuff is extendable.
Definition dbuff.h:624
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:583
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:1263
#define fr_dbuff_ahead(_dbuff_or_marker)
How many bytes the dbuff or marker is ahead of its parent.
Definition dbuff.h:848
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:1303
#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:453
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:582
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
uint8_t * end
uint8_t * start
long int ssize_t
uint8_t * buff
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:864
#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 * in
Definition value.h:1061
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1061
static fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061
int nonnull(2, 5))