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