For signal functions this is important because all frames are signalled. For process functions it removes significant amounts of boilerplate.
/** Asynchronously add a request_t to a worker thread
*
* When we don't know what the worker is...
+ *
+ * @param[in] request to add.
+ * @param[in] process module method to call when the request is executed.
+ * @param[in] uctx to pass to the process method.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
*/
-int fr_worker_request_add(request_t *request, module_method_t process, void *ctx)
+int fr_worker_request_add(request_t *request, module_method_t process, void *uctx)
{
fr_worker_t *worker;
fr_time_t now;
- if (!request || !process) {
+ if (unlikely(!request || !process)) {
fr_strerror_const("Invalid arguments");
return -1;
}
worker = thread_local_worker;
- if (!worker) {
+ if (unlikely(!worker)) {
fr_strerror_const("No worker has been defined");
return -1;
}
fr_assert(request_is_internal(request));
request->async->process = process;
- request->async->process_inst = ctx;
+ request->async->process_inst = uctx;
worker_request_time_tracking_start(worker, request, now);
fr_assert(request != NULL);
+ /*
+ * Let any signal handler that cares
+ * know that the child is about to
+ * be detached.
+ */
+ unlang_interpret_signal(child, FR_SIGNAL_DETACH);
+
/*
* Unlink the child from the parent.
*/
///< with this, the module should stop processing
///< the request and cleanup anything it's done.
FR_SIGNAL_DUP, //!< A duplicate request was received.
+ FR_SIGNAL_DETACH //!< Request is being detached from its parent.
} fr_state_signal_t;
#ifdef __cplusplus
* @copyright 2016-2019 The FreeRADIUS server project
*/
#include <freeradius-devel/unlang/compile.h>
+#include <freeradius-devel/unlang/function.h>
#include <freeradius-devel/unlang/interpret.h>
#include <freeradius-devel/unlang/module.h>
#include <freeradius-devel/unlang/subrequest.h>
extern "C" {
#endif
-#define UNLANG_STACK_MAX (64) //!< The maximum depth of the stack.
-#define UNLANG_FRAME_PRE_ALLOC (128) //!< How much memory we pre-alloc for each frame.
-
bool unlang_section(CONF_SECTION *cs);
-void unlang_register(int type, unlang_op_t *op);
-
int unlang_init(void);
void unlang_free(void);
#include "call_priv.h"
#include "unlang_priv.h"
-static unlang_action_t unlang_call_process(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_call_process(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_call_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_call_t);
- unlang_t *instruction = frame->instruction;
- unlang_group_t *g = unlang_generic_to_group(instruction);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
rlm_rcode_t rcode;
unlang_action_t ua;
return UNLANG_ACTION_CALCULATE_RESULT;
}
-static unlang_action_t unlang_call_frame_init(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_call_frame_init(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_call_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_call_t);
- unlang_t *instruction = frame->instruction;
-
unlang_group_t *g;
unlang_call_t *gext;
char const *server;
* can still be side effects from executing the virtual
* server.
*/
- g = unlang_generic_to_group(instruction);
+ g = unlang_generic_to_group(frame->instruction);
gext = unlang_group_to_call(g);
server = cf_section_name2(gext->server_cs);
.prev_server_cs = request->server_cs,
};
- return unlang_call_process(p_result, request);
+ return unlang_call_process(p_result, request, frame);
}
/** Push a call to a virtual server onto the stack for evaluation
#include "unlang_priv.h"
#include "group_priv.h"
-static unlang_action_t unlang_caller(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_caller(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
-
- unlang_group_t *g;
- unlang_caller_t *gext;
-
- g = unlang_generic_to_group(instruction);
- gext = unlang_group_to_caller(g);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
+ unlang_caller_t *gext = unlang_group_to_caller(g);
fr_assert(g->num_children > 0); /* otherwise the compilation is broken */
/*
* The dictionary matches. Go recurse into its' children.
*/
- return unlang_group(p_result, request);
+ return unlang_group(p_result, request, frame);
}
#include "group_priv.h"
#include "unlang_priv.h"
-static unlang_action_t unlang_if(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_if(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
int condition;
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
+ unlang_cond_t *gext = unlang_group_to_cond(g);
- unlang_group_t *g;
- unlang_cond_t *gext;
-
- g = unlang_generic_to_group(instruction);
- gext = unlang_group_to_cond(g);
fr_assert(gext->cond != NULL);
condition = cond_eval(request, *p_result, gext->cond);
/*
* We took the "if". Go recurse into its' children.
*/
- return unlang_group(p_result, request);
+ return unlang_group(p_result, request, frame);
}
void unlang_condition_init(void)
return 0;
}
-static unlang_action_t unlang_foreach_next(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_foreach_next(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
fr_pair_t *vp;
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
- unlang_frame_state_foreach_t *foreach = NULL;
- unlang_group_t *g;
-
- g = unlang_generic_to_group(instruction);
-
- foreach = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
-
+ unlang_frame_state_foreach_t *foreach = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
vp = fr_dcursor_current(&foreach->cursor);
if (!vp) {
*p_result = frame->result;
}
-static unlang_action_t unlang_foreach(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_foreach(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame;
- unlang_t *instruction;
unlang_frame_state_foreach_t *foreach = NULL;
-
- unlang_group_t *g;
- unlang_foreach_t *gext;
+ unlang_stack_t *stack = request->stack;
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
+ unlang_foreach_t *gext = unlang_group_to_foreach(g);
int i, foreach_depth = 0;
fr_pair_list_t vps;
- frame = &stack->frame[stack->depth];
fr_pair_list_init(&vps);
- instruction = frame->instruction;
- g = unlang_generic_to_group(instruction);
- gext = unlang_group_to_foreach(g);
/*
* Ensure any breaks terminate here...
* Figure out foreach depth by walking back up the stack
*/
if (stack->depth > 0) for (i = (stack->depth - 1); i >= 0; i--) {
- unlang_t *our_instruction;
+ unlang_t const *our_instruction;
our_instruction = stack->frame[i].instruction;
if (!our_instruction || (our_instruction->type != UNLANG_TYPE_FOREACH)) continue;
foreach_depth++;
return UNLANG_ACTION_CALCULATE_RESULT;
}
- MEM(frame->state = foreach = talloc_zero(stack, unlang_frame_state_foreach_t));
+ MEM(frame->state = foreach = talloc_zero(request->stack, unlang_frame_state_foreach_t));
fr_pair_list_init(&foreach->vps);
/*
talloc_set_destructor(foreach, _free_unlang_frame_state_foreach);
frame->process = unlang_foreach_next;
- return unlang_foreach_next(p_result, request);
+ return unlang_foreach_next(p_result, request, frame);
}
-static unlang_action_t unlang_break(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_break(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
-
- RDEBUG2("%s", unlang_ops[instruction->type].name);
+ RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
*p_result = frame->result;
* Stop at the next break point, or if we hit
* the a top frame.
*/
- return unwind_to_break(stack);
+ return unwind_to_break(request->stack);
}
/** Implements the Foreach-Variable-X
* @file unlang/function.c
* @brief Unlang "function" keyword evaluation.
- * @copyright 2018 The FreeRADIUS server project
- * @copyright 2018 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2018,2021 The FreeRADIUS server project
+ * @copyright 2018,2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
*/
RCSID("$Id$")
#include "unlang_priv.h"
+#include "function.h"
/*
* Some functions differ mainly in their parsing
typedef struct {
unlang_function_t func; //!< To call when going down the stack.
unlang_function_t repeat; //!< To call when going back up the stack.
+ unlang_function_signal_t signal; //!< Signal function to call.
void *uctx; //!< Uctx to pass to function.
} unlang_frame_state_func_t;
}
};
+/** Generic signal handler
+ *
+ * @param[in] request being signalled.
+ * @param[in] frame being signalled.
+ * @param[in] action Type of signal.
+ */
+static void unlang_function_signal(request_t *request,
+ unlang_stack_frame_t *frame, fr_state_signal_t action)
+{
+ unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
+
+ if (!state->signal) return;
+
+ state->signal(request, action, state->uctx);
+}
+
/** Call a generic function
*
- * @param[out] p_result The frame result.
- * @param[in] request The current request.
+ * @param[out] p_result The frame result.
+ * @param[in] request The current request.
+ * @param[in] frame The current frame.
*/
-static unlang_action_t unlang_function_call(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_function_call(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_func_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_func_t);
unlang_action_t ua;
char const *caller;
caller = request->module;
request->module = NULL;
if (!is_repeatable(frame)) {
- ua = state->func(p_result, NULL, request, state->uctx);
+ ua = state->func(p_result, &frame->priority, request, state->uctx);
} else {
- ua = state->repeat(p_result, NULL, request, state->uctx);
+ ua = state->repeat(p_result, &frame->priority, request, state->uctx);
}
request->module = caller;
* @param[in] func to call going up the stack.
* @param[in] repeat function to call going back down the stack (may be NULL).
* This may be the same as func.
+ * @param[in] signal function to call if the request is signalled.
* @param[in] uctx to pass to func.
* @return
* - 0 on success.
* - -1 on failure.
*/
-int unlang_interpret_push_function(request_t *request, unlang_function_t func, unlang_function_t repeat, void *uctx)
+int unlang_interpret_push_function(request_t *request, unlang_function_t func, unlang_function_t repeat,
+ unlang_function_signal_t signal, void *uctx)
{
unlang_stack_t *stack = request->stack;
unlang_stack_frame_t *frame;
state = frame->state;
state->func = func;
state->repeat = repeat;
+ state->signal = signal;
state->uctx = uctx;
return 0;
&(unlang_op_t){
.name = "function",
.interpret = unlang_function_call,
+ .signal = unlang_function_signal,
.debug_braces = false,
.frame_state_size = sizeof(unlang_frame_state_func_t),
.frame_state_name = "unlang_frame_state_func_t",
--- /dev/null
+#pragma once
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * $Id$
+ *
+ * @file unlang/function.h
+ * @brief Declarations for generic unlang functions.
+ *
+ * @copyright 2021 The FreeRADIUS server project
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <freeradius-devel/server/rcode.h>
+#include <freeradius-devel/server/request.h>
+#include <freeradius-devel/server/signal.h>
+
+/** A generic function pushed by a module or xlat to functions deeper in the C call stack to create resumption points
+ *
+ * @param[in] request The current request.
+ * @param[in,out] uctx Provided by whatever pushed the function. Is opaque to the
+ * interpreter, but should be usable by the function.
+ * All input (args) and output will be done using this structure.
+ * @return an #unlang_action_t.
+ */
+typedef unlang_action_t (*unlang_function_t)(rlm_rcode_t *p_result, int *priority, request_t *request, void *uctx);
+
+/** Function to call if the request was signalled
+ *
+ * @param[in] request The current request.
+ * @param[in] action We're being signalled with.
+ * @param[in,out] uctx Provided by whatever pushed the function. Is opaque to the
+ * interpreter, but should be usable by the function.
+ * All input (args) and output will be done using this structure.
+ */
+typedef void (*unlang_function_signal_t)(request_t *request, fr_state_signal_t action, void *uctx);
+
+int unlang_interpret_push_function(request_t *request,
+ unlang_function_t func, unlang_function_t repeat,
+ unlang_function_signal_t signal, void *uctx)
+ CC_HINT(warn_unused_result);
+
+#ifdef __cplusplus
+}
+#endif
#include "unlang_priv.h"
#include "group_priv.h"
-unlang_action_t unlang_group(rlm_rcode_t *p_result, request_t *request)
+unlang_action_t unlang_group(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
- unlang_group_t *g;
-
- g = unlang_generic_to_group(instruction);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
/*
* The compiler catches most of these, EXCEPT for the
* and can be empty.
*/
if (!g->children) {
- RDEBUG2("} # %s ... <ignoring empty subsection>", instruction->debug_name);
+ RDEBUG2("} # %s ... <ignoring empty subsection>", frame->instruction->debug_name);
return UNLANG_ACTION_EXECUTE_NEXT;
}
return UNLANG_ACTION_PUSHED_CHILD;
}
-static unlang_action_t unlang_policy(rlm_rcode_t *result, request_t *request)
+static unlang_action_t unlang_policy(rlm_rcode_t *result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
-
/*
* Ensure returns stop at the enclosing policy
*/
return_point_set(frame);
- return unlang_group(result, request);
+ return unlang_group(result, request, frame);
}
extern "C" {
#endif
-unlang_action_t unlang_group(UNUSED rlm_rcode_t *p_result, request_t *request);
+unlang_action_t unlang_group(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame);
#ifdef __cplusplus
}
static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
{
instruction_dump(request, frame->instruction);
- unlang_stack_t *stack = request->stack;
RINDENT();
-
- RDEBUG("frame %zd", (frame - stack->frame));
if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
if (frame->next) {
RDEBUG2("next %s", frame->next->debug_name);
* - 0 on success.
* - -1 on call stack too deep.
*/
-int unlang_interpret_push(request_t *request, unlang_t *instruction,
+int unlang_interpret_push(request_t *request, unlang_t const *instruction,
rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
{
unlang_stack_t *stack = request->stack;
* was called.
* - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
*/
-static inline unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame,
- rlm_rcode_t *result, int *priority)
+static inline CC_HINT(always_inline)
+unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame, rlm_rcode_t *result, int *priority)
{
unlang_stack_t *stack = request->stack;
if (request->master_state == REQUEST_STOP_PROCESSING) {
do_stop:
frame->result = RLM_MODULE_FAIL;
- frame->priority = 9999;
+ frame->priority = MOD_PRIORITY_MAX;
RDEBUG4("** [%i] %s - STOP current subsection with (%s %d)",
stack->depth, __FUNCTION__,
unlang_ops[instruction->type].name);
fr_assert(frame->process != NULL);
- action = frame->process(result, request);
+ action = frame->process(result, request, frame);
RDEBUG4("** [%i] %s << %s (%d)", stack->depth, __FUNCTION__,
fr_table_str_by_value(unlang_action_table, action, "<INVALID>"), *priority);
*/
rlm_rcode_t unlang_interpret(request_t *request)
{
- int priority = -1;
unlang_frame_action_t fa = UNLANG_FRAME_ACTION_NEXT;
/*
unlang_stack_t *stack = request->stack;
unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
+ stack->priority = -1; /* Reset */
+
#ifndef NDEBUG
if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
DUMP_STACK;
fr_assert(stack->depth < UNLANG_STACK_MAX);
frame = &stack->frame[stack->depth];
- fa = frame_eval(request, frame, &stack->result, &priority);
+ fa = frame_eval(request, frame, &stack->result, &stack->priority);
/*
* We were executing a frame, frame_eval()
* if we had performed a module call.
*/
stack->result = frame->result;
- priority = frame->priority;
+ stack->priority = frame->priority;
/*
* Head on back up the stack
}
}
- fa = result_calculate(request, frame, &stack->result, &priority);
+ fa = result_calculate(request, frame, &stack->result, &stack->priority);
/*
* If we're continuing after popping a frame
RDEBUG4("** [%i] %s - continuing after subsection with (%s %d)",
stack->depth, __FUNCTION__,
fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
- priority);
+ stack->priority);
frame_next(stack, frame);
/*
* Else if we're really done with this frame
/*
* Nothing in this section, use the top frame stack->result.
*/
- if ((priority < 0) || (stack->result == RLM_MODULE_UNKNOWN)) {
+ if ((stack->priority < 0) || (stack->result == RLM_MODULE_UNKNOWN)) {
RDEBUG4("** [%i] %s - empty section, using stack result (%s %d)", stack->depth, __FUNCTION__,
- fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"), priority);
+ fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"), stack->priority);
stack->result = frame->result;
- priority = frame->priority;
+ stack->priority = frame->priority;
}
- if (priority > frame->priority) {
+ if (stack->priority > frame->priority) {
frame->result = stack->result;
- frame->priority = priority;
+ frame->priority = stack->priority;
RDEBUG4("** [%i] %s - over-riding stack->result from higher priority to (%s %d)",
stack->depth, __FUNCTION__,
fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
- priority);
+ stack->priority);
}
/*
*/
RDEBUG4("** [%i] %s - interpreter exiting, returning %s", stack->depth, __FUNCTION__,
fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
+
stack->result = frame->result;
+
stack->depth--;
DUMP_STACK;
if (!frame->signal) continue;
- frame->signal(request, action);
+ frame->signal(request, frame, action);
}
stack->depth = depth; /* Reset */
}
}
if (!unlang_request_is_scheduled(request)) {
- RDEBUG3("marking as resumable");
+ RDEBUG3("Marked as resumable");
}
fr_assert(request->backlog != NULL);
#define UNLANG_TOP_FRAME (true)
#define UNLANG_SUB_FRAME (false)
-/** Function to call when interpreting a frame
- *
- * @param[in,out] p_result Pointer to the current rcode, may be modified by the function.
- * @param[in] request The current request.
- * @return an action for the interpreter to perform.
- */
-typedef unlang_action_t (*unlang_process_t)(rlm_rcode_t *p_result, request_t *request);
-
-/** Function to call if the initial function yielded and the request was signalled
- *
- * This is the operation specific cancellation function. This function will usually
- * either call a more specialised cancellation function set when something like a module yielded,
- * or just cleanup the state of the original #unlang_process_t.
- *
- * @param[in] request The current request.
- * @param[in] action We're being signalled with.
- */
-typedef void (*unlang_signal_t)(request_t *request, fr_state_signal_t action);
-
-/** A generic function pushed by a module or xlat to functions deeper in the C call stack to create resumption points
- *
- * @param[in] request The current request.
- * @param[in,out] uctx Provided by whatever pushed the function. Is opaque to the
- * interpreter, but should be usable by the function.
- * All input (args) and output will be done using this structure.
- * @return an #unlang_action_t.
- */
-typedef unlang_action_t (*unlang_function_t)(rlm_rcode_t *p_result, int *priority, request_t *request, void *uctx);
-
-/** An unlang operation
- *
- * These are like the opcodes in other interpreters. Each operation, when executed
- * will return an #unlang_action_t, which determines what the interpreter does next.
- */
-typedef struct {
- char const *name; //!< Name of the operation.
-
- unlang_process_t interpret; //!< Function to interpret the keyword
-
- unlang_signal_t signal; //!< Function to signal stop / dup / whatever
-
- bool debug_braces; //!< Whether the operation needs to print braces
- ///< in debug mode.
-
- size_t frame_state_size; //!< size of instance data in the stack frame
-
- char const *frame_state_name; //!< talloc name of the frame instance data
-
- size_t frame_state_pool_objects; //!< How many sub-allocations we expect.
-
- size_t frame_state_pool_size; //!< The total size of the pool to alloc.
-} unlang_op_t;
+#define UNLANG_STACK_MAX (64) //!< The maximum depth of the stack.
+#define UNLANG_FRAME_PRE_ALLOC (128) //!< How much memory we pre-alloc for each frame.
/** Return whether a request is currently scheduled
*
return (request->runnable_id >= 0);
}
-int unlang_interpret_push_function(request_t *request,
- unlang_function_t func, unlang_function_t repeat, void *uctx)
- CC_HINT(warn_unused_result);
-
int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs,
rlm_rcode_t default_action, bool top_frame)
CC_HINT(warn_unused_result);
#define unlang_redundant_load_balance unlang_load_balance
-static unlang_action_t unlang_load_balance_next(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_load_balance_next(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
- unlang_frame_state_redundant_t *redundant;
-
- unlang_group_t *g;
-
- g = unlang_generic_to_group(instruction);
-
- redundant = talloc_get_type_abort(frame->state, unlang_frame_state_redundant_t);
+ unlang_frame_state_redundant_t *redundant = talloc_get_type_abort(frame->state, unlang_frame_state_redundant_t);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
#ifdef __clang_analyzer__
if (!redundant->found) {
* process again.
*/
- fr_assert(instruction->type != UNLANG_TYPE_LOAD_BALANCE); /* this is never called again */
+ fr_assert(frame->instruction->type != UNLANG_TYPE_LOAD_BALANCE); /* this is never called again */
/*
* If the current child says "return", then do
return UNLANG_ACTION_PUSHED_CHILD;
}
-static unlang_action_t unlang_load_balance(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_load_balance(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
unlang_frame_state_redundant_t *redundant;
-
- unlang_group_t *g;
- unlang_load_balance_t *gext = NULL;
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
+ unlang_load_balance_t *gext = NULL;
uint32_t count = 0;
- g = unlang_generic_to_group(instruction);
if (!g->num_children) {
*p_result = RLM_MODULE_NOOP;
return UNLANG_ACTION_CALCULATE_RESULT;
RDEBUG4("%s setting up", frame->instruction->debug_name);
- redundant = talloc_get_type_abort(frame->state, unlang_frame_state_redundant_t);
+ redundant = talloc_get_type_abort(frame->state,
+ unlang_frame_state_redundant_t);
if (gext && gext->vpt) {
uint32_t hash, start;
/*
* Plain "load-balance". Just do one child.
*/
- if (instruction->type == UNLANG_TYPE_LOAD_BALANCE) {
+ if (frame->instruction->type == UNLANG_TYPE_LOAD_BALANCE) {
if (unlang_interpret_push(request, redundant->found,
frame->result, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
*p_result = RLM_MODULE_FAIL;
redundant->child = NULL;
frame->process = unlang_load_balance_next;
- return unlang_load_balance_next(p_result, request);
+ return unlang_load_balance_next(p_result, request, frame);
}
void unlang_load_balance_init(void)
/** Create a list of modifications to apply to one or more fr_pair_t lists
*
- * @param[in] request The current request.
* @param[out] p_result The rcode indicating what the result
* of the operation was.
+ * @param[in] request The current request.
+ * @param[in] frame Current stack frame.
* @return
* - UNLANG_ACTION_CALCULATE_RESULT changes were applied.
* - UNLANG_ACTION_PUSHED_CHILD async execution of an expansion is required.
*/
-static unlang_action_t list_mod_create(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t list_mod_create(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_frame_state_update_t *update_state = frame->state;
- map_t *map;
+ unlang_frame_state_update_t *update_state = talloc_get_type_abort(frame->state, unlang_frame_state_update_t);
+ map_t *map;
/*
* Iterate over the maps producing a set of modifications to apply.
* If one map fails in the evaluation phase, no more maps are processed, and the current
* result is discarded.
*/
-static unlang_action_t unlang_update_state_init(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_update_state_init(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
-
- unlang_group_t *g = unlang_generic_to_group(instruction);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
unlang_map_t *gext = unlang_group_to_map(g);
unlang_frame_state_update_t *update_state;
/*
* Initialise the frame state
*/
- MEM(frame->state = update_state = talloc_zero_pooled_object(stack, unlang_frame_state_update_t,
+ MEM(frame->state = update_state = talloc_zero_pooled_object(request->stack, unlang_frame_state_update_t,
(sizeof(map_t) +
(sizeof(tmpl_t) * 2) + 128),
g->num_children)); /* 128 is for string buffers */
* Call list_mod_create
*/
frame->process = list_mod_create;
- return list_mod_create(p_result, request);
+ return list_mod_create(p_result, request, frame);
}
-static unlang_action_t map_proc_apply(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t map_proc_apply(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
-
- unlang_group_t *g = unlang_generic_to_group(instruction);
- unlang_map_t *gext = unlang_group_to_map(g);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
+ unlang_map_t *gext = unlang_group_to_map(g);
map_proc_inst_t *inst = gext->proc_inst;
unlang_frame_state_map_proc_t *map_proc_state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t);
return *p_result == RLM_MODULE_YIELD ? UNLANG_ACTION_YIELD : UNLANG_ACTION_CALCULATE_RESULT;
}
-static unlang_action_t unlang_map_state_init(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_map_state_init(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
- unlang_group_t *g = unlang_generic_to_group(instruction);
- unlang_map_t *gext = unlang_group_to_map(g);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
+ unlang_map_t *gext = unlang_group_to_map(g);
map_proc_inst_t *inst = gext->proc_inst;
unlang_frame_state_map_proc_t *map_proc_state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t);
goto error;
}
- return map_proc_apply(p_result, request);
+ return map_proc_apply(p_result, request, frame);
}
void unlang_map_init(void)
if (!subcs) {
unlang_stack_t *stack = request->stack;
unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
- unlang_module_t *mc;
+ unlang_module_t *mc;
- fr_assert(instruction->type == UNLANG_TYPE_MODULE);
- mc = unlang_generic_to_module(instruction);
+ fr_assert(frame->instruction->type == UNLANG_TYPE_MODULE);
+ mc = unlang_generic_to_module(frame->instruction);
/*
* Be transparent to the resume function.
* If there is no #unlang_module_signal_t callback defined, the action is ignored.
*
* @param[in] request The current request.
+ * @param[in] frame current stack frame.
* @param[in] action to signal.
*/
-static void unlang_module_signal(request_t *request, fr_state_signal_t action)
+static void unlang_module_signal(request_t *request, unlang_stack_frame_t *frame, fr_state_signal_t action)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
unlang_module_t *mc = unlang_generic_to_module(frame->instruction);
/** Return UNLANG_CALCULATE_RESULT only for async async calls
*
*/
-static unlang_action_t unlang_module_resume_final(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_module_resume_final(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
request->rcode = state->rcode;
/** Wrapper to call a module's resumption function
*
*/
-static unlang_action_t unlang_module_resume(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_module_resume(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
unlang_module_t *mc = unlang_generic_to_module(frame->instruction);
char const *caller;
rlm_rcode_t rcode = RLM_MODULE_NOOP;
- int stack_depth = stack->depth;
+ int stack_depth = unlang_current_depth(request);
unlang_action_t ua;
fr_assert(state->resume != NULL);
fr_table_str_by_value(mod_rcode_table, rcode, "<invalid>"));
if (ua == UNLANG_ACTION_YIELD) {
- if (stack_depth < stack->depth) return UNLANG_ACTION_PUSHED_CHILD;
- fr_assert(stack_depth == stack->depth);
+ if (stack_depth < unlang_current_depth(request)) return UNLANG_ACTION_PUSHED_CHILD;
+ fr_assert(stack_depth == unlang_current_depth(request));
*p_result = rcode;
return UNLANG_ACTION_YIELD;
}
return UNLANG_ACTION_YIELD;
}
-static unlang_action_t unlang_module(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_module(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
unlang_module_t *mc;
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
- int stack_depth = stack->depth;
+ int stack_depth = unlang_current_depth(request);
char const *caller;
rlm_rcode_t rcode = RLM_MODULE_NOOP;
unlang_action_t ua;
* Process a stand-alone child, and fall through
* to dealing with it's parent.
*/
- mc = unlang_generic_to_module(instruction);
+ mc = unlang_generic_to_module(frame->instruction);
fr_assert(mc);
- RDEBUG4("[%i] %s - %s (%s)", stack->depth, __FUNCTION__,
+ RDEBUG4("[%i] %s - %s (%s)", unlang_current_depth(request), __FUNCTION__,
mc->instance->name, mc->instance->module->name);
/*
/*
* Must be left at RDEBUG() level otherwise RDEBUG becomes pointless
*/
- RDEBUG("%s (%s)", instruction->name ? instruction->name : "",
+ RDEBUG("%s (%s)", frame->instruction->name ? frame->instruction->name : "",
fr_table_str_by_value(mod_rcode_table, rcode, "<invalid>"));
if (ua == UNLANG_ACTION_YIELD) {
state->thread->active_callers++;
- if (stack_depth < stack->depth) return UNLANG_ACTION_PUSHED_CHILD;
- fr_assert(stack_depth == stack->depth);
+ if (stack_depth < unlang_current_depth(request)) return UNLANG_ACTION_PUSHED_CHILD;
+ fr_assert(stack_depth == unlang_current_depth(request));
frame->process = unlang_module_resume;
return UNLANG_ACTION_YIELD;
}
/** @} */
} unlang_frame_state_module_t;
-static inline unlang_module_t *unlang_generic_to_module(unlang_t *p)
+static inline unlang_module_t *unlang_generic_to_module(unlang_t const *p)
{
fr_assert(p->type == UNLANG_TYPE_MODULE);
- return talloc_get_type_abort(p, unlang_module_t);
+ return UNCONST(unlang_module_t *, talloc_get_type_abort_const(p, unlang_module_t));
}
static inline unlang_t *unlang_module_to_generic(unlang_module_t *p)
/** Run one or more sub-sections from the parallel section.
*
*/
-static unlang_action_t unlang_parallel_process(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_parallel_process(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_parallel_state_t *state = talloc_get_type_abort(frame->state, unlang_parallel_state_t);
int i, priority;
*/
if ((unlang_interpret_push(child, NULL, RLM_MODULE_NOOP,
UNLANG_NEXT_STOP, UNLANG_TOP_FRAME) < 0) ||
- (unlang_interpret_push_function(child, unlang_parallel_child_done, NULL, &state->children[i]) < 0) ||
+ (unlang_interpret_push_function(child, unlang_parallel_child_done, NULL, NULL, &state->children[i]) < 0) ||
(unlang_interpret_push(child,
state->children[i].instruction, RLM_MODULE_FAIL,
UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0)) {
state->priority = priority;
RDEBUG4("** [%i] %s - over-riding result from higher priority to (%s %d)",
- stack->depth, __FUNCTION__,
+ unlang_current_depth(request), __FUNCTION__,
fr_table_str_by_value(mod_rcode_table, result, "<invalid>"),
priority);
}
/** Send a signal from parent request to all of it's children
*
*/
-static void unlang_parallel_signal(request_t *request, fr_state_signal_t action)
+static void unlang_parallel_signal(UNUSED request_t *request, unlang_stack_frame_t *frame, fr_state_signal_t action)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_parallel_state_t *state = talloc_get_type_abort(frame->state, unlang_parallel_state_t);
int i;
}
}
-static unlang_action_t unlang_parallel(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_parallel(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
+ unlang_t const *instruction = frame->instruction;
unlang_group_t *g;
unlang_parallel_t *gext;
}
frame->process = unlang_parallel_process;
- return unlang_parallel_process(p_result, request);
+ return unlang_parallel_process(p_result, request, frame);
}
void unlang_parallel_init(void)
unlang_parallel_child_state_t state; //!< State of the child.
request_t *child; //!< Child request.
char *name; //!< Cache the request name.
- unlang_t *instruction; //!< broken out of g->children
+ unlang_t const *instruction; //!< broken out of g->children
} unlang_parallel_child_t;
typedef struct {
#include "unlang_priv.h"
#include "return_priv.h"
-unlang_action_t unlang_return(rlm_rcode_t *p_result, request_t *request)
+unlang_action_t unlang_return(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
-
- RDEBUG2("%s", unlang_ops[instruction->type].name);
+ RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
*p_result = frame->result;
* Stop at the next return point, or if we hit
* the a top frame.
*/
- return unwind_to_return(stack);
+ return unwind_to_return(request->stack);
}
void unlang_return_init(void)
extern "C" {
#endif
-unlang_action_t unlang_return(UNUSED rlm_rcode_t *result, request_t *request);
+unlang_action_t unlang_return(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame);
#ifdef __cplusplus
}
/** Send a signal from parent request to subrequest
*
*/
-static void unlang_subrequest_signal(request_t *request, fr_state_signal_t action)
+static void unlang_subrequest_signal(UNUSED request_t *request, unlang_stack_frame_t *frame, fr_state_signal_t action)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_subrequest_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_subrequest_t);
request_t *child = talloc_get_type_abort(state->child, request_t);
/** Process a subrequest until it either detaches, or is done.
*
*/
-static unlang_action_t unlang_subrequest_process(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_subrequest_process(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_subrequest_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_subrequest_t);
request_t *child = talloc_get_type_abort(state->child, request_t);
unlang_group_t *g = unlang_generic_to_group(frame->instruction);
}
-static unlang_action_t unlang_subrequest_start(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_subrequest_start(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_subrequest_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_subrequest_t);
request_t *child = state->child;
log_request_pair_list(L_DBG_LVL_1, request, NULL, &child->request_pairs, NULL);
frame->process = unlang_subrequest_process;
- return unlang_subrequest_process(p_result, request);
+ return unlang_subrequest_process(p_result, request, frame);
}
-static unlang_action_t unlang_subrequest_state_init(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_subrequest_state_init(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
unlang_frame_state_subrequest_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_subrequest_t);
request_t *child;
fr_pair_t *vp;
unlang_group_t *g;
- unlang_subrequest_t *gext;
+ unlang_subrequest_t *gext;
/*
* Initialize the state
*/
- g = unlang_generic_to_group(instruction);
+ g = unlang_generic_to_group(frame->instruction);
if (!g->num_children) {
*p_result = RLM_MODULE_NOOP;
return UNLANG_ACTION_CALCULATE_RESULT;
* keyed off the exact subrequest keyword.
*/
state->session.enable = true;
- state->session.unique_ptr = instruction;
+ state->session.unique_ptr = frame->instruction;
state->session.unique_int = 0;
frame->process = unlang_subrequest_start;
- return unlang_subrequest_start(p_result, request);
+ return unlang_subrequest_start(p_result, request, frame);
}
/** Initialize a detached child
return 0;
}
-static unlang_action_t unlang_detach(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_detach(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_detach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_detach_t);
-
+ unlang_stack_frame_t *parent_frame;
unlang_frame_state_subrequest_t *parent_state;
/*
/*
* Get the PARENT's stack.
*/
- stack = request->parent->stack;
- frame = &stack->frame[stack->depth];
+ parent_frame = unlang_current_frame(request->parent);
parent_state = talloc_get_type_abort(frame->state, unlang_frame_state_subrequest_t);
if (!parent_state->detachable) {
*/
fr_assert(parent_state->child == request);
parent_state->child = NULL;
- frame->signal = NULL;
+ parent_frame->signal = NULL;
/*
* Pass through whatever the previous instruction had as
#include "switch_priv.h"
#include "unlang_priv.h"
-static unlang_action_t unlang_switch(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_switch(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
unlang_t *this, *found, *null_case;
unlang_group_t *switch_g;
map_t map;
tmpl_t vpt, *switch_vpt;
- switch_g = unlang_generic_to_group(instruction);
+ switch_g = unlang_generic_to_group(frame->instruction);
switch_gext = unlang_group_to_switch(switch_g);
memset(&cond, 0, sizeof(cond));
}
-static unlang_action_t unlang_case(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_case(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
- unlang_group_t *g;
-
- g = unlang_generic_to_group(instruction);
+ unlang_group_t *g = unlang_generic_to_group(frame->instruction);
if (!g->children) {
*p_result = RLM_MODULE_NOOP;
return UNLANG_ACTION_CALCULATE_RESULT;
}
- return unlang_group(p_result, request);
+ return unlang_group(p_result, request, frame);
}
void unlang_switch_init(void)
* If there is no #fr_unlang_tmpl_signal_t callback defined, the action is ignored.
*
* @param[in] request The current request.
+ * @param[in] frame being signalled.
* @param[in] action to signal.
*/
-static void unlang_tmpl_signal(request_t *request, fr_state_signal_t action)
+static void unlang_tmpl_signal(request_t *request, unlang_stack_frame_t *frame, fr_state_signal_t action)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
unlang_frame_state_tmpl_t);
* called repeatedly until the resumption function returns a final
* value.
*/
-static unlang_action_t unlang_tmpl_resume(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_tmpl_resume(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
- unlang_frame_state_tmpl_t);
+ unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_tmpl_t);
if (state->out) fr_dlist_move(state->out, &state->box);
/** Wrapper to call exec after the program has finished executing
*
*/
-static unlang_action_t unlang_tmpl_exec_wait_final(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_tmpl_exec_wait_final(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
unlang_frame_state_tmpl_t);
*/
resume:
frame->process = unlang_tmpl_resume;
- return unlang_tmpl_resume(p_result, request);
+ return unlang_tmpl_resume(p_result, request, frame);
}
/** Wrapper to call exec after a tmpl has been expanded
*
*/
-static unlang_action_t unlang_tmpl_exec_wait_resume(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_tmpl_exec_wait_resume(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
- unlang_frame_state_tmpl_t);
+ unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_tmpl_t);
pid_t pid;
int *fd_p = NULL;
/** Wrapper to call exec after a tmpl has been expanded
*
*/
-static unlang_action_t unlang_tmpl_exec_nowait_resume(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_tmpl_exec_nowait_resume(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
- unlang_frame_state_tmpl_t);
+ unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_tmpl_t);
if (fr_exec_nowait(request, &state->box, state->vps) < 0) {
RPEDEBUG("Failed executing program");
}
-static unlang_action_t unlang_tmpl(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_tmpl(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
- unlang_frame_state_tmpl_t);
+ unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_tmpl_t);
unlang_tmpl_t *ut = unlang_generic_to_tmpl(frame->instruction);
xlat_exp_t const *xlat;
#define UNLANG_NORMAL_CHILD (false)
typedef struct unlang_s unlang_t;
+typedef struct unlang_stack_frame_s unlang_stack_frame_t;
/** A node in a graph of #unlang_op_t (s) that we execute
*
xlat_flags_t flags;
} unlang_tmpl_t;
+/** Function to call when interpreting a frame
+ *
+ * @param[in,out] p_result Pointer to the current rcode, may be modified by the function.
+ * @param[in] request The current request.
+ * @param[in] frame being executed.
+ *
+ * @return an action for the interpreter to perform.
+ */
+typedef unlang_action_t (*unlang_process_t)(rlm_rcode_t *p_result, request_t *request,
+ unlang_stack_frame_t *frame);
+
+/** Function to call if the request was signalled
+ *
+ * This is the instruction specific cancellation function.
+ * This function will usually either call a more specialised cancellation function
+ * set when something like a module yielded, or just cleanup the state of the original
+ * #unlang_process_t.
+ *
+ * @param[in] request The current request.
+ * @param[in] frame being signalled.
+ * @param[in] action We're being signalled with.
+ */
+typedef void (*unlang_signal_t)(request_t *request,
+ unlang_stack_frame_t *frame, fr_state_signal_t action);
+
+/** An unlang operation
+ *
+ * These are like the opcodes in other interpreters. Each operation, when executed
+ * will return an #unlang_action_t, which determines what the interpreter does next.
+ */
+typedef struct {
+ char const *name; //!< Name of the operation.
+
+ unlang_process_t interpret; //!< Function to interpret the keyword
+
+ unlang_signal_t signal; //!< Function to signal stop / dup / whatever
+
+ bool debug_braces; //!< Whether the operation needs to print braces
+ ///< in debug mode.
+
+ size_t frame_state_size; //!< size of instance data in the stack frame
+
+ char const *frame_state_name; //!< talloc name of the frame instance data
+
+ size_t frame_state_pool_objects; //!< How many sub-allocations we expect.
+
+ size_t frame_state_pool_size; //!< The total size of the pool to alloc.
+} unlang_op_t;
+
/** Our interpreter stack, as distinct from the C stack
*
* We don't call the modules recursively. Instead we iterate over a list of #unlang_t and
* through the server. Because the interpreter stack is distinct from the C stack, we can have
* a single system thread with many thousands of pending requests.
*/
-typedef struct {
- unlang_t *instruction; //!< The unlang node we're evaluating.
- unlang_t *next; //!< The next unlang node we will evaluate
+struct unlang_stack_frame_s {
+ unlang_t const *instruction; //!< The unlang node we're evaluating.
+ unlang_t const *next; //!< The next unlang node we will evaluate
unlang_process_t process; //!< function to call for interpreting this stack frame
unlang_signal_t signal; //!< function to call when signalling this stack frame
*/
void *state;
- rlm_rcode_t result; //!< The result from executing the instruction.
+ rlm_rcode_t result; //!< The result from executing the instruction.
int priority; //!< Result priority. When we pop this stack frame
///< this priority will be compared with the one of the
///< frame lower in the stack to determine if the
///< result stored in the lower stack frame should
///< be replaced.
uint8_t uflags; //!< Unwind markers
-} unlang_stack_frame_t;
+};
/** An unlang stack associated with a request
*
*/
typedef struct {
+ int priority; //!< Current priority.
rlm_rcode_t result; //!< The current stack rcode.
int depth; //!< Current depth we're executing at.
uint8_t unwind; //!< Unwind to this frame if it exists.
static inline void top_frame_clear(unlang_stack_frame_t *frame) { frame->uflags &= ~UNWIND_FLAG_TOP_FRAME; }
static inline void break_point_clear(unlang_stack_frame_t *frame) { frame->uflags &= ~UNWIND_FLAG_BREAK_POINT; }
static inline void return_point_clear(unlang_stack_frame_t *frame) { frame->uflags &= ~UNWIND_FLAG_RETURN_POINT; }
-static inline void yielded_clear(unlang_stack_frame_t *frame) { frame->uflags &= ~UNWIND_FLAG_YIELDED; }
+static inline void yielded_clear(unlang_stack_frame_t *frame) { frame->uflags &= ~UNWIND_FLAG_YIELDED; }
-static inline bool is_repeatable(unlang_stack_frame_t *frame) { return frame->uflags & UNWIND_FLAG_REPEAT; }
-static inline bool is_top_frame(unlang_stack_frame_t *frame) { return frame->uflags & UNWIND_FLAG_TOP_FRAME; }
-static inline bool is_break_point(unlang_stack_frame_t *frame) { return frame->uflags & UNWIND_FLAG_BREAK_POINT; }
-static inline bool is_return_point(unlang_stack_frame_t *frame) { return frame->uflags & UNWIND_FLAG_RETURN_POINT; }
-static inline bool is_yielded(unlang_stack_frame_t *frame) { return frame->uflags & UNWIND_FLAG_YIELDED; }
+static inline bool is_repeatable(unlang_stack_frame_t const *frame) { return frame->uflags & UNWIND_FLAG_REPEAT; }
+static inline bool is_top_frame(unlang_stack_frame_t const *frame) { return frame->uflags & UNWIND_FLAG_TOP_FRAME; }
+static inline bool is_break_point(unlang_stack_frame_t const *frame) { return frame->uflags & UNWIND_FLAG_BREAK_POINT; }
+static inline bool is_return_point(unlang_stack_frame_t const *frame) { return frame->uflags & UNWIND_FLAG_RETURN_POINT; }
+static inline bool is_yielded(unlang_stack_frame_t const *frame) { return frame->uflags & UNWIND_FLAG_YIELDED; }
static inline unlang_action_t unwind_to_break(unlang_stack_t *stack)
{
return UNLANG_ACTION_UNWIND;
}
+static inline unlang_stack_frame_t *unlang_current_frame(request_t *request)
+{
+ unlang_stack_t *stack = request->stack;
+
+ return &stack->frame[stack->depth];
+}
+
+static inline int unlang_current_depth(request_t *request)
+{
+ unlang_stack_t *stack = request->stack;
+
+ return stack->depth;
+}
+
/** Different operations the interpreter can execute
*/
extern unlang_op_t unlang_ops[];
*
* @{
*/
-static inline unlang_group_t *unlang_generic_to_group(unlang_t *p)
+static inline unlang_group_t *unlang_generic_to_group(unlang_t const *p)
{
fr_assert((p->type > UNLANG_TYPE_MODULE) && (p->type <= UNLANG_TYPE_POLICY));
- return (unlang_group_t *)p;
+ return UNCONST(unlang_group_t *, p);
}
-static inline unlang_t *unlang_group_to_generic(unlang_group_t *p)
+static inline unlang_t *unlang_group_to_generic(unlang_group_t const *p)
{
- return (unlang_t *)p;
+ return UNCONST(unlang_t *, p);
}
-static inline unlang_tmpl_t *unlang_generic_to_tmpl(unlang_t *p)
+static inline unlang_tmpl_t *unlang_generic_to_tmpl(unlang_t const *p)
{
fr_assert(p->type == UNLANG_TYPE_TMPL);
- return talloc_get_type_abort(p, unlang_tmpl_t);
+ return UNCONST(unlang_tmpl_t *, talloc_get_type_abort_const(p, unlang_tmpl_t));
}
-static inline unlang_t *unlang_tmpl_to_generic(unlang_tmpl_t *p)
+static inline unlang_t *unlang_tmpl_to_generic(unlang_tmpl_t const *p)
{
- return (unlang_t *)p;
+ return UNCONST(unlang_t *, p);
}
/** @} */
*
* @{
*/
-int unlang_interpret_push(request_t *request, unlang_t *instruction,
+int unlang_interpret_push(request_t *request, unlang_t const *instruction,
rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
CC_HINT(warn_unused_result);
*
* @{
*/
+void unlang_register(int type, unlang_op_t *op);
+
void unlang_call_init(void);
void unlang_caller_init(void);
* Calls the xlat interpreter and translates its wants and needs into
* unlang_action_t codes.
*/
-static unlang_action_t unlang_xlat(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_xlat(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
xlat_exp_t const *child = NULL;
xlat_action_t xa;
* If there is no #xlat_func_signal_t callback defined, the action is ignored.
*
* @param[in] request The current request.
+ * @param[in] frame The current stack frame.
* @param[in] action What the request should do (the type of signal).
*/
-static void unlang_xlat_signal(request_t *request, fr_state_signal_t action)
+static void unlang_xlat_signal(request_t *request, unlang_stack_frame_t *frame, fr_state_signal_t action)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
/*
* - RLM_MODULE_YIELD if additional asynchronous
* operations need to be performed.
* @param[in] request to resume processing.
+ * @param[in] frame the current stack frame.
* @return
* - UNLANG_ACTION_YIELD if yielding.
* - UNLANG_ACTION_CALCULATE_RESULT if done.
*/
-static unlang_action_t unlang_xlat_resume(rlm_rcode_t *p_result, request_t *request)
+static unlang_action_t unlang_xlat_resume(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_xlat_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_xlat_t);
xlat_action_t xa;
/*
* Catch the interpreter on the way back up the stack
*/
- if (unlang_interpret_push_function(request, NULL, eap_tls_virtual_server_result, eap_session) < 0) {
+ if (unlang_interpret_push_function(request, NULL, eap_tls_virtual_server_result, NULL, eap_session) < 0) {
RETURN_MODULE_FAIL;
}