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