The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
xlat_inst.c
Go to the documentation of this file.
1/*
2 * This program 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
5 * (at 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: c21db77cad8aadb649573fee3b22141c14eb9c4b $
19 *
20 * @file xlat_inst.c
21 * @brief Create instance data for xlat function calls.
22 *
23 * @copyright 2018-2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @copyright 2018 The FreeRADIUS server project
25 */
26RCSID("$Id: c21db77cad8aadb649573fee3b22141c14eb9c4b $")
27
28#include <freeradius-devel/io/schedule.h>
29#include <freeradius-devel/server/base.h>
30#include <freeradius-devel/unlang/xlat_priv.h>
31
32/** Holds instance data created by xlat_instantiate
33 */
35
36/** Holds thread specific instance data created by xlat_instantiate
37 */
38static _Thread_local fr_heap_t *xlat_thread_inst_tree;
39
40/** Compare two xlat instances based on node pointer
41 *
42 * @param[in] one First xlat expansion instance.
43 * @param[in] two Second xlat expansion instance.
44 * @return CMP(one, two)
45 */
46static int8_t _xlat_inst_cmp(void const *one, void const *two)
47{
48 xlat_inst_t const *a = one, *b = two;
49
50 return CMP(a->node->call.id, b->node->call.id);
51}
52
53/** Compare two thread instances based on node pointer
54 *
55 * @param[in] one First thread specific xlat expansion instance.
56 * @param[in] two Second thread specific xlat expansion instance.
57 * @return CMP(one, two)
58 */
59static int8_t _xlat_thread_inst_cmp(void const *one, void const *two)
60{
61 xlat_thread_inst_t const *a = one, *b = two;
62
63 return CMP(a->node->call.id, b->node->call.id);
64}
65
66/** Destructor for xlat_thread_inst_t
67 *
68 * Calls thread_detach method if provided by xlat expansion
69 *
70 * @note This cannot be converted to a talloc destructor,
71 * as we need to call thread_detach *before* any of the children
72 * of the talloc ctx are freed.
73 */
75{
76 xlat_call_t const *call = &xt->node->call;
77
79
80 DEBUG4("Cleaning up xlat thread instance (%p/%p)", xt, xt->data);
81
83
84 (void) call->func->thread_detach(XLAT_THREAD_INST_CTX(call->inst->data,
85 xt->data, xt->node, xt->mctx,
86 xt->el,
87 call->func->thread_uctx));
88
89 return 0;
90}
91
92/** Create thread instances where needed
93 *
94 * @param[in] ctx to allocate thread instance data in.
95 * @param[in] el event list to register I/O handlers against.
96 * @param[in] xi to allocate thread-instance data for.
97 * @return
98 * - 0 on success. The node/thread specific data will be inserted
99 * into xlat_thread_inst_tree.
100 * - -1 on failure.
101 */
103{
104 size_t extra_headers = 0;
105 size_t extra_mem = 0;
106 xlat_call_t const *call = &((xlat_inst_t const *)talloc_get_type_abort_const(xi, xlat_inst_t))->node->call;
107 xlat_thread_inst_t *xt = NULL;
108
109 /*
110 * Allocate extra room for the thread instance data
111 */
112 if (call->func->thread_inst_size) {
113 extra_headers++;
114 extra_mem += call->func->thread_inst_size;
115 }
116
117 /*
118 * Allocate extra room for the mctx
119 */
120 if (call->func->mctx) {
121 extra_headers++;
122 extra_mem += sizeof(*call->func->mctx);
123 }
124
125 if (extra_headers || extra_mem) {
126 MEM(xt = talloc_zero_pooled_object(ctx, xlat_thread_inst_t, extra_headers, extra_mem));
127 } else {
128 MEM(xt = talloc_zero(ctx, xlat_thread_inst_t));
129 }
130
131 xt->node = xi->node;
132 xt->el = el;
133
134 fr_assert(xi->node->type == XLAT_FUNC);
135
136 if (call->func->thread_detach) talloc_set_destructor(xt, _xlat_thread_inst_detach);
137
138 if (call->func->thread_inst_size) {
139 MEM(xt->data = talloc_zero_array(xt, uint8_t, call->func->thread_inst_size));
140
141 if (call->func->thread_inst_type) {
142 talloc_set_name_const(xt->data, call->func->thread_inst_type);
143 } else {
144 talloc_set_name(xt->data, "xlat_%s_thread_t", call->func->name);
145 }
146 }
147
148 /*
149 * Create a module call ctx.
150 *
151 * We do this now because we're operating in the
152 * context of a thread and can get the thread
153 * specific data for the module.
154 */
155 if (call->func->mctx) {
156 module_ctx_t *mctx;
157
158 mctx = module_ctx_from_inst(xt, call->func->mctx);
159 mctx->thread = module_thread(mctx->mi)->data;
160
161 xt->mctx = mctx;
162 }
163
164 DEBUG4("Alloced xlat thread instance (%p/%p)", xt, xt->data);
165
166 return xt;
167}
168
169/** Destructor for xlat_inst_t
170 *
171 * Calls detach method if provided by xlat expansion
172 *
173 * @note This cannot be converted to a talloc destructor,
174 * as we need to call thread_detach *before* any of the children
175 * of the talloc ctx are freed.
176 */
178{
179 xlat_call_t const *call;
180
181 fr_assert(xlat_inst_tree); /* xlat_inst_init must have been called */
182
184 fr_assert(xi->node->type == XLAT_FUNC);
185
186 call = &xi->node->call;
187
188 /*
189 * Remove permanent data from the instance tree
190 * and auto-free the tree when the last xlat is
191 * freed.
192 */
193 if (!call->ephemeral) {
195 if (fr_heap_num_elements(xlat_inst_tree) == 0) TALLOC_FREE(xlat_inst_tree);
196 }
197
198 DEBUG4("Cleaning up xlat instance (%p/%p)", xi, xi->data);
199
200 if (call->func->detach) (void) call->func->detach(XLAT_INST_CTX(xi->data,
201 xi->node,
202 call->func->mctx,
203 call->func->uctx));
204 return 0;
205}
206
207/** Allocate instance data for an xlat expansion
208 *
209 * @param[in] node to allocate instance data for.
210 */
212{
213 xlat_call_t const *call = &node->call;
214 xlat_inst_t *xi = NULL;
215
216 (void)talloc_get_type_abort(node, xlat_exp_t);
217
218 fr_assert(xlat_inst_tree); /* xlat_inst_init must have been called */
219 fr_assert(node->type == XLAT_FUNC);
220 fr_assert(!call->inst);
221
222 if (call->func->inst_size) {
224 } else {
225 MEM(xi = talloc_zero(node, xlat_inst_t));
226 }
227 xi->node = node;
228
229 /*
230 * Instance data is freed when the
231 * node is freed.
232 */
233 if (call->func->detach || !call->ephemeral) {
234 talloc_set_destructor(xi, _xlat_inst_detach);
235 }
236
237 if (call->func->inst_size) {
238 MEM(xi->data = talloc_zero_array(xi, uint8_t, call->func->inst_size));
239 if (call->func->inst_type) {
240 talloc_set_name_const(xi->data, call->func->inst_type);
241 } else {
242 talloc_set_name(xi->data, "xlat_%s_t", call->func->name);
243 }
244 }
245
246 /*
247 * If the xlat has a call env defined, parse it.
248 */
249 if (call->func->call_env_method) {
251 "Method environment for module %s, xlat %s declared, "
252 "but no inst_size set", call->func->mctx->mi->name, call->func->name);
253
254 /*
255 * FIXME - This is wrong, we should pass in the tmpl_rule_t
256 * from the compiler call. But it would be prohibitively
257 * memory inefficient to copy it on every xlat call, and it
258 * only exists for the duration of the compilation phase
259 * because many elements are stack allocated. The correct
260 * fix is to allocate all tmpl_rules_t on the heap.
261 * OR just bite the bullet and duplicate the whole nested
262 * rules structure for every xlat node.
263 *
264 * Because of this hack, outer. and parent. will not work
265 * within xlat call envs.
266 */
267 xi->call_env = call_env_alloc(xi, call->func->name, call->func->call_env_method,
268 &(tmpl_rules_t){
269 .attr = {
270 .dict_def = call->dict,
271 .list_def = request_attr_request
272 }
273 }, call->func->mctx->mi->conf,
276 .mi = call->func->mctx->mi
277 });
278 if (!xi->call_env) {
279 talloc_free(xi);
280 return NULL;
281 }
282 }
283
284 return xi;
285}
286
287/** Callback for creating "ephemeral" instance data for a #xlat_exp_t
288 *
289 * @note Epehemeral xlats must not be shared between requests.
290 *
291 * @param[in] node to create "ephemeral" instance data for.
292 * @param[in] uctx event list passed to xlat thread instantiation functions.
293 * @return
294 * - 0 if instantiation functions were successful.
295 * - -1 if either instantiation function failed.
296 */
298{
300 xlat_call_t *call;
301 xlat_inst_t *xi;
303
304 /*
305 * tmpl_tokenize() instantiates ephemeral xlats. So for
306 * now, just ignore ones which are already instantiated.
307 */
308 if (node->type == XLAT_GROUP) {
309 return node->group->instantiated; /* prune on 1, continue on 0 */
310 }
311
312 if (node->type != XLAT_FUNC) return 0; /* skip it */
313
314 el = talloc_get_type_abort(uctx, fr_event_list_t);
315 call = &node->call;
316
317 fr_assert(!call->inst && !call->thread_inst);
318
319 /*
320 * Mark this up as an ephemeral node, so the destructors
321 * don't search for it in the xlat_inst_tree.
322 */
323 call->ephemeral = true;
324
325 xi = call->inst = xlat_inst_alloc(node);
326 if (!xi) return -1;
327
328 /*
329 * Instantiate immediately unlike permanent XLATs
330 * Where it's a separate phase.
331 */
332 if (call->func->instantiate) {
333 XLAT_VERIFY(xi->node);
334 if (call->func->instantiate(XLAT_INST_CTX(xi->data,
335 xi->node,
336 call->func->mctx,
337 call->func->uctx)) < 0) {
338 error:
339 TALLOC_FREE(call->inst);
340 return -1;
341 }
342 XLAT_VERIFY(xi->node);
343 }
344
345 /*
346 * Create a thread instance too.
347 */
348 xt = node->call.thread_inst = xlat_thread_inst_alloc(node, el, call->inst);
349 if (!xt) goto error;
350
351 if (call->func->thread_instantiate) {
352 XLAT_VERIFY(xi->node);
354 xt->data,
355 xi->node,
356 xt->mctx,
357 el,
358 call->func->thread_uctx)) < 0) goto error;
359 XLAT_VERIFY(xi->node);
360 }
361
362
363 return 0;
364}
365
366/** Create instance data for "ephemeral" xlats
367 *
368 * @note This function should only be called from routines which get
369 * passed a #request_t.
370 *
371 * @param[in] head of xlat tree to create instance data for.
372 * @param[in] el event list used to run any instantiate data
373 */
374static inline CC_HINT(always_inline) int xlat_instantiate_ephemeral(xlat_exp_head_t *head, fr_event_list_t *el)
375{
376 int ret;
377
378 /*
379 * The caller MAY resolve it, or may not. If the caller
380 * hasn't resolved it, then we can't allow any unresolved
381 * functions or attributes.
382 */
383 if (head->flags.needs_resolving) {
384 if (xlat_resolve(head, &(xlat_res_rules_t){ .allow_unresolved = false }) < 0) return -1;
385 }
386
387 if (head->instantiated) return 0;
388
390 if (ret < 0) return ret;
391
392 head->instantiated = true;
393
394 return 0;
395}
396
397/** Retrieve xlat/thread specific instance data
398 *
399 * @param[in] node to find thread specific data for.
400 * @return
401 * - Thread specific data on success.
402 * - NULL if the xlat has no thread instance data.
403 */
405{
406 xlat_call_t const *call = &node->call;
408
409 if (call->ephemeral) return call->thread_inst;
410
412 fr_assert(node->type == XLAT_FUNC);
414
415 /*
416 * This works because the comparator for
417 * the thread heap returns the same result
418 * as the one for the global instance data
419 * heap, and both heaps contain the same
420 * number of elements.
421 */
423 fr_assert(xt && (xt->idx == call->inst->idx));
424
425 return xt;
426}
427
428/** Create thread specific instance tree and create thread instances
429 *
430 * This should be called directly after the modules_thread_instantiate() function.
431 *
432 * Memory will be freed automatically when the thread exits.
433 *
434 * @param[in] ctx to bind instance tree lifetime to. Must not be
435 * shared between multiple threads.
436 * @param[in] el Event list to pass to all thread instantiation functions.
437 * @return
438 * - 0 on success.
439 * - -1 on failure.
440 */
442{
444
449 idx,
451 }
452
454 int ret;
455 xlat_call_t const *call = &xi->node->call;
457 if (unlikely(!xt)) return -1;
458
459 DEBUG3("Instantiating xlat \"%s\" node %p, instance %p, new thread instance %p",
460 call->func->name, xt->node, xi->data, xt);
461
463 if (!fr_cond_assert(ret == 0)) {
464 error:
465 TALLOC_FREE(xlat_thread_inst_tree); /* Reset the tree on error */
466 return -1;
467 }
468
469 if (!call->func->thread_instantiate) continue;
470
471 ret = call->func->thread_instantiate(XLAT_THREAD_INST_CTX(xi->data,
472 xt->data,
473 xi->node,
474 xt->mctx,
475 el,
476 call->func->thread_uctx));
477 if (unlikely(ret < 0)) goto error;
478 }}
479
480 return 0;
481}
482
483/** Destroy any thread specific xlat instances
484 *
485 */
487{
488 if (!xlat_thread_inst_tree) return;
489
490 TALLOC_FREE(xlat_thread_inst_tree);
491}
492
493/** Initialise the xlat instance data code
494 *
495 */
496static int xlat_instantiate_init(void)
497{
498 if (unlikely(xlat_inst_tree != NULL)) return 0;
499
501 if (!xlat_inst_tree) return -1;
502
503 return 0;
504}
505
506/** Call instantiation functions for all registered, "permanent" xlats
507 *
508 * Should be called after all the permanent xlats have been tokenised/bootstrapped.
509 */
511{
513
514 /*
515 * Loop over all the bootstrapped
516 * xlats, instantiating them.
517 */
519 xlat_call_t const *call = &xi->node->call;
520
521 /*
522 * We can't instantiate functions which
523 * still have children that need resolving
524 * as this may break redundant xlats
525 * if we end up needing to duplicate the
526 * argument nodes.
527 */
528 fr_assert(!xi->node->flags.needs_resolving);
529
530 if (!call->func->instantiate) continue;
531
532 if (call->func->instantiate(XLAT_INST_CTX(xi->data,
533 xi->node,
534 call->func->mctx,
535 call->func->uctx)) < 0) return -1;
536 }}
537
538 return 0;
539}
540
541/** Remove a node from the list of xlat instance data
542 *
543 * @note This is primarily used during "purification", to remove xlats which are no longer used.
544 *
545 * @param[in] node to remove instance data for.
546 */
548{
549 int ret;
550
551 fr_assert(node->type == XLAT_FUNC);
552 fr_assert(!node->call.func->detach);
553 fr_assert(!node->call.func->thread_detach);
554
555 if (node->call.inst) {
556 ret = fr_heap_extract(&xlat_inst_tree, node->call.inst);
557 if (ret < 0) return ret;
558
559 talloc_set_destructor(node->call.inst, NULL);
560 TALLOC_FREE(node->call.inst);
561 }
562
563 if (node->call.thread_inst) {
564 if (!node->call.ephemeral) {
565 ret = fr_heap_extract(&xlat_thread_inst_tree, node->call.thread_inst);
566 if (ret < 0) return ret;
567 }
568
569 talloc_set_destructor(node->call.thread_inst, NULL);
570 TALLOC_FREE(node->call.thread_inst);
571 }
572
573 return 0;
574}
575
576/** Callback for creating "permanent" instance data for a #xlat_exp_t
577 *
578 * This function records the #xlat_exp_t requiring instantiation but does
579 * not call the instantiation function. This is to allow for a clear separation
580 * between the module instantiation phase and the xlat instantiation phase.
581 *
582 * @note This is very similar to #xlat_instance_register but does not walk the
583 * children of the node. This is primarily used to register individual
584 * nodes for instantiation and when an xlat function is resolved in a
585 * subsequent resolution pass and needs to be registered for instantiation.
586 *
587 * @param[in] node to create "permanent" instance data for.
588 * @return
589 * - 0 if instantiation functions were successful.
590 * - -1 if either instantiation function failed.
591 */
593{
594 static uint64_t call_id;
595 xlat_call_t *call = &node->call;
596 bool ret;
597
598 fr_assert(node->type == XLAT_FUNC);
599 fr_assert(!call->id && !call->inst && !call->thread_inst); /* Node cannot already have instance data */
600 if (!fr_cond_assert(!call->ephemeral)) return -1; /* Can't bootstrap ephemeral calls */
601
602 call->inst = xlat_inst_alloc(node);
603 if (unlikely(!call->inst)) return -1;
604
605 DEBUG3("Instantiating xlat \"%s\" node %p, new instance %p", call->func->name, node, call->inst);
606
607 /*
608 * Assign a unique ID to each xlat function call.
609 *
610 * This is so they're ordered in the heap by
611 * the order in which they were "bootstrapped".
612 *
613 * This allows additional functions to be added
614 * in the instantiation functions of other xlats
615 * which is useful for the redundant xlats.
616 */
617 node->call.id = call_id++;
618
619 ret = fr_heap_insert(&xlat_inst_tree, call->inst);
620 if (!fr_cond_assert(ret == 0)) {
621 TALLOC_FREE(call->inst);
622 return -1;
623 }
624
625 return 0;
626}
627
628static int _xlat_inst_walker(xlat_exp_t *node, UNUSED void *uctx)
629{
630 /*
631 * tmpl_tokenize() instantiates ephemeral xlats. So for
632 * now, just ignore ones which are already instantiated.
633 */
634 if (node->type == XLAT_GROUP) {
635 return node->group->instantiated; /* prune on 1, continue on 0 */
636 }
637
638 if (node->type != XLAT_FUNC) return 0; /* skip it */
639
640
641 return xlat_instance_register_func(node);
642}
643
644/** Create instance data for "permanent" xlats
645 *
646 * @note This must only be used for xlats which are read from the configuration files.
647 * IF THIS IS CALLED FOR XLATS TOKENIZED AT RUNTIME YOU WILL LEAK LARGE AMOUNTS OF MEMORY.
648 * If the caller has a #tmpl_rules_t, it should call xlat_finalize() instead.
649 *
650 * @param[in] head of xlat tree to create instance data for. Will walk the entire tree
651 * registering all the xlat function calls for later instantiation.
652 */
653static inline CC_HINT(always_inline) int xlat_instance_register(xlat_exp_head_t *head)
654{
655 int ret;
656
657 /*
658 * If thread instantiate has been called, it's too late to
659 * bootstrap new xlats.
660 */
661 fr_assert_msg(!xlat_thread_inst_tree, "Tried to instantiate new compile time xlat at runtime. "
662 "xlat.runtime_el likely not set in tmpl rules when it should've been. "
663 "Use unlang_interpret_event_list() to get the current event list from the request");
664
665 /*
666 * Initialise the instance tree if this is the first xlat
667 * being instantiated.
668 */
670
671 if (head->instantiated) return 0;
672
673 /*
674 * Walk an expression registering all the function calls
675 * so that we can instantiate them later.
676 */
678 if (ret < 0) return ret;
679
680 head->instantiated = true;
681 return 0;
682}
683
684/** Bootstrap static xlats, or instantiate ephemeral ones.
685 *
686 * @param[in] head of xlat tree to create instance data for.
687 * @param[in] runtime_el determines whether we do ephemeral or static instantiation.
688 * If NULL, we perform static instantiation, otherwise
689 * will perform ephemeral instantiation passing the el to
690 * the instantiation functions.
691 */
693{
694 if (!runtime_el) {
696 }
697 return xlat_instantiate_ephemeral(head, runtime_el);
698}
699
700/** Walk over all registered instance data and free them explicitly
701 *
702 * This must be called before any modules or xlats are deregistered/unloaded and before
703 * the mainconfig is freed, as the xlat_t need to still exist in order to call
704 * the detach functions within them.
705 */
707{
708 xlat_inst_t *xi;
709
710 /*
711 * When we get to zero instances the heap
712 * is freed, so we need to check there's
713 * still a heap to pass to fr_heap_pop.
714 */
716}
#define RCSID(id)
Definition build.h:506
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:113
#define unlikely(_x)
Definition build.h:402
#define UNUSED
Definition build.h:336
call_env_t * call_env_alloc(TALLOC_CTX *ctx, char const *name, call_env_method_t const *call_env_method, tmpl_rules_t const *t_rules, CONF_SECTION *cs, call_env_ctx_t const *cec)
Given a call_env_method, parse all call_env_pair_t in the context of a specific call to an xlat or mo...
Definition call_env.c:795
@ CALL_ENV_CTX_TYPE_XLAT
The callenv is registered to an xlat.
Definition call_env.h:223
size_t inst_size
Size of per call env.
Definition call_env.h:245
struct call_env_ctx_s call_env_ctx_t
Definition call_env.h:37
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:141
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:212
#define MEM(x)
Definition debug.h:46
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:146
void * fr_heap_pop(fr_heap_t **hp)
Remove a node from the heap.
Definition heap.c:325
int fr_heap_extract(fr_heap_t **hp, void *data)
Remove a node from the heap.
Definition heap.c:239
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
Definition heap.h:124
static void * fr_heap_peek_at(fr_heap_t *h, fr_heap_index_t idx)
Peek at a specific index in the heap.
Definition heap.h:151
static unsigned int fr_heap_num_elements(fr_heap_t *h)
Return the number of elements in the heap.
Definition heap.h:179
#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
#define fr_heap_foreach(_heap, _type, _data)
Iterate over the contents of a heap.
Definition heap.h:205
The main heap structure.
Definition heap.h:66
talloc_free(hp)
#define DEBUG3(_fmt,...)
Definition log.h:266
#define DEBUG4(_fmt,...)
Definition log.h:267
Stores all information relating to an event list.
Definition event.c:377
unsigned char uint8_t
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
static module_ctx_t * module_ctx_from_inst(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx)
Allocate a module calling ctx on the heap based on an instance ctx.
Definition module_ctx.h:76
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
#define fr_assert(_expr)
Definition rad_assert.h:37
char const * name
Instance name e.g. user_database.
Definition module.h:357
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:351
void * data
Thread specific instance data.
Definition module.h:374
static module_thread_instance_t * module_thread(module_instance_t const *mi)
Retrieve module/thread specific instance for a module.
Definition module.h:503
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:336
#define talloc_get_type_abort_const
Definition talloc.h:110
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:201
static fr_event_list_t * el
fr_heap_index_t idx
Entry in heap of xlat instances.
Definition xlat.h:72
xlat_exp_t * node
Node this data relates to.
Definition xlat.h:77
void * data
Thread specific instance data.
Definition xlat.h:94
xlat_exp_t const * node
Node this data relates to.
Definition xlat.h:93
fr_heap_index_t idx
Entry in heap of xlat thread instances.
Definition xlat.h:86
fr_event_list_t * el
Event list associated with this thread.
Definition xlat.h:91
static fr_slen_t head
Definition xlat.h:420
void * data
xlat node specific instance data.
Definition xlat.h:78
#define XLAT_VERIFY(_node)
Definition xlat.h:463
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
call_env_t const * call_env
Per call environment.
Definition xlat.h:79
module_ctx_t const * mctx
A synthesised module calling ctx containing module global and thread instance data.
Definition xlat.h:96
Instance data for an xlat expansion node.
Definition xlat.h:71
Thread specific instance data for xlat expansion node.
Definition xlat.h:85
#define XLAT_THREAD_INST_CTX(_inst, _thread, _ex, _mctx, _el, _uctx)
Wrapper to create a xlat_thread_inst_ctx_t as a compound literal.
Definition xlat_ctx.h:124
#define XLAT_INST_CTX(_inst, _ex, _mctx, _uctx)
Wrapper to create a xlat_inst_ctx_t as a compound literal.
Definition xlat_ctx.h:109
int xlat_eval_walk(xlat_exp_head_t *head, xlat_walker_t walker, xlat_type_t type, void *uctx)
Walk over all xlat nodes (depth first) in a xlat expansion, calling a callback.
Definition xlat_eval.c:1942
xlat_thread_inst_t * xlat_thread_instance_find(xlat_exp_t const *node)
Retrieve xlat/thread specific instance data.
Definition xlat_inst.c:404
static int _xlat_inst_detach(xlat_inst_t *xi)
Destructor for xlat_inst_t.
Definition xlat_inst.c:177
int xlat_instance_register_func(xlat_exp_t *node)
Callback for creating "permanent" instance data for a xlat_exp_t.
Definition xlat_inst.c:592
void xlat_thread_detach(void)
Destroy any thread specific xlat instances.
Definition xlat_inst.c:486
static int xlat_instance_register(xlat_exp_head_t *head)
Create instance data for "permanent" xlats.
Definition xlat_inst.c:653
static int _xlat_instantiate_ephemeral_walker(xlat_exp_t *node, void *uctx)
Callback for creating "ephemeral" instance data for a xlat_exp_t.
Definition xlat_inst.c:297
static int xlat_instantiate_ephemeral(xlat_exp_head_t *head, fr_event_list_t *el)
Create instance data for "ephemeral" xlats.
Definition xlat_inst.c:374
int xlat_instantiate(void)
Call instantiation functions for all registered, "permanent" xlats.
Definition xlat_inst.c:510
static int8_t _xlat_inst_cmp(void const *one, void const *two)
Compare two xlat instances based on node pointer.
Definition xlat_inst.c:46
static int8_t _xlat_thread_inst_cmp(void const *one, void const *two)
Compare two thread instances based on node pointer.
Definition xlat_inst.c:59
int xlat_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Create thread specific instance tree and create thread instances.
Definition xlat_inst.c:441
static int _xlat_inst_walker(xlat_exp_t *node, UNUSED void *uctx)
Definition xlat_inst.c:628
static xlat_inst_t * xlat_inst_alloc(xlat_exp_t *node)
Allocate instance data for an xlat expansion.
Definition xlat_inst.c:211
static int _xlat_thread_inst_detach(xlat_thread_inst_t *xt)
Destructor for xlat_thread_inst_t.
Definition xlat_inst.c:74
void xlat_instances_free(void)
Walk over all registered instance data and free them explicitly.
Definition xlat_inst.c:706
static fr_heap_t * xlat_inst_tree
Holds instance data created by xlat_instantiate.
Definition xlat_inst.c:34
static int xlat_instantiate_init(void)
Initialise the xlat instance data code.
Definition xlat_inst.c:496
int xlat_finalize(xlat_exp_head_t *head, fr_event_list_t *runtime_el)
Bootstrap static xlats, or instantiate ephemeral ones.
Definition xlat_inst.c:692
static _Thread_local fr_heap_t * xlat_thread_inst_tree
Holds thread specific instance data created by xlat_instantiate.
Definition xlat_inst.c:38
int xlat_instance_unregister_func(xlat_exp_t *node)
Remove a node from the list of xlat instance data.
Definition xlat_inst.c:547
static xlat_thread_inst_t * xlat_thread_inst_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, xlat_inst_t *xi)
Create thread instances where needed.
Definition xlat_inst.c:102
char const * name
Name of xlat function.
Definition xlat_priv.h:64
char const * thread_inst_type
C type of thread instance structure.
Definition xlat_priv.h:84
module_inst_ctx_t * mctx
Original module instantiation ctx if this xlat was registered by a module.
Definition xlat_priv.h:72
bool ephemeral
Instance data is ephemeral (not inserted) into the instance tree.
Definition xlat_priv.h:140
xlat_instantiate_t instantiate
Instantiation function.
Definition xlat_priv.h:75
size_t thread_inst_size
Size of the thread instance data to pre-allocate.
Definition xlat_priv.h:85
xlat_detach_t detach
Destructor for when xlat instances are freed.
Definition xlat_priv.h:76
void * thread_uctx
uctx to pass to instantiation functions.
Definition xlat_priv.h:86
call_env_method_t const * call_env_method
Optional tmpl expansions performed before calling the xlat.
Definition xlat_priv.h:96
size_t inst_size
Size of instance data to pre-allocate.
Definition xlat_priv.h:78
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:110
@ XLAT_GROUP
encapsulated string of xlats
Definition xlat_priv.h:116
@ XLAT_INVALID
Bad expansion.
Definition xlat_priv.h:107
xlat_thread_instantiate_t thread_instantiate
Thread instantiation function.
Definition xlat_priv.h:81
xlat_thread_inst_t * thread_inst
Thread specific instance.
Definition xlat_priv.h:137
xlat_inst_t * inst
Instance data for the xlat_t.
Definition xlat_priv.h:136
char const * inst_type
C type of instance structure.
Definition xlat_priv.h:77
xlat_t const * func
The xlat expansion to expand format with.
Definition xlat_priv.h:127
uint64_t id
Identifier unique to each permanent xlat node.
Definition xlat_priv.h:123
xlat_type_t _CONST type
type of this expansion.
Definition xlat_priv.h:155
xlat_thread_detach_t thread_detach
Destructor for when xlat thread instance data is freed.
Definition xlat_priv.h:82
void * uctx
uctx to pass to instantiation functions.
Definition xlat_priv.h:79
An xlat function call.
Definition xlat_priv.h:122
An xlat expansion node.
Definition xlat_priv.h:148