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