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