25RCSID(
"$Id: 16425de27b49c2d8ccaf3c90bb7b5852fcac0893 $")
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>
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>
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>
210 node->call.func = func;
255 unsigned int num = 0;
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);
294 switch (xrf->func->input_type) {
300 PERROR(
"Invalid arguments for redundant expansion function \"%s\"",
315 PERROR(
"Failed bootstrapping function \"%s\"",
343static inline CC_HINT(always_inline)
362 char const *a_p, *b_p;
369 a_p = strchr(mrx_a->
xlat->
name,
'.');
370 b_p = strchr(mrx_b->
xlat->
name,
'.');
371 if (!a_p && !b_p)
return 0;
376 if (!a_p || !b_p)
return CMP(a_p, b_p);
378 return CMP(strcmp(a_p, b_p), 0);
389 if (ret != 0)
return ret;
391 return CMP(mrx_a->
mi, mrx_b->
mi);
411 static size_t xlat_redundant_type_table_len =
NUM_ELEMENTS(xlat_redundant_type_table);
427 cf_log_err(cs,
"Invalid redundant section verb \"%s\"", name1);
459 cf_log_err(cs,
"%s %s { ... } section must contain at least one module",
487 cf_log_err(ci,
"Module '%s' not found. Referenced in %s %s { ... } section",
497 cf_log_err(cs,
"Module '%s' referenced multiple times in %s %s { ... } section",
505 cf_log_debug(cs,
"No expansions exported by modules in %s %s { ... } section, "
506 "not registering redundant/load-balance expansion",
541 fr_sbuff_marker(&name_start,
name);
563 name_p = strchr(mrx->
xlat->
name,
'.');
607 cf_log_warn(cs,
"%s expansion has no alternates, only %s",
622 cf_log_err(cs,
"Registering expansion for %s section failed",
627 talloc_steal(xlat, xr);
629 cf_log_debug(cs,
"Registered %s expansion \"%s\" with %u alternates",
#define L(_str)
Helper for initialising arrays of string literals.
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_perr(_cf, _fmt,...)
#define cf_log_warn(_cf, _fmt,...)
#define cf_log_debug(_cf, _fmt,...)
#define cf_item_next(_ci, _curr)
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.
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Head of a doubly linked list.
Entry in a doubly linked list.
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.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
module_instance_t * module_rlm_static_by_name(module_instance_t const *parent, char const *asked_name)
module_instance_t * mi
The module instance that registered the xlat.
fr_dlist_head_t xlats
xlats registered to this module instance.
xlat_t const * xlat
The xlat function.
An xlat function registered to a module.
uint32_t fr_rand(void)
Return a 32-bit random number.
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
void * fr_rb_iter_init_inorder(fr_rb_iter_inorder_t *iter, fr_rb_tree_t *tree)
Initialise an in-order iterator.
void * fr_rb_iter_next_inorder(fr_rb_iter_inorder_t *iter)
Return the next node.
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
#define fr_rb_talloc_alloc(_ctx, _type, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
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.
ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
#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.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
#define talloc_get_type_abort_const
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.
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.
fr_type_t type
Type to cast argument to.
@ XLAT_ARG_VARIADIC_EMPTY_KEEP
Empty argument groups are left alone, and either passed through as empty groups or null boxes.
fr_value_box_safe_for_t safe_for
Escaped value to set for boxes processed by this escape function.
#define xlat_copy(_ctx, _out, _in)
bool can_purify
if the xlat has a pure function with pure arguments.
@ XLAT_INPUT_ARGS
Ingests a number of arguments.
@ XLAT_INPUT_UNPROCESSED
No input argument processing.
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
#define XLAT_ARG_PARSER_TERMINATOR
int xlat_finalize(xlat_exp_head_t *head, fr_event_list_t *runtime_el)
Bootstrap static xlats, or instantiate ephemeral ones.
@ XLAT_ACTION_FAIL
An xlat function failed.
@ XLAT_ACTION_YIELD
An xlat function pushed a resume frame onto the stack.
@ XLAT_ACTION_PUSH_UNLANG
An xlat function pushed an unlang frame onto the unlang stack.
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
bool impure_func
xlat contains an impure function
Definition for a single argument consumend by an xlat function.
#define fr_value_box_mark_safe_for(_box, _safe_for)
static size_t char ** out
void * rctx
Resume context.
xlat_exp_t * ex
Tokenized expression to use in expansion.
void const * inst
xlat instance data.
void * uctx
Passed to the registration function.
void * inst
xlat instance data to populate.
An xlat instantiation ctx.
void xlat_func_flags_set(xlat_t *x, xlat_func_flags_t flags)
Specify flags that alter the xlat's behaviour.
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
#define xlat_func_instantiate_set(_xlat, _instantiate, _inst_struct, _detach, _uctx)
Set a callback for global instantiation of xlat functions.
char const * name
Name of xlat function.
#define xlat_exp_head_alloc(_ctx)
xlat_flags_t flags
Flags that control resolution and evaluation.
static xlat_exp_t * xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t const *node)
static void xlat_flags_merge(xlat_flags_t *parent, xlat_flags_t const *child)
Merge flags from child to parent.
xlat_input_type_t input_type
Type of input used.
#define xlat_exp_alloc(_ctx, _type, _in, _inlen)
xlat_flags_t flags
various flags
#define xlat_exp_foreach(_list_head, _iter)
Iterate over the contents of a list, only one level.
static int xlat_exp_insert_tail(xlat_exp_head_t *head, xlat_exp_t *node)
static xlat_exp_t * xlat_exp_head(xlat_exp_head_t const *head)
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_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.