The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_cache_htrie.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: e45787a9e5f311b7822aaf40e2381572394aa7c8 $
19 * @file rlm_cache_htrie.c
20 * @brief Simple htrie based cache.
21 *
22 * @copyright 2024 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23 * @copyright 2014 The FreeRADIUS server project
24 */
25#include <freeradius-devel/server/base.h>
26#include <freeradius-devel/util/heap.h>
27#include <freeradius-devel/util/debug.h>
28#include <freeradius-devel/util/value.h>
29#include <freeradius-devel/util/htrie.h>
30#include "../../rlm_cache.h"
31#include "lib/server/cf_parse.h"
32#include "lib/server/tmpl.h"
33#include "lib/util/types.h"
34
35static int cf_htrie_type_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
36static int cf_htrie_key_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
37 void const *data, UNUSED call_env_parser_t const *rule);
38
39typedef struct {
40 fr_htrie_t *cache; //!< Tree for looking up cache keys.
41 fr_heap_t *heap; //!< For managing entry expiry.
42
43 fr_type_t ktype; //!< When htrie is "auto", we use this type to decide
44 ///< what type of tree to use.
45
46 fr_htrie_type_t htype; //!< The htrie type we'll be using
47 bool htrie_auto; //!< Whether the user wanted to automatically configure
48 ///< the htrie.
49
50 pthread_mutex_t mutex; //!< Protect the tree from multiple readers/writers.
52
53typedef struct {
54 rlm_cache_entry_t fields; //!< Entry data.
55 fr_heap_index_t heap_id; //!< Offset used for expiry heap.
57
59 { FR_CONF_OFFSET("type", rlm_cache_htrie_t, htype), .dflt = "auto",
63};
64
65/** Custom htrie type parsing function
66 *
67 * Sets a bool, so we known if the original type was "auto", so we can constantly re-evaluate
68 * the htrie type based on the key type.
69 */
70int cf_htrie_type_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
71{
72 rlm_cache_htrie_t *inst = talloc_get_type_abort(parent, rlm_cache_htrie_t);
73 int ret;
74
75 ret = cf_table_parse_int(ctx, out, parent, ci, rule);
76 if (unlikely(ret < 0)) return ret;
77
78 /*
79 * Record this now, so when we overwrite this
80 * value later, we know to keep checking the
81 * htrie type value for consistency.
82 */
83 if (*(int *)out == FR_HTRIE_AUTO) inst->htrie_auto = true;
84
85 return 0;
86}
87
88/** Custom key parsing function for checking compatibility of key types
89 *
90 * This function does two things:
91 * - It selects a htrie type based on the key type.
92 * - It checks that all keys are compatible with each other.
93 */
94static int cf_htrie_key_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
95 void const *data, UNUSED call_env_parser_t const *rule)
96{
98 tmpl_t *key_tmpl;
99 fr_type_t our_ktype, old_ktype;
100
101 /*
102 * Call the standard pair parsing function
103 */
104 if (unlikely(call_env_parse_pair(ctx, &key_tmpl, t_rules, ci, data, rule) < 0)) return -1;
105 our_ktype = tmpl_expanded_type(key_tmpl);
106
107 /*
108 * We need the user to tell us what the key type is for ambiguous expansions
109 */
110 if (fr_type_is_void(our_ktype)) {
111 cf_log_err(ci, "Key type is unspecified. Add a cast to set a specific type");
112 return -1;
113 }
114
115 /*
116 * If we don't have a key type already, then just set it to the first key type we see
117 */
118 if (fr_type_is_void(inst->ktype)) {
119 inst->ktype = our_ktype;
120 /*
121 * Check if we can cast this key type, to the key type we've already seen
122 */
123 } else if (!fr_type_cast(our_ktype, inst->ktype)) {
124 cf_log_err(ci, "Incompatible key types '%s' and '%s', cast to a more broadly compatible "
125 "type such as 'string'", fr_type_to_str(inst->ktype), fr_type_to_str(our_ktype));
126 return -1;
127 }
128
129 /*
130 * See if we should promote inst->ktype
131 */
132 old_ktype = inst->ktype;
133 inst->ktype = fr_type_promote(inst->ktype, our_ktype);
135
136 /*
137 * If we're not automatically determining the htrie type,
138 * or the ktype hasn't changed, then don't bother figuring
139 * out the htrie type.
140 */
141 if (!inst->htrie_auto || (old_ktype == inst->ktype)) return 0;
142
143 /*
144 * We need to figure out the htrie type based on the key type
145 */
146 inst->htype = fr_htrie_hint(inst->ktype);
147 if (inst->htype == FR_HTRIE_INVALID) {
148 cf_log_err(ci, "Invalid data type '%s' for htrie key. "
149 "Cast to another type, or manually specify 'type", fr_type_to_str(inst->ktype));
150 return -1;
151 }
152
153 cf_log_info(ci, "Automatically setting htrie type to '%s' based on key type '%s'",
155
156 *(void **)out = key_tmpl;
157 return 0;
158}
159
160/** Compare two entries by expiry time
161 *
162 * There may be multiple entries with the same expiry time.
163 */
164static int8_t cache_heap_cmp(void const *one, void const *two)
165{
166 rlm_cache_entry_t const *a = one, *b = two;
167
168 return fr_unix_time_cmp(a->expires, b->expires);
169}
170
171/** Custom allocation function for the driver
172 *
173 * Allows allocation of cache entry structures with additional fields.
174 *
175 * @copydetails cache_entry_alloc_t
176 */
178 request_t *request)
179{
181
182 c = talloc_zero(NULL, rlm_cache_htrie_entry_t);
183 if (!c) {
184 RERROR("Failed allocating cache entry");
185 return NULL;
186 }
187
188 return (rlm_cache_entry_t *)c;
189}
190
191/** Locate a cache entry
192 *
193 * @note handle not used except for sanity checks.
194 *
195 * @copydetails cache_entry_find_t
196 */
198 UNUSED rlm_cache_config_t const *config, void *instance,
199 request_t *request, UNUSED void *handle, fr_value_box_t const *key)
200{
201 rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
202 rlm_cache_entry_t find = {};
203
205
206 fr_assert(driver->cache);
207
208 /*
209 * Clear out old entries
210 */
211 c = fr_heap_peek(driver->heap);
212 if (c && (fr_unix_time_lt(c->expires, fr_time_to_unix_time(request->packet->timestamp)))) {
213 fr_heap_extract(&driver->heap, c);
214 fr_htrie_delete(driver->cache, c);
215 talloc_free(c);
216 }
217
218 fr_value_box_copy_shallow(NULL, &find.key, key);
219
220 /*
221 * Is there an entry for this key?
222 */
223 c = fr_htrie_find(driver->cache, &find);
224 if (!c) {
225 *out = NULL;
226 return CACHE_MISS;
227 }
228 *out = c;
229
230 return CACHE_OK;
231}
232
233/** Free an entry and remove it from the data store
234 *
235 * @note handle not used except for sanity checks.
236 *
237 * @copydetails cache_entry_expire_t
238 */
240 request_t *request, UNUSED void *handle,
241 fr_value_box_t const *key)
242{
243 rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
244 rlm_cache_entry_t find = {};
246
247 if (!request) return CACHE_ERROR;
248
249 fr_value_box_copy_shallow(NULL, &find.key, key);
250
251 c = fr_htrie_find(driver->cache, &find);
252 if (!c) return CACHE_MISS;
253
254 fr_heap_extract(&driver->heap, c);
255 fr_htrie_delete(driver->cache, c);
256 talloc_free(c);
257
258 return CACHE_OK;
259}
260
261/** Insert a new entry into the data store
262 *
263 * @note handle not used except for sanity checks.
264 *
265 * @copydetails cache_entry_insert_t
266 */
268 request_t *request, void *handle,
269 rlm_cache_entry_t const *c)
270{
271 cache_status_t status;
272
273 rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
274
275 fr_assert(handle == request);
276
277 if (!request) return CACHE_ERROR;
278
279 /*
280 * Allow overwriting
281 */
282 if (!fr_htrie_insert(driver->cache, c)) {
283 status = cache_entry_expire(config, instance, request, handle, &c->key);
284 if ((status != CACHE_OK) && !fr_cond_assert(0)) return CACHE_ERROR;
285
286 if (!fr_htrie_insert(driver->cache, c)) {
287 RERROR("Failed adding entry");
288
289 return CACHE_ERROR;
290 }
291 }
292
293 if (fr_heap_insert(&driver->heap, UNCONST(rlm_cache_entry_t *, c)) < 0) {
294 fr_htrie_delete(driver->cache, c);
295 RERROR("Failed adding entry to expiry heap");
296
297 return CACHE_ERROR;
298 }
299
300 return CACHE_OK;
301}
302
303/** Update the TTL of an entry
304 *
305 * @note handle not used except for sanity checks.
306 *
307 * @copydetails cache_entry_set_ttl_t
308 */
310 request_t *request, UNUSED void *handle,
312{
313 rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
314
315#ifdef NDEBUG
316 if (!request) return CACHE_ERROR;
317#endif
318
319 if (!fr_cond_assert(fr_heap_extract(&driver->heap, c) == 0)) {
320 RERROR("Entry not in heap");
321 return CACHE_ERROR;
322 }
323
324 if (fr_heap_insert(&driver->heap, c) < 0) {
325 fr_htrie_delete(driver->cache, c); /* make sure we don't leak entries... */
326 RERROR("Failed updating entry TTL. Entry was forcefully expired");
327 return CACHE_ERROR;
328 }
329 return CACHE_OK;
330}
331
332/** Return the number of entries in the cache
333 *
334 * @note handle not used except for sanity checks.
335 *
336 * @copydetails cache_entry_count_t
337 */
338static uint64_t cache_entry_count(UNUSED rlm_cache_config_t const *config, void *instance,
339 request_t *request, UNUSED void *handle)
340{
341 rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
342
343 if (!request) return CACHE_ERROR;
344
345 return fr_htrie_num_elements(driver->cache);
346}
347
348/** Lock the htrie
349 *
350 * @note handle not used except for sanity checks.
351 *
352 * @copydetails cache_acquire_t
353 */
354static int cache_acquire(void **handle, UNUSED rlm_cache_config_t const *config, void *instance,
355 request_t *request)
356{
357 rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
358
359 pthread_mutex_lock(&driver->mutex);
360
361 *handle = request; /* handle is unused, this is just for sanity checking */
362
363 RDEBUG3("Mutex acquired");
364
365 return 0;
366}
367
368/** Release an entry unlocking any mutexes
369 *
370 * @note handle not used except for sanity checks.
371 *
372 * @copydetails cache_release_t
373 */
374static void cache_release(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request,
376{
377 rlm_cache_htrie_t *driver = talloc_get_type_abort(instance, rlm_cache_htrie_t);
378
379 pthread_mutex_unlock(&driver->mutex);
380
381 RDEBUG3("Mutex released");
382}
383
384/** Cleanup a cache_htrie instance
385 *
386 */
387static int mod_detach(module_detach_ctx_t const *mctx)
388{
389 rlm_cache_htrie_t *driver = talloc_get_type_abort(mctx->mi->data, rlm_cache_htrie_t);
390
391 if (driver->cache) {
393 void *data;
394
395 for (data = fr_rb_iter_init_inorder(&iter, driver->cache);
396 data;
397 data = fr_rb_iter_next_inorder(&iter)) {
400 }
401 }
402
403 pthread_mutex_destroy(&driver->mutex);
404
405 return 0;
406}
407
408/** Create a new cache_htrie instance
409 *
410 * @param[in] mctx Data required for instantiation.
411 * @return
412 * - 0 on success.
413 * - -1 on failure.
414 */
415static int mod_instantiate(module_inst_ctx_t const *mctx)
416{
417 rlm_cache_htrie_t *driver = talloc_get_type_abort(mctx->mi->data, rlm_cache_htrie_t);
418 int ret;
419
420 /*
421 * The cache.
422 */
423 driver->cache = fr_htrie_alloc(driver, driver->htype,
427 if (!driver->cache) {
428 PERROR("Failed to create cache");
429 return -1;
430 }
431
432 /*
433 * The heap of entries to expire.
434 */
435 driver->heap = fr_heap_talloc_alloc(driver, cache_heap_cmp, rlm_cache_htrie_entry_t, heap_id, 0);
436 if (!driver->heap) {
437 ERROR("Failed to create heap for the cache");
438 return -1;
439 }
440
441 if ((ret = pthread_mutex_init(&driver->mutex, NULL)) < 0) {
442 ERROR("Failed initializing mutex: %s", fr_syserror(ret));
443 return -1;
444 }
445
446 return 0;
447}
448
451 .common = {
452 .magic = MODULE_MAGIC_INIT,
453 .name = "cache_htrie",
455 .instantiate = mod_instantiate,
456 .detach = mod_detach,
457 .inst_size = sizeof(rlm_cache_htrie_t),
458 .inst_type = "rlm_cache_htrie_t",
459 },
460 .alloc = cache_entry_alloc,
461
462 .find = cache_entry_find,
463 .insert = cache_entry_insert,
464 .expire = cache_entry_expire,
465 .set_ttl = cache_entry_set_ttl,
466 .count = cache_entry_count,
467
468 .acquire = cache_acquire,
469 .release = cache_release,
470
471 .key_parse = cf_htrie_key_parse
472};
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
int call_env_parse_pair(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Standard function we use for parsing call env pairs.
Definition call_env.c:375
Per method call config.
Definition call_env.h:175
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition cf_parse.c:1550
API to parse internal format configuration items into native C types.
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:596
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
Common header for all CONF_* types.
Definition cf_priv.h:49
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_log_info(_cf, _fmt,...)
Definition cf_util.h:291
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
uint32_t(* fr_hash_t)(void const *)
Definition hash.h:36
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:146
int fr_heap_extract(fr_heap_t **hp, void *data)
Remove a node from the heap.
Definition heap.c:239
unsigned int fr_heap_index_t
Definition heap.h:80
static void * fr_heap_peek(fr_heap_t *h)
Return the item from the top of the heap but don't pop it.
Definition heap.h:136
#define fr_heap_talloc_alloc(_ctx, _cmp, _talloc_type, _field, _init)
Creates a heap that verifies elements are of a specific talloc type.
Definition heap.h:115
The main heap structure.
Definition heap.h:66
size_t fr_htrie_type_table_len
Definition htrie.c:37
fr_table_num_sorted_t const fr_htrie_type_table[]
Definition htrie.c:31
fr_htrie_t * fr_htrie_alloc(TALLOC_CTX *ctx, fr_htrie_type_t type, fr_hash_t hash_data, fr_cmp_t cmp_data, fr_trie_key_t get_key, fr_free_t free_data)
An abstraction over our internal hashes, rb trees, and prefix tries.
Definition htrie.c:92
fr_htrie_type_t
Definition htrie.h:49
@ FR_HTRIE_AUTO
Automatically choose the best type.
Definition htrie.h:54
@ FR_HTRIE_INVALID
Definition htrie.h:50
static fr_htrie_type_t fr_htrie_hint(fr_type_t type)
Definition htrie.h:149
static bool fr_htrie_insert(fr_htrie_t *ht, void const *data)
Insert data into a htrie.
Definition htrie.h:112
static int fr_htrie_num_elements(fr_htrie_t *ht)
Return the number of elements in the htrie.
Definition htrie.h:144
static char const * fr_htrie_type_to_str(fr_htrie_type_t type)
Return a static string containing the type name.
Definition htrie.h:185
static bool fr_htrie_delete(fr_htrie_t *ht, void const *data)
Delete data from a htrie, freeing it if free_data cb was passed to fr_htrie_alloc.
Definition htrie.h:136
static void * fr_htrie_find(fr_htrie_t *ht, void const *data)
Find data in a htrie.
Definition htrie.h:104
A hash/rb/prefix trie abstraction.
Definition htrie.h:80
#define PERROR(_fmt,...)
Definition log.h:228
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RERROR(fmt,...)
Definition log.h:298
talloc_free(reap)
fr_type_t
int8_t(* fr_cmp_t)(void const *a, void const *b)
Definition misc.h:38
module_instance_t * mi
Module instance to detach.
Definition module_ctx.h:57
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for detach calls.
Definition module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
static const conf_parser_t config[]
Definition base.c:183
#define fr_assert(_expr)
Definition rad_assert.h:38
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition rb.c:824
void fr_rb_iter_delete_inorder(fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
Definition rb.c:898
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:321
fr_value_box_t key
Key used to identify entry.
Definition rlm_cache.h:73
module_t common
Common fields for all loadable modules.
Definition rlm_cache.h:258
cache_status_t
Definition rlm_cache.h:39
@ CACHE_ERROR
Fatal error.
Definition rlm_cache.h:41
@ CACHE_OK
Cache entry found/updated.
Definition rlm_cache.h:42
@ CACHE_MISS
Cache entry notfound.
Definition rlm_cache.h:43
void rlm_cache_handle_t
Definition rlm_cache.h:35
fr_unix_time_t expires
When the entry expires.
Definition rlm_cache.h:76
Configuration for the rlm_cache module.
Definition rlm_cache.h:51
Definition rlm_cache.h:72
static int mod_detach(module_detach_ctx_t const *mctx)
Cleanup a cache_htrie instance.
static rlm_cache_entry_t * cache_entry_alloc(UNUSED rlm_cache_config_t const *config, UNUSED void *instance, request_t *request)
Custom allocation function for the driver.
bool htrie_auto
Whether the user wanted to automatically configure the htrie.
static int cf_htrie_type_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Custom htrie type parsing function.
static int cf_htrie_key_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, void const *data, UNUSED call_env_parser_t const *rule)
Custom key parsing function for checking compatibility of key types.
rlm_cache_entry_t fields
Entry data.
static conf_parser_t driver_config[]
static uint64_t cache_entry_count(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle)
Return the number of entries in the cache.
static int cache_acquire(void **handle, UNUSED rlm_cache_config_t const *config, void *instance, request_t *request)
Lock the htrie.
fr_htrie_t * cache
Tree for looking up cache keys.
static void cache_release(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED rlm_cache_handle_t *handle)
Release an entry unlocking any mutexes.
rlm_cache_driver_t rlm_cache_htrie
static int8_t cache_heap_cmp(void const *one, void const *two)
Compare two entries by expiry time.
static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle, fr_value_box_t const *key)
Free an entry and remove it from the data store.
static cache_status_t cache_entry_find(rlm_cache_entry_t **out, UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle, fr_value_box_t const *key)
Locate a cache entry.
pthread_mutex_t mutex
Protect the tree from multiple readers/writers.
fr_heap_index_t heap_id
Offset used for expiry heap.
static cache_status_t cache_entry_set_ttl(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle, rlm_cache_entry_t *c)
Update the TTL of an entry.
static int mod_instantiate(module_inst_ctx_t const *mctx)
Create a new cache_htrie instance.
static cache_status_t cache_entry_insert(rlm_cache_config_t const *config, void *instance, request_t *request, void *handle, rlm_cache_entry_t const *c)
Insert a new entry into the data store.
fr_heap_t * heap
For managing entry expiry.
fr_htrie_type_t htype
The htrie type we'll be using.
fr_type_t ktype
When htrie is "auto", we use this type to decide what type of tree to use.
void * data
Module's instance data.
Definition module.h:271
conf_parser_t const * config
How to convert a CONF_SECTION to a module instance.
Definition module.h:198
Structures and prototypes for templates.
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition tmpl_eval.c:209
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:341
eap_aka_sim_process_conf_t * inst
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_get_type_abort_const
Definition talloc.h:282
static int8_t fr_unix_time_cmp(fr_unix_time_t a, fr_unix_time_t b)
Compare two fr_unix_time_t values.
Definition time.h:944
static fr_unix_time_t fr_time_to_unix_time(fr_time_t when)
Convert an fr_time_t (internal time) to our version of unix time (wallclock time)
Definition time.h:688
#define fr_unix_time_lt(_a, _b)
Definition time.h:367
int(* fr_trie_key_t)(uint8_t **out, size_t *outlen, void const *data)
Definition trie.h:56
static fr_slen_t parent
Definition pair.h:851
bool fr_type_cast(fr_type_t dst, fr_type_t src)
Return if we're allowed to cast the types.
Definition types.c:283
fr_type_t fr_type_promote(fr_type_t a, fr_type_t b)
Return the promoted type.
Definition types.c:572
Types of values contained within an fr_value_box_t.
#define fr_type_is_void(_x)
Definition types.h:357
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition value.c:6129
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition value.c:676
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition value.c:3834
int fr_value_box_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
Definition value.c:2084
static fr_slen_t data
Definition value.h:1265
static size_t char ** out
Definition value.h:997