static unlang_action_t unlang_call_children(rlm_rcode_t *p_result, request_t *request,
unlang_stack_frame_t *frame)
{
- unlang_group_t *g = unlang_generic_to_group(frame->instruction);
-
- fr_assert(g->children);
+ frame_repeat(frame, unlang_call_finalize);
/*
* Push the contents of the call { } section onto the stack.
* This gets executed after the server returns.
*/
- if (unlang_interpret_push(request, g->children, frame->result,
- UNLANG_NEXT_SIBLING, UNLANG_SUB_FRAME) < 0) {
- *p_result = RLM_MODULE_FAIL;
- return UNLANG_ACTION_STOP_PROCESSING;
- }
-
- frame_repeat(frame, unlang_call_finalize);
- return UNLANG_ACTION_PUSHED_CHILD;
+ return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
}
.local = true,
};
+ fr_assert(unlang_ops[parent->type].debug_braces);
+
/*
* The variables exist in the parent block.
*/
static unlang_action_t unlang_foreach_next(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
- unlang_group_t *g = unlang_generic_to_group(frame->instruction);
fr_pair_t *vp;
if (is_stack_unwinding_to_break(request->stack)) return UNLANG_ACTION_CALCULATE_RESULT;
RDEBUG2("# looping with: Foreach-Variable-%d = %pV", state->depth, &vp->data);
#endif
+ repeatable_set(frame);
+
/*
* Push the child, and yield for a later return.
*/
- if (unlang_interpret_push(request, g->children, frame->result, UNLANG_NEXT_SIBLING, UNLANG_SUB_FRAME) < 0) {
- *p_result = RLM_MODULE_FAIL;
- return UNLANG_ACTION_STOP_PROCESSING;
- }
-
- repeatable_set(frame);
-
- return UNLANG_ACTION_PUSHED_CHILD;
+ return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
}
frame->process = unlang_foreach_next;
+ repeatable_set(frame);
+
/*
* Push the child, and go process it.
*/
- if (unlang_interpret_push(request, g->children, frame->result, UNLANG_NEXT_SIBLING, UNLANG_SUB_FRAME) < 0) {
- *p_result = RLM_MODULE_FAIL;
- return UNLANG_ACTION_STOP_PROCESSING;
- }
-
- repeatable_set(frame);
-
- return UNLANG_ACTION_PUSHED_CHILD;
+ return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
}
static unlang_action_t unlang_break(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
unlang_action_t unlang_group(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
- unlang_group_t *g = unlang_generic_to_group(frame->instruction);
-
- /*
- * The compiler catches most of these, EXCEPT for the
- * top-level 'recv Access-Request' etc. Which can exist,
- * and can be empty.
- */
- if (!g->children) {
- RDEBUG2("<ignoring empty subsection>");
- return UNLANG_ACTION_EXECUTE_NEXT;
- }
-
- if (unlang_interpret_push(request, g->children, frame->result, UNLANG_NEXT_SIBLING, UNLANG_SUB_FRAME) < 0) {
- *p_result = RLM_MODULE_FAIL;
- return UNLANG_ACTION_STOP_PROCESSING;
- }
-
- return UNLANG_ACTION_PUSHED_CHILD;
+ return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
}
static unlang_action_t unlang_policy(rlm_rcode_t *result, request_t *request, unlang_stack_frame_t *frame)
return 0;
}
+/** Push the children of the current frame onto a new frame onto the stack
+ *
+ * @param[in] request to push the frame onto.
+ * @param[in] default_rcode The default result.
+ * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
+ * or to execute subsequent nodes.
+ * @return
+ * - UNLANG_ACTION_PUSHED_CHILD on success.
+ * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
+ * - UNLANG_ACTION_STOP_PROCESSING, fatal error, usually stack overflow.
+ */
+unlang_action_t unlang_interpret_push_children(rlm_rcode_t *p_result, request_t *request,
+ rlm_rcode_t default_rcode, bool do_next_sibling)
+{
+ unlang_stack_t *stack = request->stack;
+ unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
+ unlang_group_t *g;
+
+ fr_assert(unlang_ops[frame->instruction->type].debug_braces);
+
+ g = unlang_generic_to_group(frame->instruction);
+
+ /*
+ * The compiler catches most of these, EXCEPT for the
+ * top-level 'recv Access-Request' etc. Which can exist,
+ * and can be empty.
+ */
+ if (!g->children) {
+ RDEBUG2("<ignoring empty subsection>");
+ return UNLANG_ACTION_EXECUTE_NEXT;
+ }
+
+ if (unlang_interpret_push(request, g->children, default_rcode, do_next_sibling, UNLANG_SUB_FRAME) < 0) {
+ *p_result = RLM_MODULE_FAIL;
+ return UNLANG_ACTION_STOP_PROCESSING;
+ }
+
+ return UNLANG_ACTION_PUSHED_CHILD;
+}
+
static void instruction_timeout_handler(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *ctx);
/** Update the current result after each instruction, and after popping each stack frame
static unlang_action_t unlang_limit_enforce(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
unlang_frame_state_limit_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_limit_t);
- unlang_group_t *g;
+ unlang_action_t action;
state->thread = unlang_thread_instance(frame->instruction);
fr_assert(state->thread != NULL);
if (state->thread->active_callers >= state->limit) return UNLANG_ACTION_FAIL;
- g = unlang_generic_to_group(frame->instruction);
-
- if (unlang_interpret_push(request, g->children, frame->result, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
- *p_result = RLM_MODULE_FAIL;
- return UNLANG_ACTION_STOP_PROCESSING;
- }
+ frame_repeat(frame, unlang_limit_resume_done);
- state->thread->active_callers++;
+ action = unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_STOP);
- frame_repeat(frame, unlang_limit_resume_done);
+ state->thread->active_callers += (action == UNLANG_ACTION_PUSHED_CHILD);
- return UNLANG_ACTION_PUSHED_CHILD;
+ return action;
}
static unlang_action_t unlang_limit_xlat_done(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
static unlang_action_t unlang_timeout_set(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
{
unlang_frame_state_timeout_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_timeout_t);
- unlang_group_t *g;
fr_time_t timeout;
/*
if (fr_event_timer_at(state, unlang_interpret_event_list(request), &state->ev, timeout,
unlang_timeout_handler, state) < 0) {
RPEDEBUG("Failed inserting event");
- goto fail;
- }
-
- g = unlang_generic_to_group(frame->instruction);
-
- if (unlang_interpret_push(request, g->children, frame->result, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
- fail:
*p_result = RLM_MODULE_FAIL;
return UNLANG_ACTION_STOP_PROCESSING;
}
frame_repeat(frame, unlang_timeout_resume_done);
state->success = true;
- return UNLANG_ACTION_PUSHED_CHILD;
+ return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_STOP);
}
static unlang_action_t unlang_timeout_xlat_done(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
CC_HINT(warn_unused_result);
+int unlang_interpret_push_children(rlm_rcode_t *p_result, request_t *request,
+ rlm_rcode_t default_rcode, bool do_next_sibling)
+ CC_HINT(warn_unused_result);
+
int unlang_op_init(void);
void unlang_op_free(void);