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