The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
xlat_redundant.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: 16425de27b49c2d8ccaf3c90bb7b5852fcac0893 $
19 *
20 * @file xlat_redundant.c
21 * @brief Register xlat functions for calling redundant xlats
22 *
23 * @copyright 2023 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 */
25RCSID("$Id: 16425de27b49c2d8ccaf3c90bb7b5852fcac0893 $")
26
27#include <freeradius-devel/unlang/interpret.h>
28#include <freeradius-devel/unlang/xlat_redundant.h>
29#include <freeradius-devel/unlang/xlat_func.h>
30#include <freeradius-devel/unlang/xlat_priv.h>
31
32#include <freeradius-devel/server/cf_util.h>
33#include <freeradius-devel/server/module.h>
34#include <freeradius-devel/server/module_rlm.h>
35#include <freeradius-devel/unlang/xlat.h>
36
37#include <freeradius-devel/util/dlist.h>
38#include <freeradius-devel/util/rand.h>
39#include <freeradius-devel/util/rb.h>
40#include <freeradius-devel/util/sbuff.h>
41
42
43/*
44 * Internal redundant handler for xlats
45 */
46typedef enum {
47 XLAT_REDUNDANT_INVALID = 0, //!< Not a valid redundant type.
48 XLAT_REDUNDANT, //!< Use the first xlat function first, then
49 ///< go through in sequence, using the next
50 ///< function after each failure.
51
52 XLAT_LOAD_BALANCE, //!< Pick a random xlat, and if that fails
53 ///< then the call as a whole fails.
54
55 XLAT_REDUNDANT_LOAD_BALANCE, //!< Pick a random xlat to start, then fail
56 ///< between the other xlats in the redundant
57 ///< group.
59
60typedef struct {
61 fr_dlist_t entry; //!< Entry in the redundant function list.
62 xlat_t const *func; //!< Resolved xlat function.
64
65typedef struct {
66 xlat_redundant_type_t type; //!< Type of redundant xlat expression.
67 fr_dlist_head_t funcs; //!< List of redundant xlat functions.
68 CONF_SECTION *cs; //!< That this redundant xlat list was created from.
70
71typedef struct {
72 xlat_redundant_t *xr; //!< Information about the redundant xlat.
73 xlat_exp_head_t **ex; //!< Array of xlat expressions created by
74 ///< tokenizing the arguments to the redundant
75 ///< xlat, then duplicating them multiple times,
76 ///< one for each xlat function that may be called.
78
79typedef struct {
80 bool last_success; //!< Did the last call succeed?
81
82 xlat_exp_head_t **first; //!< First function called.
83 ///< Used for redundant-load-balance.
84 xlat_exp_head_t **current; //!< Last function called, used for redundant xlats.
86
87/** Pass back the result from a single redundant child call
88 *
89 */
91 xlat_ctx_t const *xctx,
92 request_t *request, UNUSED fr_value_box_list_t *in)
93{
95 xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
97
98 if (rctx->last_success) {
99 done:
100 talloc_free(rctx);
101 return xa;
102 }
103
104 /*
105 * We're at the end, loop back to the start
106 */
107 if (++rctx->current >= (xri->ex + talloc_array_length(xri->ex))) rctx->current = xri->ex;
108
109 /*
110 * We're back to the first one we tried, fail...
111 */
112 if (rctx->current == rctx->first) {
113 error:
114 xa = XLAT_ACTION_FAIL;
115 goto done;
116 }
117
118 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
119
120 /*
121 * Push the next child...
122 */
123 if (unlang_xlat_push(ctx, &rctx->last_success, (fr_value_box_list_t *)out->dlist,
124 request, *rctx->current, UNLANG_SUB_FRAME) < 0) goto error;
125
127}
128
129/** Pass back the result from a single redundant child call
130 *
131 */
133 xlat_ctx_t const *xctx,
134 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
135{
136 xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
138
139 talloc_free(rctx);
140
141 return xa;
142}
143
144/** xlat "redundant", "load-balance" and "redundant-load-balance" processing
145 *
146 * @ingroup xlat_functions
147 */
149 xlat_ctx_t const *xctx,
150 request_t *request, UNUSED fr_value_box_list_t *in)
151{
154
155 MEM(rctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), xlat_redundant_rctx_t));
156
157 switch (xri->xr->type) {
158 /*
159 * Run through each of the redundant functions sequentially
160 * starting at the first.
161 */
162 case XLAT_REDUNDANT:
163 rctx->current = rctx->first = xri->ex; /* First element first */
164 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) {
165 error:
166 talloc_free(rctx);
167 return XLAT_ACTION_FAIL;
168 }
169 break;
170
171 /*
172 * Run a single random redundant function.
173 */
175 rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
176 if (unlang_xlat_yield(request, xlat_load_balance_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
177 break;
178
179 /*
180 * Run through each of the redundant functions sequentially
181 * starting at a random element.
182 */
184 rctx->first = &xri->ex[(size_t)fr_rand() & (talloc_array_length(xri->ex) - 1)]; /* Random start */
185 if (unlang_xlat_yield(request, xlat_redundant_resume, NULL, 0, rctx) != XLAT_ACTION_YIELD) goto error;
186 break;
187
188 default:
189 fr_assert(0);
190 }
191
192 if (unlang_xlat_push(ctx, &rctx->last_success, (fr_value_box_list_t *)out->dlist,
193 request, *rctx->current, UNLANG_SUB_FRAME) < 0) return XLAT_ACTION_FAIL;
194
196}
197
198/** Allocate an xlat node to call an xlat function
199 *
200 * @param[in] ctx to allocate the new node in.
201 * @param[in] func to call.
202 * @param[in] args Arguments to the function. Will be copied,
203 * and freed when the new xlat node is freed.
204 */
205static xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t const *func, xlat_exp_head_t const *args)
206{
207 xlat_exp_t *node;
208
209 MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, func->name, strlen(func->name)));
210 node->call.func = func;
211 if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
212 talloc_free(node);
213 return NULL;
214 }
215 node->flags = func->flags;
216 node->flags.impure_func = !func->flags.pure;
217 xlat_flags_merge(&node->flags, &args->flags);
218
219 if (func->input_type == XLAT_INPUT_ARGS) {
220 xlat_arg_parser_t const *arg_p;
221 xlat_exp_t *arg = xlat_exp_head(node->call.args);
222
223 /*
224 * The original tokenizing is done using the redundant xlat argument parser
225 * so the boxes haven't been marked up with the appropriate "safe for".
226 */
227 for (arg_p = node->call.func->args; arg_p->type != FR_TYPE_NULL; arg_p++) {
228 if (!arg) break;
229
230 xlat_exp_foreach(arg->group, child) {
231 if (child->type == XLAT_BOX) fr_value_box_mark_safe_for(&child->data, arg_p->safe_for);
232 }
233
234 arg = xlat_exp_next(node->call.args, arg);
235 }
236 }
237
238 /*
239 * If the function is pure, AND it's arguments are pure,
240 * then remember that we need to call a pure function.
241 */
242 node->flags.can_purify = (func->flags.pure && args->flags.pure) | args->flags.can_purify;
243
244 return node;
245}
246
247
248/** Allocate additional nodes for evaluation
249 *
250 */
252{
253 xlat_redundant_t *xr = talloc_get_type_abort(xctx->uctx, xlat_redundant_t);
254 xlat_redundant_inst_t *xri = talloc_get_type_abort(xctx->inst, xlat_redundant_inst_t);
255 unsigned int num = 0;
256 xlat_redundant_func_t const *first;
257
258 MEM(xri->ex = talloc_array(xri, xlat_exp_head_t *, fr_dlist_num_elements(&xr->funcs)));
259 xri->xr = xr;
260
261 first = talloc_get_type_abort(fr_dlist_head(&xr->funcs), xlat_redundant_func_t);
262
263 /*
264 * For each function, create the appropriate xlat
265 * node, and duplicate the child arguments.
266 */
268 xlat_exp_t *node;
270
271 /*
272 * We have to do this here as it only
273 * becomes an error when the user tries
274 * to use the redundant xlat.
275 */
276 if (first->func->input_type != xrf->func->input_type) {
277 cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different argument styles "
278 "cannot be used in the same redundant section", first->func->name, xrf->func->name);
279 error:
280 talloc_free(xri->ex);
281 return -1;
282 }
283
284 /*
285 * We pass the current arguments in
286 * so that the instantiation functions
287 * for the new node can operate
288 * correctly.
289 */
291 MEM(node = xlat_exp_func_alloc(head, xrf->func, xctx->ex->call.args));
293
294 switch (xrf->func->input_type) {
296 break;
297
298 case XLAT_INPUT_ARGS:
299 if (xlat_validate_function_args(node) < 0) {
300 PERROR("Invalid arguments for redundant expansion function \"%s\"",
301 xrf->func->name);
302 goto error;
303 }
304 break;
305 }
306
307 /*
308 * Add the xlat function (and any children)
309 * to the end of the instantiation list so
310 * they'll get called at some point after
311 * we return.
312 */
313 head->flags = node->flags;
314 if (xlat_finalize(head, NULL) < 0) {
315 PERROR("Failed bootstrapping function \"%s\"",
316 xrf->func->name);
317 goto error;
318 }
319 xri->ex[num++] = head;
320 }
321
322 /*
323 * Free the original argument nodes so they're
324 * not evaluated when the redundant xlat is called.
325 *
326 * We need to re-evaluate the arguments for each
327 * redundant function call we perform.
328 *
329 * The xlat_exp_func_alloc call above associates
330 * a copy of the original arguments with each
331 * function that's called.
332 */
333 fr_dlist_talloc_free(&xctx->ex->call.args->dlist);
334
335 return 0;
336}
337
342
343static inline CC_HINT(always_inline)
345{
347
348 MEM(xrf = talloc_zero(xr, xlat_redundant_func_t));
349 xrf->func = x;
350 fr_dlist_insert_tail(&xr->funcs, xrf);
351}
352
353/** Compare two module_rlm_xlat_t based on whether they have the same name
354 *
355 * @note If the two xlats both have the same name as the module that registered them,
356 * then they are considered equal.
357 */
358static int8_t module_xlat_cmp(void const *a, void const *b)
359{
362 char const *a_p, *b_p;
363
364 /*
365 * A null result means a self-named module xlat,
366 * which is always equal to another self-named
367 * module xlat.
368 */
369 a_p = strchr(mrx_a->xlat->name, '.');
370 b_p = strchr(mrx_b->xlat->name, '.');
371 if (!a_p && !b_p) return 0;
372
373 /*
374 * Compare the bit after the module name
375 */
376 if (!a_p || !b_p) return CMP(a_p, b_p);
377
378 return CMP(strcmp(a_p, b_p), 0);
379}
380
381static int8_t module_qualified_xlat_cmp(void const *a, void const *b)
382{
383 int8_t ret;
384
387
388 ret = module_xlat_cmp(a, b);
389 if (ret != 0) return ret;
390
391 return CMP(mrx_a->mi, mrx_b->mi);
392}
393
394/** Registers a redundant xlat
395 *
396 * These xlats wrap the xlat methods of the modules in a redundant section,
397 * emulating the behaviour of a redundant section, but over xlats.
398 *
399 * @return
400 * - 0 on success.
401 * - -1 on error.
402 * - 1 if the modules in the section do not have an xlat method.
403 */
405{
406 static fr_table_num_sorted_t const xlat_redundant_type_table[] = {
407 { L("load-balance"), XLAT_LOAD_BALANCE },
408 { L("redundant"), XLAT_REDUNDANT },
409 { L("redundant-load-balance"), XLAT_REDUNDANT_LOAD_BALANCE },
410 };
411 static size_t xlat_redundant_type_table_len = NUM_ELEMENTS(xlat_redundant_type_table);
412
413 char const *name1;
414 xlat_redundant_type_t xr_type;
415 xlat_func_flags_t default_flags = 0; /* Prevent warnings about default flags if xr_rype is corrupt */
416
417 fr_type_t return_type = FR_TYPE_NULL;
418
419 CONF_ITEM *ci = NULL;
420 int children = 0, i;
421 fr_rb_tree_t *mrx_tree; /* Temporary tree for ordering xlats */
422
423 name1 = cf_section_name1(cs);
424 xr_type = fr_table_value_by_str(xlat_redundant_type_table, name1, XLAT_REDUNDANT_INVALID);
425 switch (xr_type) {
427 cf_log_err(cs, "Invalid redundant section verb \"%s\"", name1);
428 return -1;
429
430 case XLAT_REDUNDANT:
431 default_flags = XLAT_FUNC_FLAG_PURE; /* Can be pure */
432 break;
433
435 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
436 break;
437
439 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
440 break;
441 }
442
443 /*
444 * Count the children
445 */
446 while ((ci = cf_item_next(cs, ci))) {
447 if (!cf_item_is_pair(ci)) continue;
448
449 children++;
450 }
451
452 /*
453 * There must be at least one child.
454 *
455 * It's useful to allow a redundant section with only one
456 * child, for debugging.
457 */
458 if (children == 0) {
459 cf_log_err(cs, "%s %s { ... } section must contain at least one module",
461 return -1;
462 }
463
464 /*
465 * Resolve all the modules in the redundant section,
466 * and insert all the mrx into a temporary tree to
467 * order them.
468 *
469 * Next we'll iterate over all the mrx, creating
470 * redundant xlats from contiguous runs of mrxs
471 * pointing to the same xlat.
472 */
474 for (ci = cf_item_next(cs, NULL), i = 0;
475 ci;
476 ci = cf_item_next(cs, ci), i++) {
479 char const *name;
480
481 if (!cf_item_is_pair(ci)) continue;
482
484
486 if (!mi) {
487 cf_log_err(ci, "Module '%s' not found. Referenced in %s %s { ... } section",
489 error:
490 talloc_free(mrx_tree);
491 return -1;
492 }
493
494 mri = talloc_get_type_abort(mi->uctx, module_rlm_instance_t);
495 fr_dlist_foreach(&mri->xlats, module_rlm_xlat_t const, mrx) {
496 if (!fr_rb_insert(mrx_tree, mrx)) {
497 cf_log_err(cs, "Module '%s' referenced multiple times in %s %s { ... } section",
498 mrx->mi->name, cf_section_name1(cs), cf_section_name2(cs));
499 goto error;
500 }
501 }
502 }
503
504 if (fr_rb_num_elements(mrx_tree) == 0) {
505 cf_log_debug(cs, "No expansions exported by modules in %s %s { ... } section, "
506 "not registering redundant/load-balance expansion",
508 talloc_free(mrx_tree);
509 return 0;
510 }
511
512 /*
513 * Iterate over the xlats registered for the first module,
514 * verifying that the other module instances have all registered
515 * the similarly named xlat functions.
516 *
517 * We ignore any xlat functions that aren't available in all the
518 * modules.
519 */
520 {
523 fr_sbuff_marker_t name_start;
525 module_rlm_xlat_t *mrx, *prev_mrx;
527
528 FR_SBUFF_TALLOC_THREAD_LOCAL(&name, 128, SIZE_MAX);
529
530 /*
531 * Prepopulate the name buffer with <section_name2>.
532 * as every function wil be registered with this
533 * prefix.
534 */
536 (fr_sbuff_in_char(name, '.') <= 0)) {
537 cf_log_perr(cs, "Name too long");
538 return -1;
539 }
540
541 fr_sbuff_marker(&name_start, name);
542
543 mrx = fr_rb_iter_init_inorder(&iter, mrx_tree);
544
545 /*
546 * Iterate over the all the xlats, registered by
547 * all the modules in the section.
548 */
549 while (mrx) {
550 xlat_t *xlat;
551 xlat_func_flags_t flags = default_flags;
552 char const *name_p;
553
554 mi = mrx->mi;
555
556 /*
557 * Where the xlat name is in the format <mod>.<name2>
558 * then the redundant xlat will be <section_name2>.<xlat_name>.
559 *
560 * Where the xlat has no '.', it's likely just the module
561 * name, in which case we just use <section_name2>.
562 */
563 name_p = strchr(mrx->xlat->name, '.');
564 if (name_p) {
565 name_p++;
566 fr_sbuff_set(name, &name_start); /* Reset the aggregation buffer to the '.' */
567 if (fr_sbuff_in_bstrncpy(name, name_p, strlen(name_p)) < 0) {
568 cf_log_perr(cs, "Name too long");
569 goto error;
570 }
571 name_p = fr_sbuff_start(name);
572 } else {
573 name_p = cf_section_name2(cs);
574 }
575
576 MEM(xr = talloc_zero(NULL, xlat_redundant_t));
577 xr->type = xr_type;
578 xr->cs = cs;
580
581 /*
582 * Iterate over all the xlats registered by all the modules
583 * in the section, when we reach the end of a run of common
584 * xlats, we register the redundant xlat.
585 *
586 * Note: Just because a xlat function has the same name,
587 * it does not mean the function signature is compatible.
588 *
589 * These issues are caught when we instantiate a redundant
590 * xlat, as the arguments passed to the redunant xlat are
591 * validated against the argument definitions for each
592 * individual xlat the redunant xlat would call.
593 */
594 do {
595 if (!mrx->xlat->flags.pure) flags &= ~XLAT_FUNC_FLAG_PURE;
597 prev_mrx = mrx;
598 } while ((mrx = fr_rb_iter_next_inorder(&iter)) && (module_xlat_cmp(prev_mrx, mrx) == 0));
599
600 /*
601 * Warn, but allow, redundant/failover expansions that are
602 * neither redundant, nor failover.
603 *
604 * Sometimes useful to comment out modules during testing.
605 */
606 if (fr_dlist_num_elements(&xr->funcs) == 1) {
607 cf_log_warn(cs, "%s expansion has no alternates, only %s",
608 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
609 ((xlat_redundant_func_t *)fr_dlist_head(&xr->funcs))->func->name);
610
611 }
612
613 /*
614 * Register the new redundant xlat, and hang it off of
615 * the first module instance in the section.
616 *
617 * This isn't great, but at least the xlat should
618 * get unregistered at about the right time.
619 */
620 xlat = xlat_func_register(mi, name_p, xlat_redundant, return_type);
621 if (unlikely(xlat == NULL)) {
622 cf_log_err(cs, "Registering expansion for %s section failed",
623 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"));
624 talloc_free(xr);
625 return -1;
626 }
627 talloc_steal(xlat, xr); /* redundant xlat should own its own config */
628
629 cf_log_debug(cs, "Registered %s expansion \"%s\" with %u alternates",
630 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
631 xlat->name, fr_dlist_num_elements(&xr->funcs));
632
633 xlat_func_flags_set(xlat, flags);
636 }
637 }
638 talloc_free(mrx_tree);
639
640 return 0;
641}
va_list args
Definition acutest.h:770
#define RCSID(id)
Definition build.h:483
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#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
#define NUM_ELEMENTS(_t)
Definition build.h:337
Common header for all CONF_* types.
Definition cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:632
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1185
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1171
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:664
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1578
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:296
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:290
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:292
#define cf_item_next(_ci, _curr)
Definition cf_util.h:92
#define MEM(x)
Definition debug.h:36
static fr_slen_t in
Definition dict.h:824
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:486
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition dlist.h:94
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
Definition dlist.h:908
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:939
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:378
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:275
Head of a doubly linked list.
Definition dlist.h:51
Entry in a doubly linked list.
Definition dlist.h:41
static xlat_action_t xlat_redundant(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
xlat "redundant", "load-balance" and "redundant-load-balance" processing
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1403
#define UNLANG_SUB_FRAME
Definition interpret.h:36
#define PERROR(_fmt,...)
Definition log.h:228
talloc_free(reap)
fr_type_t
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VOID
User data.
unsigned long int size_t
module_instance_t * module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
Definition module_rlm.c:828
module_instance_t * mi
The module instance that registered the xlat.
Definition module_rlm.h:54
fr_dlist_head_t xlats
xlats registered to this module instance.
Definition module_rlm.h:44
xlat_t const * xlat
The xlat function.
Definition module_rlm.h:53
An xlat function registered to a module.
Definition module_rlm.h:52
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
Definition rb.c:824
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
#define fr_rb_talloc_alloc(_ctx, _type, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:205
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:321
The main red black tree structure.
Definition rb.h:73
static char const * name
ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1480
ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
Definition sbuff.c:1502
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_in_char(_sbuff,...)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
void * uctx
Extra data passed to module_instance_alloc.
Definition module.h:339
Module instance data.
Definition module.h:265
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_get_type_abort_const
Definition talloc.h:282
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition xlat.c:573
int unlang_xlat_push(TALLOC_CTX *ctx, bool *p_success, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:286
fr_type_t type
Type to cast argument to.
Definition xlat.h:155
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition xlat.h:139
static fr_slen_t head
Definition xlat.h:422
fr_value_box_safe_for_t safe_for
Escaped value to set for boxes processed by this escape function.
Definition xlat.h:157
#define xlat_copy(_ctx, _out, _in)
Definition xlat.h:459
bool can_purify
if the xlat has a pure function with pure arguments.
Definition xlat.h:116
@ XLAT_INPUT_ARGS
Ingests a number of arguments.
Definition xlat.h:49
@ XLAT_INPUT_UNPROCESSED
No input argument processing.
Definition xlat.h:48
fr_slen_t xlat_validate_function_args(xlat_exp_t *node)
bool pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition xlat.h:114
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:168
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
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
Definition xlat.h:42
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
Definition xlat.h:39
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
bool impure_func
xlat contains an impure function
Definition xlat.h:115
Definition for a single argument consumend by an xlat function.
Definition xlat.h:147
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1048
static size_t char ** out
Definition value.h:997
void * rctx
Resume context.
Definition xlat_ctx.h:54
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition xlat_ctx.h:63
void const * inst
xlat instance data.
Definition xlat_ctx.h:50
void * uctx
Passed to the registration function.
Definition xlat_ctx.h:65
void * inst
xlat instance data to populate.
Definition xlat_ctx.h:62
An xlat calling ctx.
Definition xlat_ctx.h:49
An xlat instantiation ctx.
Definition xlat_ctx.h:61
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
Definition xlat_func.c:402
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:365
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition xlat_func.c:218
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
Definition xlat_func.h:93
xlat_func_flags_t
Definition xlat_func.h:36
@ XLAT_FUNC_FLAG_NONE
Definition xlat_func.h:37
@ XLAT_FUNC_FLAG_PURE
Definition xlat_func.h:38
char const * name
Name of xlat function.
Definition xlat_priv.h:64
#define xlat_exp_head_alloc(_ctx)
Definition xlat_priv.h:271
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:157
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
Definition xlat_priv.h:244
@ XLAT_BOX
fr_value_box_t
Definition xlat_priv.h:107
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:109
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
Definition xlat_priv.h:227
xlat_input_type_t input_type
Type of input used.
Definition xlat_priv.h:92
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
Definition xlat_priv.h:280
xlat_flags_t flags
various flags
Definition xlat_priv.h:90
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
Definition xlat_priv.h:220
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
Definition xlat_priv.h:236
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition xlat_priv.h:207
An xlat expansion node.
Definition xlat_priv.h:151
static xlat_action_t xlat_load_balance_resume(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Pass back the result from a single redundant child call.
xlat_redundant_t * xr
Information about the redundant xlat.
static xlat_arg_parser_t const xlat_redundant_args[]
static int8_t module_qualified_xlat_cmp(void const *a, void const *b)
bool last_success
Did the last call succeed?
fr_dlist_head_t funcs
List of redundant xlat functions.
fr_dlist_t entry
Entry in the redundant function list.
static int8_t module_xlat_cmp(void const *a, void const *b)
Compare two module_rlm_xlat_t based on whether they have the same name.
xlat_exp_head_t ** first
First function called.
xlat_redundant_type_t type
Type of redundant xlat expression.
xlat_exp_head_t ** current
Last function called, used for redundant xlats.
xlat_exp_head_t ** ex
Array of xlat expressions created by tokenizing the arguments to the redundant xlat,...
static xlat_exp_t * xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t const *func, xlat_exp_head_t const *args)
Allocate an xlat node to call an xlat function.
static void xlat_redundant_add_xlat(xlat_redundant_t *xr, xlat_t const *x)
static int xlat_redundant_instantiate(xlat_inst_ctx_t const *xctx)
Allocate additional nodes for evaluation.
int xlat_register_redundant(CONF_SECTION *cs)
Registers a redundant xlat.
xlat_t const * func
Resolved xlat function.
CONF_SECTION * cs
That this redundant xlat list was created from.
xlat_redundant_type_t
@ XLAT_REDUNDANT_INVALID
Not a valid redundant type.
@ XLAT_REDUNDANT
Use the first xlat function first, then go through in sequence, using the next function after each fa...
@ XLAT_LOAD_BALANCE
Pick a random xlat, and if that fails then the call as a whole fails.
@ XLAT_REDUNDANT_LOAD_BALANCE
Pick a random xlat to start, then fail between the other xlats in the redundant group.
static xlat_action_t xlat_redundant_resume(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat_ctx_t const *xctx, request_t *request, UNUSED fr_value_box_list_t *in)
Pass back the result from a single redundant child call.