The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
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: 3676b6904a4d0f5d456ce6ae811a583f0b933a98 $
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: 3676b6904a4d0f5d456ce6ae811a583f0b933a98 $")
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/module.h>
33#include <freeradius-devel/server/module_rlm.h>
34
35#include <freeradius-devel/util/rand.h>
36
37
38/*
39 * Internal redundant handler for xlats
40 */
41typedef enum : uint8_t {
42 XLAT_REDUNDANT_INVALID = 0, //!< Not a valid redundant type.
43 XLAT_REDUNDANT, //!< Use the first xlat function first, then
44 ///< go through in sequence, using the next
45 ///< function after each failure.
46
47 XLAT_LOAD_BALANCE, //!< Pick a random xlat, and if that fails
48 ///< then the call as a whole fails.
49
50 XLAT_REDUNDANT_LOAD_BALANCE, //!< Pick a random xlat to start, then fail
51 ///< between the other xlats in the redundant
52 ///< group.
54
55typedef struct {
56 fr_dlist_t entry; //!< Entry in the redundant function list.
57 xlat_t const *func; //!< Resolved xlat function.
59
60typedef struct {
61 xlat_redundant_type_t type; //!< Type of redundant xlat expression.
62 fr_dlist_head_t funcs; //!< List of redundant xlat functions.
63 CONF_SECTION *cs; //!< That this redundant xlat list was created from.
65
66typedef struct {
67 xlat_redundant_t *xr; //!< Information about the redundant xlat.
68 xlat_exp_head_t **ex; //!< Array of xlat expressions created by
69 ///< tokenizing the arguments to the redundant
70 ///< xlat, then duplicating them multiple times,
71 ///< one for each xlat function that may be called.
73
74typedef struct {
75 unlang_result_t last_result; //!< Did the last call succeed?
76
77 xlat_exp_head_t **first; //!< First function called.
78 ///< Used for redundant-load-balance.
79 xlat_exp_head_t **current; //!< Last function called, used for redundant xlats.
81
82/** Pass back the result from a single redundant child call
83 *
84 */
86 xlat_ctx_t const *xctx,
87 request_t *request, UNUSED fr_value_box_list_t *in)
88{
90 xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
92
93 if (XLAT_RESULT_SUCCESS(&rctx->last_result)) {
94 done:
95 talloc_free(rctx);
96 return xa;
97 }
98
99 /*
100 * We're at the end, loop back to the start
101 */
102 if (++rctx->current >= (xri->ex + talloc_array_length(xri->ex))) rctx->current = xri->ex;
103
104 /*
105 * We're back to the first one we tried, fail...
106 */
107 if (rctx->current == rctx->first) {
108 fr_strerror_printf("Failed all choices for redundant expansion %s", xctx->ex->fmt);
109 error:
110 xa = XLAT_ACTION_FAIL;
111 goto done;
112 }
113
115
116 /*
117 * Push the next child...
118 */
119 if (unlang_xlat_push(ctx, &rctx->last_result, (fr_value_box_list_t *)fr_dcursor_list(out),
120 request, *rctx->current, UNLANG_SUB_FRAME) < 0) goto error;
121
123}
124
125/** Pass back the result from a single redundant child call
126 *
127 */
129 xlat_ctx_t const *xctx,
130 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
131{
132 xlat_redundant_rctx_t *rctx = talloc_get_type_abort(xctx->rctx, xlat_redundant_rctx_t);
134
135 talloc_free(rctx);
136
137 return xa;
138}
139
140/** xlat "redundant", "load-balance" and "redundant-load-balance" processing
141 *
142 * @ingroup xlat_functions
143 */
145 xlat_ctx_t const *xctx,
146 request_t *request, UNUSED fr_value_box_list_t *in)
147{
150
152
153 switch (xri->xr->type) {
154 /*
155 * Run through each of the redundant functions sequentially
156 * starting at the first.
157 */
158 case XLAT_REDUNDANT:
159 rctx->current = rctx->first = xri->ex; /* First element first */
161 error:
162 talloc_free(rctx);
163 return XLAT_ACTION_FAIL;
164 }
165 break;
166
167 /*
168 * Run a single random redundant function.
169 */
171 rctx->current = rctx->first = &xri->ex[(size_t)fr_rand() % talloc_array_length(xri->ex)]; /* Random start */
173 break;
174
175 /*
176 * Run through each of the redundant functions sequentially
177 * starting at a random element.
178 */
180 rctx->current = rctx->first = &xri->ex[(size_t)fr_rand() % talloc_array_length(xri->ex)]; /* Random start */
182 break;
183
184 default:
185 fr_assert(0);
186 }
187
188 if (unlang_xlat_push(ctx, &rctx->last_result, (fr_value_box_list_t *)fr_dcursor_list(out),
189 request, *rctx->current, UNLANG_SUB_FRAME) < 0) return XLAT_ACTION_FAIL;
190
192}
193
195{
196 xlat_exp_foreach(head, node) {
197 if (node->type == XLAT_BOX) {
198 fr_value_box_mark_safe_for(&node->data, safe_for);
199 continue;
200 }
201
202 if (node->type == XLAT_GROUP) {
203 xlat_mark_safe_for(node->group, safe_for);
204 }
205 }
206}
207
208/** Allocate an xlat node to call an xlat function
209 *
210 * @param[in] ctx to allocate the new node in.
211 * @param[in] func to call.
212 * @param[in] args Arguments to the function. Will be copied,
213 * and freed when the new xlat node is freed.
214 * @param[in] dict the dictionary
215 */
216static xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t const *func, xlat_exp_head_t const *args, fr_dict_t const *dict)
217{
218 xlat_exp_t *node;
219
220 MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, func->name, strlen(func->name)));
221 xlat_exp_set_func(node, func, dict);
222
223 node->flags = func->flags;
224 node->flags.impure_func = !func->flags.pure;
225
226 if (args) {
227 xlat_flags_merge(&node->flags, &args->flags);
228
229 /*
230 * If the function is pure, AND it's arguments are pure,
231 * then remember that we need to call a pure function.
232 */
233 node->flags.can_purify = (func->flags.pure && args->flags.pure) | args->flags.can_purify;
234
235 MEM(node->call.args = xlat_exp_head_alloc(node));
236 node->call.args->is_argv = true;
237
238 if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
239 talloc_free(node);
240 return NULL;
241 }
242 }
243
244 /*
245 * The original tokenizing is done using the redundant xlat argument parser so the boxes need to
246 * have their "safe_for" value changed to the new one.
247 */
248 if (func->args) {
249 xlat_arg_parser_t const *arg_p;
250 xlat_exp_t *arg;
251
253
254 arg = xlat_exp_head(node->call.args);
255
256 for (arg_p = node->call.func->args; arg_p->type != FR_TYPE_NULL; arg_p++) {
257 if (!arg) break;
258
259 xlat_mark_safe_for(arg->group, arg_p->safe_for);
260
261 arg = xlat_exp_next(node->call.args, arg);
262 }
263 }
264
265 return node;
266}
267
268
269/** Allocate additional nodes for evaluation
270 *
271 */
273{
274 xlat_redundant_t *xr = talloc_get_type_abort(xctx->uctx, xlat_redundant_t);
275 xlat_redundant_inst_t *xri = talloc_get_type_abort(xctx->inst, xlat_redundant_inst_t);
276 unsigned int num = 0;
277 xlat_redundant_func_t const *first;
278 fr_dict_t const *dict = NULL;
279
280 MEM(xri->ex = talloc_array(xri, xlat_exp_head_t *, fr_dlist_num_elements(&xr->funcs)));
281 xri->xr = xr;
282
283 first = talloc_get_type_abort(fr_dlist_head(&xr->funcs), xlat_redundant_func_t);
284
285 /*
286 * For each function, create the appropriate xlat
287 * node, and duplicate the child arguments.
288 */
290 xlat_exp_t *node;
292
293 /*
294 * We have to do this here as it only
295 * becomes an error when the user tries
296 * to use the redundant xlat.
297 */
298 if ((!first->func->args && xrf->func->args) ||
299 (first->func->args && !xrf->func->args)) {
300 cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different argument styles "
301 "cannot be used in the same redundant section", first->func->name, xrf->func->name);
302 error:
303 talloc_free(xri->ex);
304 return -1;
305 }
306
307 if (!dict) {
308 dict = xctx->ex->call.dict;
309 fr_assert(dict != NULL);
310
311 } else if (dict != xctx->ex->call.dict) {
312 cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different dictionaries"
313 "cannot be used in the same redundant section", first->func->name, xrf->func->name);
314 goto error;
315 }
316
317 /*
318 * We pass the current arguments in
319 * so that the instantiation functions
320 * for the new node can operate
321 * correctly.
322 */
324 MEM(node = xlat_exp_func_alloc(head, xrf->func, xctx->ex->call.args, dict));
326
327 if (xlat_validate_function_args(node) < 0) {
328 PERROR("Invalid arguments for redundant expansion function \"%s\"",
329 xrf->func->name);
330 goto error;
331 }
332
333 /*
334 * Add the xlat function (and any children)
335 * to the end of the instantiation list so
336 * they'll get called at some point after
337 * we return.
338 */
339 head->flags = node->flags;
340 if (xlat_finalize(head, NULL) < 0) {
341 PERROR("Failed bootstrapping function \"%s\"",
342 xrf->func->name);
343 goto error;
344 }
345 xri->ex[num++] = head;
346 }
347
348 /*
349 * Free the original argument nodes so they're
350 * not evaluated when the redundant xlat is called.
351 *
352 * We need to re-evaluate the arguments for each
353 * redundant function call we perform.
354 *
355 * The xlat_exp_func_alloc call above associates
356 * a copy of the original arguments with each
357 * function that's called.
358 */
359 fr_dlist_talloc_free(&xctx->ex->call.args->dlist);
360
361 return 0;
362}
363
368
369static inline CC_HINT(always_inline)
371{
373
374 MEM(xrf = talloc_zero(xr, xlat_redundant_func_t));
375 xrf->func = x;
376 fr_dlist_insert_tail(&xr->funcs, xrf);
377}
378
379/** Compare two module_rlm_xlat_t based on whether they have the same name
380 *
381 * @note If the two xlats both have the same name as the module that registered them,
382 * then they are considered equal.
383 */
384static fr_cmp_ret_t module_xlat_cmp(void const *a, void const *b)
385{
388 char const *a_p, *b_p;
389
390 /*
391 * A null result means a self-named module xlat,
392 * which is always equal to another self-named
393 * module xlat.
394 */
395 a_p = strchr(mrx_a->xlat->name, '.');
396 b_p = strchr(mrx_b->xlat->name, '.');
397 if (!a_p && !b_p) return CMP_EQ;
398
399 /*
400 * Compare the bit after the module name
401 */
402 if (!a_p || !b_p) return CMP(a_p, b_p);
403
404 return CMP(strcmp(a_p, b_p), 0);
405}
406
407/** An xlat of a redundant section, with the position of the module
408 */
409typedef struct {
410 module_rlm_xlat_t const *mrx; //!< xlat registered by the module.
411 unsigned int position; //!< Position of the module in the section.
413
414/** Order the xlats of a redundant section by name, then by module position
415 *
416 * The in-order walk of the tree sets the order in which a redundant
417 * xlat tries the modules. A tie-break on the address of the module
418 * instance makes the order follow the heap instead of the section.
419 */
420static fr_cmp_ret_t xlat_redundant_member_cmp(void const *a, void const *b)
421{
422 fr_cmp_ret_t ret;
423
426
427 ret = module_xlat_cmp(member_a->mrx, member_b->mrx);
428 if (ret != 0) return ret;
429
430 return CMP(member_a->position, member_b->position);
431}
432
433/** Registers a redundant xlat
434 *
435 * These xlats wrap the xlat methods of the modules in a redundant section,
436 * emulating the behaviour of a redundant section, but over xlats.
437 *
438 * @return
439 * - 0 on success.
440 * - -1 on error.
441 * - 1 if the modules in the section do not have an xlat method.
442 */
444{
445 static fr_table_num_sorted_t const xlat_redundant_type_table[] = {
446 { L("load-balance"), XLAT_LOAD_BALANCE },
447 { L("redundant"), XLAT_REDUNDANT },
448 { L("redundant-load-balance"), XLAT_REDUNDANT_LOAD_BALANCE },
449 };
450 static size_t xlat_redundant_type_table_len = NUM_ELEMENTS(xlat_redundant_type_table);
451
452 char const *name1;
453 xlat_redundant_type_t xr_type;
454 xlat_func_flags_t default_flags = XLAT_FUNC_FLAG_NONE; /* Prevent warnings about default flags if xr_rype is corrupt */
455
456 fr_type_t return_type = FR_TYPE_NULL;
457
458 CONF_ITEM *ci = NULL;
459 int children = 0;
460 unsigned int position = 0;
461 module_instance_t const **seen; /* Modules already in the section */
462 fr_rb_tree_t *mrx_tree; /* Temporary tree for ordering xlats */
463
464 name1 = cf_section_name1(cs);
465 xr_type = fr_table_value_by_str(xlat_redundant_type_table, name1, XLAT_REDUNDANT_INVALID);
466 switch (xr_type) {
468 cf_log_err(cs, "Invalid redundant section verb \"%s\"", name1);
469 return -1;
470
471 case XLAT_REDUNDANT:
472 default_flags = XLAT_FUNC_FLAG_PURE; /* Can be pure */
473 break;
474
476 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
477 break;
478
480 default_flags = XLAT_FUNC_FLAG_NONE; /* Can never be pure because of random selection */
481 break;
482 }
483
484 /*
485 * Count the children
486 */
487 while ((ci = cf_item_next(cs, ci))) {
488 if (!cf_item_is_pair(ci)) continue;
489
490 children++;
491 }
492
493 /*
494 * There must be at least one child.
495 *
496 * It's useful to allow a redundant section with only one
497 * child, for debugging.
498 */
499 if (children == 0) {
500 cf_log_err(cs, "%s %s { ... } section must contain at least one module",
502 return -1;
503 }
504
505 /*
506 * Resolve all the modules in the redundant section,
507 * and insert all the mrx into a temporary tree to
508 * order them.
509 *
510 * Next we'll iterate over all the mrx, creating
511 * redundant xlats from contiguous runs of mrxs
512 * pointing to the same xlat.
513 */
515 MEM(seen = talloc_zero_array(mrx_tree, module_instance_t const *, children));
516 for (ci = cf_item_next(cs, NULL);
517 ci;
518 ci = cf_item_next(cs, ci)) {
521 char const *name;
522
523 if (!cf_item_is_pair(ci)) continue;
524
526
528 if (!mi) {
529 cf_log_err(ci, "Module '%s' not found. Referenced in %s %s { ... } section",
531 error:
532 talloc_free(mrx_tree);
533 return -1;
534 }
535
536 for (unsigned int i = 0; i < position; i++) {
537 if (seen[i] != mi) continue;
538
539 cf_log_err(cs, "Module '%s' referenced multiple times in %s %s { ... } section",
541 goto error;
542 }
543 seen[position] = mi;
544
545 mri = talloc_get_type_abort(mi->uctx, module_rlm_instance_t);
546 fr_dlist_foreach(&mri->xlats, module_rlm_xlat_t const, mrx) {
548
549 MEM(member = talloc(mrx_tree, xlat_redundant_member_t));
550 *member = (xlat_redundant_member_t) {
551 .mrx = mrx,
552 .position = position
553 };
554 if (fr_rb_insert(mrx_tree, member) != 0) {
555 cf_log_err(cs, "Failed ordering expansions of module '%s' in %s %s { ... } section",
556 mrx->mi->name, cf_section_name1(cs), cf_section_name2(cs));
557 goto error;
558 }
559 }
560 position++;
561 }
562
563 if (fr_rb_num_elements(mrx_tree) == 0) {
564 cf_log_debug(cs, "No expansions exported by modules in %s %s { ... } section, "
565 "not registering redundant/load-balance expansion",
567 talloc_free(mrx_tree);
568 return 0;
569 }
570
571 /*
572 * Iterate over the xlats registered for the first module,
573 * verifying that the other module instances have all registered
574 * the similarly named xlat functions.
575 *
576 * We ignore any xlat functions that aren't available in all the
577 * modules.
578 */
579 {
582 fr_sbuff_marker_t name_start;
585 module_rlm_xlat_t const *mrx, *prev_mrx;
587
588 FR_SBUFF_TALLOC_THREAD_LOCAL(&name, 128, SIZE_MAX);
589
590 /*
591 * Prepopulate the name buffer with <section_name2>.
592 * as every function wil be registered with this
593 * prefix.
594 */
596 (fr_sbuff_in_char(name, '.') <= 0)) {
597 cf_log_perr(cs, "Name too long");
598 goto error;
599 }
600
601 fr_sbuff_marker(&name_start, name);
602
603 /*
604 * Iterate over the all the xlats, registered by
605 * all the modules in the section.
606 */
607 member = fr_rb_iter_init_inorder(mrx_tree, &iter);
608
609 while (member) {
610 xlat_t *xlat;
611 xlat_func_flags_t flags = default_flags;
612 char const *name_p;
613
614 mrx = member->mrx;
615 mi = mrx->mi;
616
617 /*
618 * Where the xlat name is in the format <mod>.<name2>
619 * then the redundant xlat will be <section_name2>.<xlat_name>.
620 *
621 * Where the xlat has no '.', it's likely just the module
622 * name, in which case we just use <section_name2>.
623 */
624 name_p = strchr(mrx->xlat->name, '.');
625 if (name_p) {
626 name_p++;
627 fr_sbuff_set(name, &name_start); /* Reset the aggregation buffer to the '.' */
628 if (fr_sbuff_in_bstrncpy(name, name_p, strlen(name_p)) < 0) {
629 cf_log_perr(cs, "Name too long");
630 goto error;
631 }
632 name_p = fr_sbuff_start(name);
633 } else {
634 name_p = cf_section_name2(cs);
635 }
636
637 MEM(xr = talloc_zero(NULL, xlat_redundant_t));
638 xr->type = xr_type;
639 xr->cs = cs;
641
642 /*
643 * Iterate over all the xlats registered by all the modules
644 * in the section, when we reach the end of a run of common
645 * xlats, we register the redundant xlat.
646 *
647 * Note: Just because a xlat function has the same name,
648 * it does not mean the function signature is compatible.
649 *
650 * These issues are caught when we instantiate a redundant
651 * xlat, as the arguments passed to the redunant xlat are
652 * validated against the argument definitions for each
653 * individual xlat the redunant xlat would call.
654 */
655 do {
656 if (!mrx->xlat->flags.pure) flags &= ~XLAT_FUNC_FLAG_PURE;
658 prev_mrx = mrx;
659
660 member = fr_rb_iter_next_inorder(mrx_tree, &iter);
661 if (!member) break;
662 mrx = member->mrx;
663 } while (module_xlat_cmp(prev_mrx, mrx) == 0);
664
665 /*
666 * Warn, but allow, redundant/failover expansions that are
667 * neither redundant, nor failover.
668 *
669 * Sometimes useful to comment out modules during testing.
670 */
671 if (fr_dlist_num_elements(&xr->funcs) == 1) {
672 cf_log_warn(cs, "%s expansion has no alternates, only %s",
673 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
674 ((xlat_redundant_func_t *)fr_dlist_head(&xr->funcs))->func->name);
675
676 }
677
678 /*
679 * Register the new redundant xlat, and hang it off of
680 * the first module instance in the section.
681 *
682 * This isn't great, but at least the xlat should
683 * get unregistered at about the right time.
684 */
685 xlat = xlat_func_register(mi, name_p, xlat_redundant, return_type);
686 if (unlikely(xlat == NULL)) {
687 cf_log_err(cs, "Registering expansion for %s section failed",
688 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"));
689 talloc_free(xr);
690 goto error;
691 }
692 talloc_steal(xlat, xr); /* redundant xlat should own its own config */
693
694 cf_log_debug(cs, "Registered %s expansion \"%s\" with %u alternates",
695 fr_table_str_by_value(xlat_redundant_type_table, xr->type, "<INVALID>"),
696 xlat->name, fr_dlist_num_elements(&xr->funcs));
697
698 xlat_func_flags_set(xlat, flags);
701 }
702 }
703 talloc_free(mrx_tree);
704
705 return 0;
706}
va_list args
Definition acutest.h:923
static uint8_t request[4]
#define RCSID(id)
Definition build.h:603
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#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:130
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
#define NUM_ELEMENTS(_t)
Definition build.h:437
fr_cmp_ret_t
Result of an ordering comparison.
Definition build.h:113
@ CMP_EQ
a == b
Definition build.h:116
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:619
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1405
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1391
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:651
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition cf_util.c:1742
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_item_next(_parent, _curr)
Definition cf_util.h:91
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:347
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:341
#define cf_log_debug(_cf, _fmt,...)
Definition cf_util.h:343
fr_dict_t * dict
Definition common.c:31
#define fr_dcursor_list(_cursor)
Definition dcursor.h:812
#define MEM(x)
Definition debug.h:38
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:468
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
Definition dlist.h:98
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
Definition dlist.h:892
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:921
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:360
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:257
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_free(hp)
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:2053
#define UNLANG_SUB_FRAME
Definition interpret.h:37
#define PERROR(_fmt,...)
Definition log.h:233
fr_type_t
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VOID
User data.
unsigned char uint8_t
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:814
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:37
static bool done
Definition radclient.c:80
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:128
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:807
void * fr_rb_iter_init_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Initialise an in-order iterator.
Definition rb.c:850
int fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:637
void * fr_rb_iter_next_inorder(UNUSED fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:876
#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:203
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:319
The main red black tree structure.
Definition rb.h:71
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:1553
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:1573
#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)
char const * name
Instance name e.g. user_database.
Definition module.h:361
void * uctx
Extra data passed to module_instance_alloc.
Definition module.h:365
Module instance data.
Definition module.h:291
@ FR_SIGNAL_NONE
No signals.
Definition signal.h:39
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
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:117
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:543
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, 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:269
fr_type_t type
Type to cast argument to.
Definition xlat.h:145
unsigned int pure
has no external side effects, true for BOX, LITERAL, and some functions
Definition xlat.h:110
int xlat_validate_function_args(xlat_exp_t *node)
unsigned int impure_func
xlat contains an impure function
Definition xlat.h:111
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
fr_value_box_escape_func_t func
Function to escape unsafe values.
Definition xlat.h:146
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
Definition xlat.h:127
static fr_slen_t head
Definition xlat.h:410
#define XLAT_RESULT_SUCCESS(_p_result)
Definition xlat.h:492
fr_value_box_safe_for_t safe_for
Escaped value to set for boxes processed by this escape function.
Definition xlat.h:147
#define xlat_copy(_ctx, _out, _in)
Definition xlat.h:447
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:160
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:699
unsigned int can_purify
if the xlat has a pure function with pure arguments.
Definition xlat.h:112
Definition for a single argument consumed by an xlat function.
Definition xlat.h:135
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_sbuff_err_t char size_t fr_sbuff_t * in
Definition value.h:1061
#define fr_value_box_mark_safe_for(_box, _safe_for)
Definition value.h:1124
static fr_sbuff_err_t char ** out
Definition value.h:1061
uintptr_t fr_value_box_safe_for_t
Escaping that's been applied to a value box.
Definition value.h:167
void xlat_exp_set_func(xlat_exp_t *node, xlat_t const *func, fr_dict_t const *dict)
Set the function for a node.
Definition xlat_alloc.c:300
void * rctx
Resume context.
Definition xlat_ctx.h:54
xlat_exp_t const * ex
Tokenized expression.
Definition xlat_ctx.h:55
xlat_exp_t * ex
Tokenized expression to use in expansion.
Definition xlat_ctx.h:64
void const * inst
xlat instance data.
Definition xlat_ctx.h:50
void * uctx
Passed to the registration function.
Definition xlat_ctx.h:66
void * inst
xlat instance data to populate.
Definition xlat_ctx.h:63
An xlat calling ctx.
Definition xlat_ctx.h:49
An xlat instantiation ctx.
Definition xlat_ctx.h:62
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:401
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:374
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:225
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
Definition xlat_func.h:95
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:276
xlat_flags_t flags
Flags that control resolution and evaluation.
Definition xlat_priv.h:156
@ XLAT_BOX
fr_value_box_t
Definition xlat_priv.h:110
@ XLAT_FUNC
xlat module
Definition xlat_priv.h:112
@ XLAT_GROUP
encapsulated string of xlats
Definition xlat_priv.h:118
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
Definition xlat_priv.h:249
xlat_arg_parser_t const * args
Definition of args consumed.
Definition xlat_priv.h:96
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
Definition xlat_priv.h:232
char const *_CONST fmt
The original format string (a talloced buffer).
Definition xlat_priv.h:153
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
Definition xlat_priv.h:285
xlat_flags_t flags
various flags
Definition xlat_priv.h:94
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
Definition xlat_priv.h:225
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
Definition xlat_priv.h:241
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
Definition xlat_priv.h:212
An xlat expansion node.
Definition xlat_priv.h:150
static fr_cmp_ret_t module_xlat_cmp(void const *a, void const *b)
Compare two module_rlm_xlat_t based on whether they have the same name.
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.
module_rlm_xlat_t const * mrx
xlat registered by the module.
static xlat_arg_parser_t const xlat_redundant_args[]
fr_dlist_head_t funcs
List of redundant xlat functions.
fr_dlist_t entry
Entry in the redundant function list.
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.
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 fr_cmp_ret_t xlat_redundant_member_cmp(void const *a, void const *b)
Order the xlats of a redundant section by name, then by module position.
static void xlat_mark_safe_for(xlat_exp_head_t *head, fr_value_box_safe_for_t safe_for)
unlang_result_t last_result
Did the last call succeed?
unsigned int position
Position of the module in the section.
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.
static xlat_exp_t * xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t const *func, xlat_exp_head_t const *args, fr_dict_t const *dict)
Allocate an xlat node to call an xlat function.
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.
An xlat of a redundant section, with the position of the module.