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