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