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) {
218typedef enum CC_HINT(flag_enum) {
282#define unlang_frame_perf_init(_x)
283#define unlang_frame_perf_yield(_x)
284#define unlang_frame_perf_resume(_x)
285#define unlang_frame_perf_cleanup(_x)
383#define MOD_NUM_TYPES (UNLANG_TYPE_XLAT + 1)
408#define has_debug_braces(_thing) \
410 unlang_t *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
411 unlang_t const *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
412 unlang_stack_frame_t *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)), \
413 unlang_stack_frame_t const *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)) \
439 for (i =
stack->depth; i > 0; i--) {
442 if (frame->
flag & flag)
return i;
457 for (i =
stack->depth; i > 0; i--) {
481 for (i =
depth; i >= to_depth; i--) {
482 frame = &
stack->frame[i];
508 if (depth_p) *depth_p =
stack->depth + 1;
514 if (depth_p) *depth_p =
depth;
576#ifdef HAVE_TALLOC_ZERO_POOLED_OBJECT
594 talloc_set_name_const(frame->
state,
name);
619 talloc_free_children(frame->
state);
620 TALLOC_FREE(frame->
state);
677 TALLOC_FREE(frame->
retry);
684 request->log.indent = frame->
indent;
728 frame->
next = unlang;
769 CC_HINT(warn_unused_result);
773 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 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 char * stack[MAX_STACK]
static uint8_t depth(fr_minmax_heap_index_t i)
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).
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
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.
size_t frame_state_pool_objects
How many sub-allocations we expect.
void unlang_register(int type, unlang_op_t *op)
Register an operation with the interpreter.
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.
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.
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.
char const * frame_state_type
talloc name of the frame instance data
char const * type_name
Talloc type name.
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.
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)
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)
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)
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.
#define unlang_frame_perf_init(_x)
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
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 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.
static bool is_rcode_set(unlang_stack_frame_t const *frame)
size_t len
Total length of the unlang_group_t + specialisation struct.
size_t mod_action_table_len
void unlang_try_init(void)
static bool is_yielded(unlang_stack_frame_t const *frame)
void unlang_catch_init(void)
size_t frame_state_pool_size
The total size of the pool to alloc.
unlang_type_t type
Keyword.
static void top_frame_set(unlang_stack_frame_t *frame)
unlang_variable_t * variables
rarely used, so we don't usually need it
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
char const * name
Name of the operation.
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)
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)
size_t pool_len
How much additional space to allocate for extensions.
unsigned pool_headers
How much additional space to allocate for chunk headers.
#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
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_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_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_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,...
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.
unlang_op_flag_t flag
Flags for this operation.
static bool is_unwinding(unlang_stack_frame_t const *frame)
void * thread_inst
thread-specific instance data
Describes how to allocate an unlang_group_t with additional memory keyword specific data.
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.