It's not needed anymore. Fatal errors should use `RETURN_UNLANG_ACTION_FATAL` to signal the request to stop.
Fix issue where finally-timeout test wasn't actually running because the dummy request got cancalled during the virtual server call (oops).
Add regression tests for module calls being immediately cancelled in finally sections.
int fr_control_callback_add(fr_control_t *c, uint32_t id, void *ctx, fr_control_callback_t callback) CC_HINT(nonnull(1,4));
int fr_control_callback_delete(fr_control_t *c, uint32_t id) CC_HINT(nonnull);
-int fr_control_same_thread(fr_control_t *c);
+int fr_control_same_thread(fr_control_t *c) CC_HINT(nonnull);
#ifdef __cplusplus
}
UNLANG_ACTION_PUSHED_CHILD, //!< #unlang_t pushed a new child onto the stack,
//!< execute it instead of continuing.
UNLANG_ACTION_YIELD, //!< Temporarily pause execution until an event occurs.
- UNLANG_ACTION_STOP_PROCESSING //!< Break out of processing the current request (unwind).
} unlang_action_t;
+#define RETURN_UNLANG_ACTION_FATAL \
+{ \
+ unlang_interpret_signal(request, FR_SIGNAL_CANCEL); \
+ return UNLANG_ACTION_FAIL; \
+}
+
#ifdef __cplusplus
}
#endif
ua = func(p_result, request, state->uctx);
if (REPEAT(state)) { /* set again by func */
switch (ua) {
- case UNLANG_ACTION_STOP_PROCESSING:
- break;
-
case UNLANG_ACTION_CALCULATE_RESULT:
goto again;
state->func_name = NULL;
if (REPEAT(state)) {
switch (ua) {
- case UNLANG_ACTION_STOP_PROCESSING:
- break;
-
case UNLANG_ACTION_CALCULATE_RESULT:
ua = call_with_result_repeat(p_result, request, frame);
break;
ua = func(request, state->uctx);
if (REPEAT(state)) { /* set again by func */
switch (ua) {
- case UNLANG_ACTION_STOP_PROCESSING:
- break;
-
case UNLANG_ACTION_CALCULATE_RESULT:
goto again;
state->func_name = NULL;
if (REPEAT(state)) {
switch (ua) {
- case UNLANG_ACTION_STOP_PROCESSING:
- break;
-
case UNLANG_ACTION_CALCULATE_RESULT:
ua = call_no_result_repeat(p_result, request, frame);
break;
.dump = unlang_function_dump,
.unlang_size = sizeof(unlang_group_t),
- .unlang_name = "unlang_group_t",
+ .unlang_name = "unlang_group_t",
.frame_state_size = sizeof(unlang_frame_state_func_t),
.frame_state_type = "unlang_frame_state_func_t",
{ L("calculate-result"), UNLANG_ACTION_CALCULATE_RESULT },
{ L("next"), UNLANG_ACTION_EXECUTE_NEXT },
{ L("pushed-child"), UNLANG_ACTION_PUSHED_CHILD },
- { L("stop"), UNLANG_ACTION_STOP_PROCESSING },
{ L("yield"), UNLANG_ACTION_YIELD }
};
static size_t unlang_action_table_len = NUM_ELEMENTS(unlang_action_table);
* @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_FAIL, fatal error, usually stack overflow.
*/
unlang_action_t unlang_interpret_push_children(unlang_result_t *p_result, request_t *request,
rlm_rcode_t default_rcode, bool do_next_sibling)
if (unlang_interpret_push(p_result, request, unlang_list_head(&g->children),
FRAME_CONF(default_rcode, UNLANG_SUB_FRAME), do_next_sibling) < 0) {
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
if (!g->variables) return UNLANG_ACTION_PUSHED_CHILD;
if (is_unwinding(frame)) goto calculate_result;
switch (ua) {
- case UNLANG_ACTION_STOP_PROCESSING:
- /*
- * This marks all the cancellable
- * frames with the unwind flag,
- * and starts popping them.
- */
- unlang_interpret_signal(request, FR_SIGNAL_CANCEL);
- return UNLANG_FRAME_ACTION_POP;
-
/*
* The operation resulted in additional frames
* being pushed onto the stack, execution should
*/
if (unlang_interpret_push(&redundant->result, request, redundant->child,
FRAME_CONF(RLM_MODULE_NOT_SET, UNLANG_SUB_FRAME), UNLANG_NEXT_STOP) < 0) {
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
uint32_t count = 0;
#ifdef STATIC_ANALYZER
- if (!g || unlang_list_empty(&g->children)) return UNLANG_ACTION_STOP_PROCESSING;
+ if (!g || unlang_list_empty(&g->children)) return UNLANG_ACTION_FAIL;
#else
fr_assert(g != NULL);
fr_assert(!unlang_list_empty(&g->children));
if (frame->instruction->type == UNLANG_TYPE_LOAD_BALANCE) {
if (unlang_interpret_push(p_result, request, redundant->start,
FRAME_CONF(RLM_MODULE_NOT_SET, UNLANG_SUB_FRAME), UNLANG_NEXT_STOP) < 0) {
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
}
case TMPL_TYPE_EXEC:
if (unlang_tmpl_push(map_proc_state, NULL, &map_proc_state->src_result,
request, inst->src, NULL, UNLANG_SUB_FRAME) < 0) {
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
case TMPL_TYPE_XLAT:
if (unlang_xlat_push(map_proc_state, NULL, &map_proc_state->src_result,
request, tmpl_xlat(inst->src), false) < 0) {
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
/*
* Push the xlat function
*/
- if (unlang_xlat_push(ctx, p_result, out, request, exp, false) < 0) return UNLANG_ACTION_STOP_PROCESSING;
+ if (unlang_xlat_push(ctx, p_result, out, request, exp, false) < 0) RETURN_UNLANG_ACTION_FATAL;
return UNLANG_ACTION_PUSHED_CHILD;
}
(void) unlang_module_yield(request, resume, signal, sigmask, rctx);
if (unlang_interpret_push_section(p_result, request, subcs,
- FRAME_CONF(default_rcode, UNLANG_SUB_FRAME)) < 0) return UNLANG_ACTION_STOP_PROCESSING;
+ FRAME_CONF(default_rcode, UNLANG_SUB_FRAME)) < 0) {
+ RETURN_UNLANG_ACTION_FATAL;
+ }
return UNLANG_ACTION_PUSHED_CHILD;
}
state->env_data, state->rctx), request);
safe_unlock(m->mmc.mi);
- if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
-
switch (ua) {
- case UNLANG_ACTION_STOP_PROCESSING:
- RWARN("Module %s or worker signalled to stop processing request", m->mmc.mi->name);
- state->thread->active_callers--;
- request->module = state->previous_module;
- p_result->rcode = RLM_MODULE_NOT_SET;
- p_result->priority = MOD_ACTION_NOT_SET;
- return UNLANG_ACTION_STOP_PROCESSING;
-
case UNLANG_ACTION_YIELD:
/*
* The module yielded but didn't set a
request);
safe_unlock(m->mmc.mi);
- if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
-
switch (ua) {
- /*
- * It is now marked as "stop" when it wasn't before, we
- * must have been blocked.
- */
- case UNLANG_ACTION_STOP_PROCESSING:
- RWARN("Module %s became unblocked", m->mmc.mi->name);
- request->module = state->previous_module;
- return UNLANG_ACTION_STOP_PROCESSING;
-
case UNLANG_ACTION_YIELD:
state->thread->active_callers++;
if (!found) return UNLANG_ACTION_EXECUTE_NEXT;
if (unlang_interpret_push(NULL, request, found, FRAME_CONF(RLM_MODULE_NOT_SET, UNLANG_SUB_FRAME), UNLANG_NEXT_STOP) < 0) {
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
.compile = unlang_compile_switch,
.interpret = unlang_switch,
-
+
.unlang_size = sizeof(unlang_switch_t),
.unlang_name = "unlang_switch_t",
if (fr_timer_in(state, unlang_interpret_event_list(request)->tl, &state->ev, state->timeout,
false, unlang_timeout_handler, state) < 0) {
RPEDEBUG("Failed inserting event");
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
frame_repeat(frame, unlang_timeout_resume_done);
push:
if (unlang_xlat_push(state->ctx, &state->xlat_result, &state->list, request, tmpl_xlat(ut->tmpl), UNLANG_SUB_FRAME) < 0) {
fail:
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
if (gext->catch[rcode]) {
if (unlang_interpret_push(NULL, request, gext->catch[rcode],
FRAME_CONF(RLM_MODULE_NOT_SET, UNLANG_SUB_FRAME), false) < 0) {
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
fr_value_box_list_talloc_free(&state->out);
if (unlang_xlat_push(state->ctx, p_result, &state->out, request, child, false) < 0) {
REXDENT();
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
fr_value_box_list_talloc_free(&state->out);
if (unlang_xlat_push(state->ctx, p_result, &state->out, request, child, false) < 0) {
RINDENT_RESTORE(request, state);
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
fr_value_box_list_talloc_free(&state->out);
if (unlang_xlat_push(state->ctx, state->p_result, &state->out, request, child, false) < 0) {
RINDENT_RESTORE(request, state);
- return UNLANG_ACTION_STOP_PROCESSING;
+ RETURN_UNLANG_ACTION_FATAL;
}
return UNLANG_ACTION_PUSHED_CHILD;
test_fail
}
-# This should timeout, so it must call success in the finally section
-call timeout-fin { }
+success
--- /dev/null
+# This should timeout, so it must call success in the finally section
+# Reply attributes are set in the finally section of the server we're calling
+# and checked with the response filter, as this request will get cancelled too.
+call timeout-fin { }
--- /dev/null
+# This should timeout, so it must call success in the finally section
+# Reply attributes are set in the finally section of the server we're calling
+# and checked with the response filter, as this request will get cancelled too.
+call module-timeout-fin { }
--- /dev/null
+Packet-Type = Access-Request
+
+# Should probably be Do-Not-Respond
+Result-Status == success
+Packet-Type == 0
+Reply-Message == bye-from-timeout-module
--- /dev/null
+# Regression test We'd set the request master state to "Stop Processing" and this
+# would result in module calls in finally being skipped.
+server module-timeout-fin {
+ namespace = radius
+
+ recv Access-Request {
+ # Trigger the overall timeout for the test binary
+ %time.advance(61s)
+ ok
+ }
+
+ finally {
+ if (timeout) {
+ # This previously resulted in the request processing terminating early
+ reschedule
+ reply.Reply-Message := 'bye-from-timeout-module'
+ success
+ } else {
+ fail
+ }
+ }
+}
--- /dev/null
+Packet-Type = Access-Request
+
+# Should probably be Do-Not-Respond
+Result-Status == success
+Packet-Type == 0
+Reply-Message == bye-from-timeout-fin
--- /dev/null
+server timeout-fin {
+ namespace = radius
+
+ recv Access-Request {
+ # Trigger the overall timeout for the test binary
+ %time.advance(61s)
+ ok
+ }
+
+ finally {
+ if (timeout) {
+ reply.Reply-Message := 'bye-from-timeout-fin'
+ success
+ } else {
+ fail
+ }
+ }
+}
fail
}
}
-
-server timeout-fin {
- namespace = radius
-
- recv Access-Request {
- # Trigger the overall timeout for the test binary
- %time.advance(61s)
- ok
- }
-
- finally {
- if (timeout) {
- Tmp-String-0 := 'bye-from-timeout-fin'
- success
- } else {
- fail
- }
- }
-}