28#include <freeradius-devel/server/cf_util.h>
29#include <freeradius-devel/server/map_proc.h>
30#include <freeradius-devel/server/modpriv.h>
31#include <freeradius-devel/server/time_tracking.h>
32#include <freeradius-devel/util/debug.h>
33#include <freeradius-devel/unlang/base.h>
34#include <freeradius-devel/io/listen.h>
97#define UNLANG_NEXT_STOP (false)
98#define UNLANG_NEXT_SIBLING (true)
100#define UNLANG_DETACHABLE (true)
101#define UNLANG_NORMAL_CHILD (false)
104typedef enum CC_HINT(flag_enum) {
218#define UNLANG_IGNORE ((unlang_t *) -1)
245static inline CC_HINT(always_inline)
258 memset(&dst->actions.retry, 0,
sizeof(dst->actions.retry)); \
278#define RULES_VERIFY(_rules) do { if (unlang_rules_verify(_rules) < 0) return NULL; } while (0)
280#define RULES_VERIFY(_rules)
284typedef enum CC_HINT(flag_enum) {
362#define unlang_frame_perf_init(_x)
363#define unlang_frame_perf_yield(_x)
364#define unlang_frame_perf_resume(_x)
365#define unlang_frame_perf_cleanup(_x)
464#define MOD_NUM_TYPES (UNLANG_TYPE_XLAT + 1)
489#define has_debug_braces(_thing) \
491 unlang_t *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
492 unlang_t const *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
493 unlang_stack_frame_t *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)), \
494 unlang_stack_frame_t const *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)) \
520 for (i =
stack->depth; i > 0; i--) {
523 if (frame->
flag & flag)
return i;
538 for (i =
stack->depth; i > 0; i--) {
562 for (i =
depth; i >= to_depth; i--) {
563 frame = &
stack->frame[i];
589 if (depth_p) *depth_p =
stack->depth + 1;
595 if (depth_p) *depth_p =
depth;
657#ifdef HAVE_TALLOC_ZERO_POOLED_OBJECT
675 talloc_set_name_const(frame->
state,
name);
699 TALLOC_FREE(frame->
retry);
701 talloc_free_children(frame->
state);
702 TALLOC_FREE(frame->
state);
759 TALLOC_FREE(frame->
retry);
766 request->log.indent = frame->
indent;
810 frame->
next = unlang;
851 CC_HINT(warn_unused_result);
855 CC_HINT(warn_unused_result);
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
fr_dict_t const * fr_dict_internal(void)
#define UNLANG_STACK_MAX
The maximum depth of the stack.
unlang_mod_action_t priority
The priority or action for that rcode.
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Configuration structure to make it easier to pass configuration options to initialise the frame with.
static TALLOC_CTX * unlang_ctx
static char * stack[MAX_STACK]
static uint8_t depth(fr_minmax_heap_index_t i)
@ MOD_ACTION_NOT_SET
default "not set by anything"
@ MOD_ACTION_RETRY
retry the instruction, MUST also set a retry config
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
bool at_runtime
Produce an ephemeral/runtime tmpl.
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Optional arguments passed to vp_tmpl functions.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
@ FR_SIGNAL_CANCEL
Request has been cancelled.
fr_aka_sim_id_type_t type
Define entry and head types for tmpl request references.
uint8_t allow_foreign
Allow arguments not found in dict_def.
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
An element in a lexicographically sorted array of name to num mappings.
#define talloc_get_type_abort_const
#define unlang_frame_perf_resume(_x)
void stack_dump_with_actions(request_t *request)
unlang_result_t section_result
The aggregate result of executing all siblings in this section.
static unlang_action_t unwind_to_op_flag(unsigned int *depth_p, unlang_stack_t *stack, unlang_op_flag_t flag)
Mark the entire stack as cancelled.
unlang_t * unlang_compile_children(unlang_group_t *g, unlang_compile_ctx_t *unlang_ctx)
size_t frame_state_pool_objects
How many sub-allocations we expect.
static void frame_pop(request_t *request, unlang_stack_t *stack)
Pop a stack frame, removing any associated dynamically allocated state.
unlang_t * next
Next node (executed on UNLANG_ACTION_EXECUTE_NEXT et al).
static void frame_next(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Advance to the next sibling instruction.
@ UNLANG_FRAME_FLAG_TOP_FRAME
are we the top frame of the stack? If true, causes the interpreter to stop interpreting and return,...
@ UNLANG_FRAME_FLAG_REPEAT
Repeat the frame on the way up the stack.
@ UNLANG_FRAME_FLAG_NONE
No flags.
@ UNLANG_FRAME_FLAG_UNWIND
This frame should be unwound without evaluation.
@ UNLANG_FRAME_FLAG_YIELDED
frame has yielded
void unlang_switch_init(void)
unlang_result_t * result_p
Where to write the result of executing the current instruction.
static bool _instruction_has_debug_braces(unlang_t const *instruction)
static unsigned int unlang_frame_by_flag(unlang_stack_t *stack, unlang_frame_flag_t flag)
Find the first frame with a given flag.
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
static bool is_cancellable(unlang_stack_frame_t const *frame)
static bool is_repeatable(unlang_stack_frame_t const *frame)
unlang_interpret_t * intp
Interpreter that the request is currently associated with.
static void frame_result_set(unlang_result_t *result_p, unlang_stack_frame_t *frame)
Initialise the result fields in a frame.
static void repeatable_clear(unlang_stack_frame_t *frame)
static unlang_action_t unwind_to_depth(unlang_stack_t *stack, unsigned int to_depth)
Mark up frames as cancelled so they're immediately popped by the interpreter.
bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
unlang_retry_t * retry
if the frame is being retried.
void unlang_finally_init(void)
unlang_signal_t signal
function to call when signalling this stack frame
char const * debug_name
Printed in log messages when the node is executed.
unlang_mod_actions_t actions
char const * frame_state_type
talloc name of the frame instance data
void * state
Stack frame specialisations.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
void(* unlang_signal_t)(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Function to call if the request was signalled.
virtual_server_t const * vs
Virtual server we're compiling in the context of.
tmpl_rules_t const * rules
bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
unlang_t * parent
Previous node.
static unsigned int unlang_frame_by_op_flag(unlang_stack_t *stack, unlang_op_flag_t flag)
Find the first frame with a given flag.
void unlang_limit_init(void)
bool unlang_compile_limit_subsection(CONF_SECTION *cs, char const *name)
unlang_signal_t signal
Function to signal stop / dup / whatever.
int unlang_subrequest_op_init(void)
Initialise subrequest ops.
size_t frame_state_size
size of instance data in the stack frame
static void unwind_set(unlang_stack_frame_t *frame)
unlang_t *(* unlang_compile_t)(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
char const * thread_inst_type
fr_dict_attr_t const * root
the root of our dictionary
int(* unlang_thread_instantiate_t)(unlang_t const *instruction, void *thread_inst)
void unlang_timeout_init(void)
size_t pool_len
How much additional space to allocate for chunks.
static void frame_state_init(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Initialise memory and instruction for a frame when a new instruction is to be evaluated.
static void unlang_compile_ctx_copy(unlang_compile_ctx_t *dst, unlang_compile_ctx_t const *src)
#define unlang_frame_perf_init(_x)
unlang_t * unlang_compile_empty(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
void unlang_edit_init(void)
void stack_dump(request_t *request)
void unlang_tmpl_init(void)
void unlang_call_init(void)
void unlang_map_init(void)
bool closed
whether or not this section is closed to new statements
unlang_dump_t dump
Dump additional information about the frame state.
static bool _frame_has_debug_braces(unlang_stack_frame_t const *frame)
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
void unlang_condition_init(void)
rindent_t indent
Indent level of the request when the frame was created.
uint8_t unwind
Unwind to this frame if it exists.
unlang_t ** tail
pointer to the tail which gets updated
static void top_frame_clear(unlang_stack_frame_t *frame)
unlang_process_t interpret
Function to interpret the keyword.
fr_table_num_sorted_t const mod_action_table[]
unlang_result_t scratch_result
The result of executing the current instruction.
int depth
of this retry structure
char const * unlang_name
Talloc type name for the unlang_t.
static void frame_cleanup(unlang_stack_frame_t *frame)
Cleanup any lingering frame state.
static unlang_t * unlang_tmpl_to_generic(unlang_tmpl_t const *p)
void unlang_op_free(void)
void unlang_load_balance_init(void)
CONF_ITEM * ci
used to generate this item
static bool is_top_frame(unlang_stack_frame_t const *frame)
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
void(* unlang_dump_t)(request_t *request, unlang_stack_frame_t *frame)
Custom callback for dumping information about frame state.
unsigned int number
unique node number
void unlang_group_init(void)
size_t unlang_size
Total length of the unlang_t + specialisation struct.
char const * section_name1
size_t mod_rcode_table_len
void unlang_parallel_init(void)
static unlang_stack_frame_t * frame_current(request_t *request)
void unlang_transaction_init(void)
static bool is_private_result(unlang_stack_frame_t const *frame)
int depth
Current depth we're executing at.
char const * name
Unknown...
request_t * unlang_io_subrequest_alloc(request_t *parent, fr_dict_t const *namespace, bool detachable)
Allocate a child request based on the parent.
static int stack_depth_current(request_t *request)
static bool is_break_point(unlang_stack_frame_t const *frame)
static void unwind_clear(unlang_stack_frame_t *frame)
void unlang_return_init(void)
void unlang_detach_init(void)
Initialise subrequest ops.
unlang_type_t
Types of unlang_t nodes.
@ UNLANG_TYPE_SWITCH
Switch section.
@ UNLANG_TYPE_TRANSACTION
transactions for editing lists
@ UNLANG_TYPE_FINALLY
run at the end of a virtual server.
@ UNLANG_TYPE_SUBREQUEST
create a child subrequest
@ UNLANG_TYPE_CONTINUE
Break statement (within a UNLANG_TYPE_FOREACH).
@ UNLANG_TYPE_UPDATE
Update block.
@ UNLANG_TYPE_ELSIF
!Condition && Condition.
@ UNLANG_TYPE_ELSE
!Condition.
@ UNLANG_TYPE_LOAD_BALANCE
Load balance section.
@ UNLANG_TYPE_DETACH
detach a child
@ UNLANG_TYPE_GROUP
Grouping section.
@ UNLANG_TYPE_POLICY
Policy section.
@ UNLANG_TYPE_TMPL
asynchronously expand a tmpl_t
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
@ UNLANG_TYPE_LIMIT
limit number of requests in a section
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH or UNLANG_TYPE_CASE).
@ UNLANG_TYPE_TRY
try / catch blocks
@ UNLANG_TYPE_CALL
call another virtual server
@ UNLANG_TYPE_RETURN
Return statement.
@ UNLANG_TYPE_REDUNDANT
exactly like group, but with different default return codes
@ UNLANG_TYPE_IF
Condition.
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
@ UNLANG_TYPE_NULL
unlang type not set.
@ UNLANG_TYPE_MAP
Mapping section (like UNLANG_TYPE_UPDATE, but uses values from a map_proc_t call).
@ UNLANG_TYPE_CALLER
conditionally check parent dictionary type
@ UNLANG_TYPE_TIMEOUT
time-based timeouts.
@ UNLANG_TYPE_MODULE
Module method.
@ UNLANG_TYPE_REDUNDANT_LOAD_BALANCE
Redundant load balance section.
@ UNLANG_TYPE_CHILD_REQUEST
a frame at the top of a child's request stack used to signal the parent when the child is complete.
@ UNLANG_TYPE_CATCH
catch a previous try
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
@ UNLANG_TYPE_EDIT
edit VPs in place. After 20 years!
@ UNLANG_TYPE_FOREACH
Foreach section.
@ UNLANG_TYPE_PARALLEL
execute statements in parallel
static void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
Mark the current stack frame up for repeat, and set a new process function.
unlang_t const * instruction
The unlang node we're evaluating.
unsigned pool_headers
How much additional space to allocate for chunk headers.
static bool is_rcode_set(unlang_stack_frame_t const *frame)
size_t mod_action_table_len
void unlang_try_init(void)
static bool is_yielded(unlang_stack_frame_t const *frame)
fr_hash_table_t * unlang_op_table
void unlang_catch_init(void)
size_t frame_state_pool_size
The total size of the pool to alloc.
unlang_compile_t compile
compile the keyword
static void top_frame_set(unlang_stack_frame_t *frame)
unlang_variable_t * variables
rarely used, so we don't usually need it
unlang_type_t type
enum value for the keyword
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
Push a new frame onto the stack.
static unlang_tmpl_t * unlang_generic_to_tmpl(unlang_t const *p)
void unlang_module_init(void)
unlang_t const * instruction
instruction which we're executing
bool pass2_fixup_map(map_t *map, tmpl_rules_t const *rules, fr_dict_attr_t const *parent)
Fixup ONE map (recursively)
char const * name
Name of the keyword.
unlang_frame_action_t
Allows the frame evaluator to signal the interpreter.
@ UNLANG_FRAME_ACTION_POP
Pop the current frame, and check the next one further up in the stack for what to do next.
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
static void yielded_set(unlang_stack_frame_t *frame)
static bool is_continue_point(unlang_stack_frame_t const *frame)
bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
static unlang_action_t frame_set_next(unlang_stack_frame_t *frame, unlang_t *unlang)
void unlang_function_init(void)
static void yielded_clear(unlang_stack_frame_t *frame)
#define unlang_frame_perf_yield(_x)
#define unlang_frame_perf_cleanup(_x)
unlang_t const * next
The next unlang node we will evaluate.
unlang_op_t unlang_ops[]
Different operations the interpreter can execute.
fr_table_num_sorted_t const mod_rcode_table[]
int max_attr
1..N local attributes have been defined
static int unlang_attr_rules_verify(tmpl_attr_rules_t const *rules)
unlang_thread_instantiate_t thread_instantiate
per-thread instantiation function
fr_dict_t * dict
our dictionary
void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
Delivers a frame to one or more frames in the stack.
void * unlang_thread_instance(unlang_t const *instruction)
Get the thread-instance data for an instruction.
static bool is_return_point(unlang_stack_frame_t const *frame)
@ UNLANG_OP_FLAG_RETURN_POINT
Return point.
@ UNLANG_OP_FLAG_NO_FORCE_UNWIND
Must not be cancelled.
@ UNLANG_OP_FLAG_SINGLE_WORD
the operation is parsed and compiled as a single word
@ UNLANG_OP_FLAG_CONTINUE_POINT
Continue point.
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_NONE
No flags.
@ UNLANG_OP_FLAG_RCODE_SET
Set request->rcode to the result of this operation.
@ UNLANG_OP_FLAG_INTERNAL
it's not a real keyword
@ UNLANG_OP_FLAG_BREAK_POINT
Break point.
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_action_t(* unlang_process_t)(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Function to call when interpreting a frame.
void unlang_foreach_init(void)
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
void unlang_caller_init(void)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
unlang_t * children
Children beneath this group.
unlang_frame_flag_t flag
Flags that mark up the frame for various things such as being the point where break,...
char const * section_name2
unlang_action_t unlang_interpret_push_children(unlang_result_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
Push the children of the current frame onto a new frame onto the stack.
int unlang_define_local_variable(CONF_ITEM *ci, unlang_variable_t *var, tmpl_rules_t *t_rules, fr_type_t type, char const *name, fr_dict_attr_t const *ref)
unlang_op_flag_t flag
Interpreter flags for this operation.
static bool is_unwinding(unlang_stack_frame_t const *frame)
void * thread_inst
thread-specific instance data
static int unlang_rules_verify(tmpl_rules_t const *rules)
Generic representation of a grouping.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.