]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Start simplifying rcode handling
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sat, 10 May 2025 19:57:34 +0000 (13:57 -0600)
committerNick Porter <nick@portercomputing.co.uk>
Wed, 18 Jun 2025 12:52:55 +0000 (13:52 +0100)
22 files changed:
src/lib/unlang/call.c
src/lib/unlang/catch.c
src/lib/unlang/child_request.c
src/lib/unlang/edit.c
src/lib/unlang/finally.c
src/lib/unlang/foreach.c
src/lib/unlang/function.c
src/lib/unlang/group.c
src/lib/unlang/interpret.c
src/lib/unlang/limit.c
src/lib/unlang/load_balance.c
src/lib/unlang/mod_action.h
src/lib/unlang/module.c
src/lib/unlang/parallel.c
src/lib/unlang/return.c
src/lib/unlang/subrequest.c
src/lib/unlang/switch.c
src/lib/unlang/timeout.c
src/lib/unlang/transaction.c
src/lib/unlang/try.c
src/lib/unlang/unlang_priv.h
src/process/radius/base.c

index 2a3915e37e78b3c80d8a0d20b856a35e2c63867c..d72b057d199bb29fcc435b406c89f3cce977e358 100644 (file)
@@ -24,6 +24,7 @@
  */
 RCSID("$Id$")
 
+#include <freeradius-devel/server/rcode.h>
 #include <freeradius-devel/server/state.h>
 #include <freeradius-devel/server/pair.h>
 
@@ -57,7 +58,7 @@ static unlang_action_t unlang_call_children(rlm_rcode_t *p_result, request_t *re
         *      Push the contents of the call { } section onto the stack.
         *      This gets executed after the server returns.
         */
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 
index 7c23080f3bb85fed1da6574e3a327ff4b491671a..9c4b350c7a4ef0fa2240ccaed196dac568990d89 100644 (file)
@@ -24,6 +24,7 @@
  */
 RCSID("$Id$")
 
+#include <freeradius-devel/server/rcode.h>
 #include "unlang_priv.h"
 #include "catch_priv.h"
 
@@ -57,7 +58,7 @@ static unlang_action_t unlang_catch(rlm_rcode_t *p_result, request_t *request, u
         */
        frame_repeat(frame, catch_skip_to_next);
 
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 
index bea7c6cf3a5e53ae71ccbd4dd500112d12483888..c68c09a706eeee53b51ee981453ff6cc4f448096 100644 (file)
@@ -125,7 +125,7 @@ static void unlang_child_request_signal(request_t *request, UNUSED unlang_stack_
  * the child is done executing, it runs this to inform the parent
  * that its done.
  */
-static unlang_action_t unlang_child_request_done(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
+static unlang_action_t unlang_child_request_done(UNUSED rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
 {
        unlang_frame_state_child_request_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_child_request_t);
        unlang_child_request_t *cr = state->cr; /* Can't use talloc_get_type_abort, may be an array element */
@@ -154,8 +154,8 @@ static unlang_action_t unlang_child_request_done(rlm_rcode_t *p_result, request_
                 *      child be used to control the rcode of
                 *      the parallel keyword.
                 */
-               cr->result.rcode = *p_result;
-               cr->result.priority = frame->priority;
+               cr->result.rcode = frame->result.rcode;
+               cr->result.priority = frame->result.priority;
                if (cr->result.p_result) *(cr->result.p_result) = cr->result.rcode;
                break;
 
@@ -302,7 +302,7 @@ int unlang_child_request_op_init(void)
                                 *      to end normally so that non-detachable requests are
                                 *      guaranteed the parent still exists.
                                 */
-                               .flag = UNLANG_OP_FLAG_NO_CANCEL,
+                               .flag = UNLANG_OP_FLAG_NO_FORCE_UNWIND,
                                .frame_state_size = sizeof(unlang_frame_state_child_request_t),
                                .frame_state_type = "unlang_frame_state_child_request_t"
                        });
index 00f2e3c7030b3f46eecc5c9258c02184daed9787..8f16b47637515bc38fe2d7e2f2e8722dc4c27cac 100644 (file)
@@ -1631,7 +1631,6 @@ static unlang_action_t process_edit(rlm_rcode_t *p_result, request_t *request, u
 
        RINDENT_RESTORE(request, state);
 
-       *p_result = RLM_MODULE_NOOP;
        if (state->success) *state->success = true;
        return UNLANG_ACTION_CALCULATE_RESULT;
 }
index 1307234c2c59bfd78e52ae68c614c2302bec11d9..f172e99b72db4409325da757cddb7a7a66563fa7 100644 (file)
@@ -162,7 +162,7 @@ void unlang_finally_init(void)
                        &(unlang_op_t){
                                .name = "finally",
                                .interpret = unlang_finally,
-                               .flag = UNLANG_OP_FLAG_NO_CANCEL,       /* No debug braces, the thing that's pushed in unlang finally should have braces */
+                               .flag = UNLANG_OP_FLAG_NO_FORCE_UNWIND, /* No debug braces, the thing that's pushed in unlang finally should have braces */
                                .frame_state_size = sizeof(unlang_frame_state_finally_t),
                                .frame_state_type = "unlang_frame_state_finally_t",
                        });
index 681d4443f8e13f900c5e8d7efa124cd0c8cfbb70..4e6a021eccc2b0ed8a2beaf1a2241a5ab8f5b87a 100644 (file)
@@ -25,6 +25,9 @@
 RCSID("$Id$")
 
 #include <freeradius-devel/server/tmpl_dcursor.h>
+#include <freeradius-devel/server/rcode.h>
+#include <freeradius-devel/unlang/action.h>
+#include <freeradius-devel/unlang/unlang_priv.h>
 #include <freeradius-devel/unlang/xlat_func.h>
 
 #include "foreach_priv.h"
@@ -182,10 +185,7 @@ next:
        state->index++;
 
        box = fr_dcursor_next(&state->cursor);
-       if (!box) {
-               *p_result = frame->result;
-               return UNLANG_ACTION_CALCULATE_RESULT;
-       }
+       if (!box) return UNLANG_ACTION_EXECUTE_NEXT;    /* Don't change the section rcode */
 
        if (unlang_foreach_xlat_key_update(request, state) < 0) goto next;
 
@@ -200,7 +200,7 @@ next:
        /*
         *      Push the child, and yield for a later return.
         */
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 
@@ -233,13 +233,12 @@ next:
                goto next;
        }
 
-       frame->process = unlang_foreach_xlat_next;
-       repeatable_set(frame);
+       frame_repeat(frame, unlang_foreach_xlat_next);
 
        /*
         *      Push the child, and yield for a later return.
         */
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 
@@ -324,11 +323,10 @@ static unlang_action_t unlang_foreach_attr_next(rlm_rcode_t *p_result, request_t
 next:
        vp = fr_dcursor_next(&state->cursor);
        if (!vp) {
-               *p_result = frame->result;
 #ifndef NDEBUG
                fr_assert(state->indent == request->log.indent.unlang);
 #endif
-               return UNLANG_ACTION_CALCULATE_RESULT;
+               return UNLANG_ACTION_EXECUTE_NEXT;
        }
 
        unlang_foreach_attr_key_update(request, state);
@@ -375,7 +373,7 @@ next:
        /*
         *      Push the child, and yield for a later return.
         */
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 /*
@@ -435,9 +433,8 @@ next:
                        vp = fr_dcursor_next(&state->cursor);
                        if (vp) goto next;
 
-                       *p_result = frame->result;
                        fr_assert(state->indent == request->log.indent.unlang);
-                       return UNLANG_ACTION_CALCULATE_RESULT;
+                       return UNLANG_ACTION_EXECUTE_NEXT;
                }
 
                if (unlang_foreach_pair_copy(state->value, vp, vp->da) < 0) {
@@ -469,7 +466,7 @@ next:
        /*
         *      Push the child, and go process it.
         */
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 
@@ -535,7 +532,13 @@ static unlang_action_t unlang_break(rlm_rcode_t *p_result, request_t *request, u
 
        RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
 
-       *p_result = frame->result;
+       /*
+        *      As we're unwinding intermediary frames we
+        *      won't be taking their rcodes or priorities
+        *      into account.  We do however want to record
+        *      the current section rcode.
+        */
+       *p_result = frame->result.rcode;
 
        /*
         *      Stop at the next break point, or if we hit
index 4ed3886cde6e13846f50afe8d65f9b6538e9451c..f7a696982349b0546bb798bb32e71736c15c7067 100644 (file)
@@ -94,7 +94,12 @@ static unlang_action_t unlang_function_call_repeat(rlm_rcode_t *p_result, reques
        caller = request->module;
        request->module = NULL;
        RDEBUG4("Calling repeat function %p (%s)", state->repeat, state->repeat_name);
-       ua = state->repeat(p_result, &frame->priority, request, state->uctx);
+
+       /*
+        *      FIXME: The full scratch rcode/priority should be passed in
+        *      and then passed to this function.
+        */
+       ua = state->repeat(p_result, &frame->result.priority, request, state->uctx);
        request->module = caller;
 
        return ua;
@@ -120,7 +125,7 @@ static unlang_action_t unlang_function_call(rlm_rcode_t *p_result, request_t *re
        request->module = NULL;
 
        RDEBUG4("Calling function %p (%s)", state->func, state->func_name);
-       ua = state->func(p_result, &frame->priority, request, state->uctx);
+       ua = state->func(p_result, &frame->result.priority, request, state->uctx);
        switch (ua) {
        case UNLANG_ACTION_STOP_PROCESSING:
                break;
index 2ce631989a6429eb3c2136c65d546ba3f95296be..fb317f49486d4e0a99c205c94d7b037f3829a029 100644 (file)
  */
 RCSID("$Id$")
 
+#include <freeradius-devel/server/rcode.h>
 #include "unlang_priv.h"
 #include "group_priv.h"
 
-unlang_action_t unlang_group(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, UNUSED unlang_stack_frame_t *frame)
 {
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 static unlang_action_t unlang_policy(rlm_rcode_t *result, request_t *request, unlang_stack_frame_t *frame)
index 818a9e05769df69a1f00169c08961cf1aa0e94b8..28a76f345c44927fde9de6e8459c0efac3dc5917 100644 (file)
@@ -30,6 +30,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/modpriv.h>
 #include <freeradius-devel/unlang/xlat_func.h>
+#include <freeradius-devel/unlang/mod_action.h>
 
 #include "interpret_priv.h"
 #include "unlang_priv.h"
@@ -87,8 +88,8 @@ static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
        } else {
                RDEBUG2("next           <none>");
        }
-       RDEBUG2("result         %s", fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
-       RDEBUG2("priority       %d", frame->priority);
+       RDEBUG2("rcode          %s", fr_table_str_by_value(mod_rcode_table, frame->result.rcode, "<invalid>"));
+       RDEBUG2("priority       %d", frame->result.priority);
        RDEBUG2("top_frame      %s", is_top_frame(frame) ? "yes" : "no");
        RDEBUG2("repeat         %s", is_repeatable(frame) ? "yes" : "no");
        RDEBUG2("resumable      %s", is_yielded(frame) ? "yes" : "no");
@@ -185,8 +186,8 @@ int unlang_interpret_push(request_t *request, unlang_t const *instruction,
        frame->flag = UNLANG_FRAME_FLAG_NONE;
        if (top_frame) top_frame_set(frame);
 
-       frame->result = default_rcode;
-       frame->priority = -1;
+       frame->result.rcode = default_rcode;
+       frame->result.priority = MOD_ACTION_NOT_SET;
        frame->indent = request->log.indent;
 
        if (!instruction) return 0;
@@ -291,24 +292,20 @@ unlang_action_t unlang_interpret_push_children(UNUSED rlm_rcode_t *p_result, req
 static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx);
 
 /** Update the current result after each instruction, and after popping each stack frame
- *
  *
  * @note When called in frame_eval, result and priority are the frame
  *
- * @param[in] request          The current request.
- * @param[in] frame            The current stack frame.
- * @param[in,out] result       The current section or stack result.
- * @param[in,out] priority     The current section or stack priority.
+ * @param[in] request                  The current request.
  * @return
  *     - UNLANG_FRAME_ACTION_NEXT      evaluate more instructions.
  *     - UNLANG_FRAME_ACTION_POP       the final result has been calculated for this frame.
  */
 static inline CC_HINT(always_inline)
-unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t *frame,
-                                      rlm_rcode_t *result, unlang_mod_action_t *priority)
+unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t *frame, unlang_result_t *result)
 {
        unlang_t const  *instruction = frame->instruction;
        unlang_stack_t  *stack = request->stack;
+       unlang_result_t *frame_result = &frame->result;
 
        if (is_unwinding(frame)) {
                RDEBUG4("** [%i] %s - unwinding frame", stack->depth, __FUNCTION__);
@@ -319,7 +316,7 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
         *      Don't calculate a new return code for the frame, just skip
         *      to the next instruction.
         */
-       if (*result == RLM_MODULE_NOT_SET) {
+       if (result->rcode == RLM_MODULE_NOT_SET) {
                RDEBUG4("** [%i] %s - skipping frame, no result set",
                        stack->depth, __FUNCTION__);
                return UNLANG_FRAME_ACTION_NEXT;
@@ -327,10 +324,10 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
 
        RDEBUG4("** [%i] %s - have (%s %d) module returned (%s %d)",
                stack->depth, __FUNCTION__,
-               fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
-               frame->priority,
-               fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
-               *priority);
+               fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
+               frame_result->priority,
+               fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
+               result->priority);
 
        /*
         *      Update request->rcode if the instruction says we should
@@ -339,10 +336,34 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
         *      This is the field that's evaluated in unlang conditions
         *      like `if (ok)`.
         */
-       if (is_rcode_set(frame)) {
+       if (frame->instruction && is_rcode_set(frame)) {
                RDEBUG3("Setting rcode to '%s'",
-                       fr_table_str_by_value(rcode_table, *result, "<INVALID>"));
-               request->rcode = *result;
+                       fr_table_str_by_value(rcode_table, result->rcode, "<INVALID>"));
+               request->rcode = result->rcode;
+       }
+
+       /*
+        *      Sometimes we don't want the rcode from one frame to
+        *      propogate to the next, like when process modules push
+        *      sections onto the stack for evaluation.
+        */
+       if (!process_rcode(frame)) {
+               RDEBUG4("** [%i] %s - no rcode set, skipping frame",
+                       stack->depth, __FUNCTION__);
+               return UNLANG_FRAME_ACTION_NEXT;
+       }
+
+       /*
+        *      The array holds a default priority for this return
+        *      code.  Grab it in preference to any unset priority.
+        */
+       if (result->priority == MOD_ACTION_NOT_SET) {
+               result->priority = instruction->actions.actions[result->rcode];
+
+               RDEBUG4("** [%i] %s - using default instruction priority for %s, %d",
+                       stack->depth, __FUNCTION__,
+                       fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
+                       result->priority);
        }
 
        /*
@@ -350,20 +371,20 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
         *      to do something in addition to modifying the frame's
         *      rcode.
         */
-       switch (instruction->actions.actions[*result]) {
+       switch (result->priority) {
        /*
         *      The child's prioriy value indicates we
         *      should return from this frame.
         */
        case MOD_ACTION_RETURN:
-               if (*priority < 0) *priority = 0;
-
                RDEBUG4("** [%i] %s - action says to return with (%s %d)",
                        stack->depth, __FUNCTION__,
-                       fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
-                       *priority);
-               frame->result = *result;
-               frame->priority = *priority;
+                       fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
+                       result->priority);
+
+               frame_result->priority = 0;
+               frame_result->rcode = result->rcode;
+
                return UNLANG_FRAME_ACTION_POP;
 
        /*
@@ -376,14 +397,14 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
         *      after the module returns...
         */
        case MOD_ACTION_REJECT:
-               if (*priority < 0) *priority = 0;
-
                RDEBUG4("** [%i] %s - action says to return with (%s %d)",
                        stack->depth, __FUNCTION__,
                        fr_table_str_by_value(mod_rcode_table, RLM_MODULE_REJECT, "<invalid>"),
-                       *priority);
-               frame->result = RLM_MODULE_REJECT;
-               frame->priority = *priority;
+                       result->priority);
+
+               frame_result->priority = 0;
+               frame_result->rcode = RLM_MODULE_REJECT;
+
                return UNLANG_FRAME_ACTION_POP;
 
        case MOD_ACTION_RETRY:
@@ -393,8 +414,6 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
                RDEBUG4("** [%i] %s - action says to retry with",
                        stack->depth, __FUNCTION__);
 
-               if (*priority < 0) *priority = 0;
-
                /*
                 *      If this is the first time doing the retry,
                 *      then allocate the structure and set the timer.
@@ -418,7 +437,7 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
                                if (fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, instruction->actions.retry.mrd,
                                                false, instruction_retry_handler, request) < 0) {
                                        RPEDEBUG("Failed inserting retry event");
-                                       *result = RLM_MODULE_FAIL;
+                                       frame_result->rcode = RLM_MODULE_FAIL;
                                        goto finalize;
                                }
                        }
@@ -442,7 +461,7 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
                                        REDEBUG("Retries hit max_rtx_count (%u) - returning 'timeout'", instruction->actions.retry.mrc);
 
                                timeout:
-                                       *result = RLM_MODULE_TIMEOUT;
+                                       frame_result->rcode = RLM_MODULE_TIMEOUT;
                                        goto finalize;
                                }
                        }
@@ -467,30 +486,17 @@ unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t
 
 finalize:
        /*
-        *      The array holds a default priority for this return
-        *      code.  Grab it in preference to any unset priority.
-        */
-       if (*priority < 0) {
-               *priority = instruction->actions.actions[*result];
-
-               RDEBUG4("** [%i] %s - setting priority to (%s %d)",
-                       stack->depth, __FUNCTION__,
-                       fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
-                       *priority);
-       }
-
-       /*
-        *      We're higher than any previous priority, remember this
+        *      We're higher or equal to previous priority, remember this
         *      return code and priority.
         */
-       if (*priority > frame->priority) {
-               frame->result = *result;
-               frame->priority = *priority;
-
-               RDEBUG4("** [%i] %s - over-riding result from higher priority to (%s %d)",
+       if (result->priority > frame_result->priority) {
+               RDEBUG4("** [%i] %s - overwriting existing result (%s %d) with higher priority (%s %d)",
                        stack->depth, __FUNCTION__,
-                       fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
-                       *priority);
+                       fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
+                       frame_result->priority,
+                       fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
+                       result->priority);
+               frame->result = *result;
        }
 
        /*
@@ -507,10 +513,8 @@ finalize:
  *
  * This function can be seen as moving horizontally.
  *
- * @param[in] request          The current request.
- * @param[in] frame            The current stack frame.
- * @param[in,out] result       The current section result.
- * @param[in,out] priority     The current section priority.
+ * @param[in] request                  The current request.
+ * @param[in] frame                    The current stack frame.
  * @return
  *     - UNLANG_FRAME_ACTION_NEXT      evaluate more instructions in the current stack frame
  *                                     which may not be the same frame as when this function
@@ -518,9 +522,15 @@ finalize:
  *     - UNLANG_FRAME_ACTION_POP       the final result has been calculated for this frame.
  */
 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_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame)
 {
        unlang_stack_t  *stack = request->stack;
+       unlang_result_t *scratch = &stack->scratch;
+
+#define RESULT_RESET(_scratch) do { \
+       (_scratch)->rcode = RLM_MODULE_NOT_SET; \
+       (_scratch)->priority = MOD_ACTION_NOT_SET; \
+} while (0);
 
        /*
         *      Loop over all the instructions in this list.
@@ -599,13 +609,14 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
                 *      after this point, and the cached instruction
                 *      should be used instead.
                 */
-               ua = frame->process(result, request, frame);
+               ua = frame->process(&scratch->rcode, request, frame);
 
-               RDEBUG4("** [%i] %s << %s (%d)", stack->depth, __FUNCTION__,
-                       fr_table_str_by_value(unlang_action_table, ua, "<INVALID>"), *priority);
+               RDEBUG4("** [%i] %s << %s (%s %d)", stack->depth, __FUNCTION__,
+                       fr_table_str_by_value(unlang_action_table, ua, "<INVALID>"),
+                       fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"), scratch->priority);
 
-               fr_assert(*priority >= -1);
-               fr_assert(*priority <= MOD_PRIORITY_MAX);
+               fr_assert(scratch->priority >= MOD_ACTION_NOT_SET);
+               fr_assert(scratch->priority <= MOD_PRIORITY_MAX);
 
                /*
                 *      If the frame is cancelled we ignore the
@@ -624,6 +635,7 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
                         *      and starts popping them.
                         */
                        unlang_interpret_signal(request, FR_SIGNAL_CANCEL);
+                       RESULT_RESET(scratch);
                        return UNLANG_FRAME_ACTION_POP;
 
                /*
@@ -637,7 +649,7 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
                                      "but stack depth was not increased",
                                      instruction->name);
                        unlang_frame_perf_yield(frame);
-                       *result = frame->result;
+                       RESULT_RESET(scratch);
                        return UNLANG_FRAME_ACTION_NEXT;
 
                /*
@@ -652,8 +664,8 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
                        unlang_frame_perf_yield(frame);
                        yielded_set(frame);
                        RDEBUG4("** [%i] %s - yielding with current (%s %d)", stack->depth, __FUNCTION__,
-                               fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
-                               frame->priority);
+                               fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"),
+                               scratch->priority);
                        DUMP_STACK;
                        return UNLANG_FRAME_ACTION_YIELD;
 
@@ -662,7 +674,7 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
                 *      functions.  It reduces boilerplate.
                 */
                case UNLANG_ACTION_FAIL:
-                       *result = RLM_MODULE_FAIL;
+                       frame->result.rcode = RLM_MODULE_FAIL;  /* Let unlang_calculate figure out if this is the final result */
                        FALL_THROUGH;
 
                /*
@@ -693,20 +705,20 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
                                 */
                                if (RDEBUG_ENABLED && !RDEBUG_ENABLED2) {
                                        RDEBUG("# %s (%s)", instruction->debug_name,
-                                              fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
+                                              fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"));
                                } else {
                                        RDEBUG2("} # %s (%s)", instruction->debug_name,
-                                               fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
+                                               fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"));
                                }
                        }
 
+                       fa = result_calculate(request, frame, scratch);
+
                        /*
-                        *      RLM_MODULE_NOT_SET means the instruction
-                        *      doesn't want to modify the result.
+                        *      Scratch priority and rcode now consumed
                         */
-                       if (*result != RLM_MODULE_NOT_SET) *priority = instruction->actions.actions[*result];
+                       RESULT_RESET(scratch);
 
-                       fa = result_calculate(request, frame, result, priority);
                        switch (fa) {
                        case UNLANG_FRAME_ACTION_POP:
                                goto pop;
@@ -731,6 +743,11 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
                                REXDENT();
                                RDEBUG2("}");
                        }
+
+                       /*
+                        *      Scratch priority and rcode now discarded
+                        */
+                       RESULT_RESET(scratch);
                        break;
                } /* switch over return code from the interpret function */
 
@@ -740,8 +757,8 @@ unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame
 pop:
        RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
                stack->depth, __FUNCTION__,
-               fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
-               frame->priority);
+               fr_table_str_by_value(mod_rcode_table, frame->result.rcode, "<invalid>"),
+               frame->result.priority);
 
        return UNLANG_FRAME_ACTION_POP;
 }
@@ -758,8 +775,6 @@ pop:
  */
 CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
 {
-       rlm_rcode_t             rcode;
-
        /*
         *      We don't have a return code yet.
         */
@@ -775,8 +790,6 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
         */
        unlang_frame_action_t   fa = is_unwinding(frame) ? UNLANG_FRAME_ACTION_POP : UNLANG_FRAME_ACTION_NEXT;
 
-       stack->priority = -1;   /* Reset */
-
 #ifndef NDEBUG
        if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
        DUMP_STACK;
@@ -797,20 +810,15 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
                switch (fa) {
                case UNLANG_FRAME_ACTION_NEXT:  /* Evaluate the current frame */
                        frame = &stack->frame[stack->depth];
-                       fa = frame_eval(request, frame, &stack->result, &stack->priority);
+                       fa = frame_eval(request, frame);
                        if (fa != UNLANG_FRAME_ACTION_POP) continue;
                        FALL_THROUGH;
 
-               case UNLANG_FRAME_ACTION_POP:           /* Pop this frame and check the one beneath it */
+               case UNLANG_FRAME_ACTION_POP:                           /* Pop this frame and check the one beneath it */
                {
                        bool top_frame = is_top_frame(frame);
-                       /*
-                        *      The result / priority is returned from the sub-section,
-                        *      and made into our current result / priority, as
-                        *      if we had performed a module call.
-                        */
-                       stack->result = frame->result;
-                       stack->priority = frame->priority;
+
+                       unlang_result_t section_result = frame->result; /* record the result of the frame before we pop it*/
 
                        /*
                         *      Head on back up the stack
@@ -818,20 +826,33 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
                        frame_pop(request, stack);
 
                        /*
-                        *      Transition back to the C stack
+                        *      Update the stack frame
                         */
-                       if (top_frame) break;   /* stop */
-
                        frame = &stack->frame[stack->depth];
                        DUMP_STACK;
 
+                       /*
+                        *      Transition back to the C stack
+                        *
+                        *      We still need to merge in the previous frame's result,
+                        *      but we don't care about the action, as we're returning.
+                        */
+                       if (top_frame) {
+                               (void)result_calculate(request, frame, &section_result);
+                               break;  /* stop */
+                       }
+
                        /*
                         *      Resume a "foreach" loop, or a "load-balance" section
                         *      or anything else that needs to be checked on the way
                         *      back on up the stack.
                         */
-
                        if (!is_unwinding(frame) && is_repeatable(frame)) {
+                               (void)result_calculate(request, frame, &section_result);
+                               RDEBUG4("** [%i] %s - repeating frame with (%s %d)",
+                                       stack->depth, __FUNCTION__,
+                                       fr_table_str_by_value(mod_rcode_table, frame->result.rcode, "<invalid>"),
+                                       frame->result.priority);
                                fa = UNLANG_FRAME_ACTION_NEXT;
                                continue;
                        }
@@ -848,14 +869,14 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
                                 */
                                if (RDEBUG_ENABLED && !RDEBUG_ENABLED2) {
                                        RDEBUG("# %s (%s)", frame->instruction->debug_name,
-                                              fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
+                                              fr_table_str_by_value(mod_rcode_table, section_result.rcode, "<invalid>"));
                                } else {
                                        RDEBUG2("} # %s (%s)", frame->instruction->debug_name,
-                                               fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
+                                               fr_table_str_by_value(mod_rcode_table, section_result.rcode, "<invalid>"));
                                }
                        }
 
-                       fa = result_calculate(request, frame, &stack->result, &stack->priority);
+                       fa = result_calculate(request, frame, &section_result);
 
                        /*
                         *      If we're continuing after popping a frame
@@ -865,8 +886,8 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
                        if (fa == UNLANG_FRAME_ACTION_NEXT) {
                                RDEBUG4("** [%i] %s - continuing after subsection with (%s %d)",
                                        stack->depth, __FUNCTION__,
-                                       fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
-                                       stack->priority);
+                                       fr_table_str_by_value(mod_rcode_table, frame->result.rcode, "<invalid>"),
+                                       frame->result.priority);
                                frame_next(stack, frame);
 
                        /*
@@ -876,8 +897,8 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
                        } else {
                                RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
                                        stack->depth, __FUNCTION__,
-                                       fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
-                                       frame->priority);
+                                       fr_table_str_by_value(mod_rcode_table, frame->result.rcode, "<invalid>"),
+                                       frame->result.priority);
                        }
                        continue;
                }
@@ -888,7 +909,7 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
 
                        RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
                        intp->funcs.yield(request, intp->uctx);
-                       return stack->result;
+                       return RLM_MODULE_NOT_SET;
 
                case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
                        fa = UNLANG_FRAME_ACTION_NEXT;
@@ -899,50 +920,31 @@ CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
 
        fr_assert(stack->depth >= 0);
 
-       /*
-        *      Nothing in this section, use the top frame stack->result.
-        */
-       if ((stack->priority < 0) || (stack->result == RLM_MODULE_NOT_SET)) {
-               RDEBUG4("** [%i] %s - empty section, using stack result (%s %d)", stack->depth, __FUNCTION__,
-                       fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"), stack->priority);
-               stack->result = frame->result;
-               stack->priority = frame->priority;
-       }
-
-       if (stack->priority > frame->priority) {
-               frame->result = stack->result;
-               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>"),
-                       stack->priority);
-       }
-
        /*
         *      We're at the top frame, return the result from the
         *      stack, and get rid of the top frame.
         */
        RDEBUG4("** [%i] %s - interpret exiting, returning %s", stack->depth, __FUNCTION__,
-               fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
-
-       stack->result = frame->result;
+               fr_table_str_by_value(mod_rcode_table, frame->result.rcode, "<invalid>"));
 
        DUMP_STACK;
 
-       /*
-        *      Record this now as the done functions may free
-        *      the request.
-        */
-       rcode = stack->result;
+       {
+               rlm_rcode_t             rcode;
+               /*
+                *      Record this now as the done functions may free
+                *      the request.
+                */
+               rcode = frame->result.rcode;
 
-       /*
-        *      This usually means the request is complete in its
-        *      entirety.
-        */
-       if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
+               /*
+               *       This usually means the request is complete in its
+               *       entirety.
+               */
+               if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
 
-       return rcode;
+               return rcode;
+       }
 }
 
 static unlang_group_t empty_group = {
@@ -1041,7 +1043,8 @@ void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
         *      like too low level to make into a tuneable.
         */
        MEM(stack = talloc_zero_pooled_object(ctx, unlang_stack_t, UNLANG_STACK_MAX, 128));     /* 128 bytes per state */
-       stack->result = RLM_MODULE_NOT_SET;
+       stack->scratch.rcode = RLM_MODULE_NOT_SET;
+       stack->scratch.priority = MOD_ACTION_NOT_SET;
 
        return stack;
 }
@@ -1061,15 +1064,15 @@ void unlang_interpret_request_done(request_t *request)
        request->master_state = REQUEST_DONE;
        switch (request->type) {
        case REQUEST_TYPE_EXTERNAL:
-               intp->funcs.done_external(request, stack->result, intp->uctx);
+               intp->funcs.done_external(request, frame_current(request)->result.rcode, intp->uctx);
                break;
 
        case REQUEST_TYPE_INTERNAL:
-               intp->funcs.done_internal(request, stack->result, intp->uctx);
+               intp->funcs.done_internal(request, frame_current(request)->result.rcode, intp->uctx);
                break;
 
        case REQUEST_TYPE_DETACHED:
-               intp->funcs.done_detached(request, stack->result, intp->uctx);  /* Callback will usually free the request */
+               intp->funcs.done_detached(request, frame_current(request)->result.rcode, intp->uctx);   /* Callback will usually free the request */
                break;
        }
 }
@@ -1336,9 +1339,7 @@ int unlang_interpret_stack_depth(request_t *request)
  */
 rlm_rcode_t unlang_interpret_stack_result(request_t *request)
 {
-       unlang_stack_t          *stack = request->stack;
-
-       return stack->result;
+       return frame_current(request)->result.rcode;
 }
 
 /** Overwrite the current stack rcode
@@ -1348,9 +1349,7 @@ rlm_rcode_t unlang_interpret_stack_result(request_t *request)
  */
 void unlang_interpret_stack_result_set(request_t *request, rlm_rcode_t rcode)
 {
-       unlang_stack_t          *stack = request->stack;
-
-       stack->result = rcode;
+       frame_current(request)->result.rcode = rcode;
 }
 
 /** Return whether a request is currently scheduled
index 877c9c8dc5b54ca5e13887b2427cb6cc55886b94..9b95242c9338b9cf949573979b9cbc950b36d96b 100644 (file)
@@ -24,6 +24,7 @@
  */
 RCSID("$Id$")
 
+#include <freeradius-devel/server/rcode.h>
 #include "group_priv.h"
 #include "limit_priv.h"
 
@@ -75,7 +76,7 @@ static unlang_action_t unlang_limit_enforce(rlm_rcode_t *p_result, request_t *re
 
        frame_repeat(frame, unlang_limit_resume_done);
 
-       action = unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_STOP);
+       action = unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP);
 
        state->thread->active_callers += (action == UNLANG_ACTION_PUSHED_CHILD);
 
index 5ad345fcc443d095a88cafb4293fce4d5d5f0e01..68fb0028a7fb2904ea81c4f0baf7857e75c3f78b 100644 (file)
@@ -22,6 +22,7 @@
  *
  * @copyright 2006-2019 The FreeRADIUS server project
  */
+#include <freeradius-devel/server/rcode.h>
 #include <freeradius-devel/util/hash.h>
 #include <freeradius-devel/util/rand.h>
 
@@ -81,7 +82,7 @@ static unlang_action_t unlang_load_balance_next(rlm_rcode_t *p_result, request_t
        /*
         *      Push the child, and yield for a later return.
         */
-       if (unlang_interpret_push(request, redundant->child, frame->result, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
+       if (unlang_interpret_push(request, redundant->child, RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
                return UNLANG_ACTION_STOP_PROCESSING;
        }
 
@@ -228,7 +229,7 @@ static unlang_action_t unlang_load_balance(rlm_rcode_t *p_result, request_t *req
         */
        if (frame->instruction->type == UNLANG_TYPE_LOAD_BALANCE) {
                if (unlang_interpret_push(request, redundant->found,
-                                         frame->result, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
+                                         RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
                        return UNLANG_ACTION_STOP_PROCESSING;
                }
                return UNLANG_ACTION_PUSHED_CHILD;
index ac78e6c39cd230790bbb722b8b7505a81512c67c..a9df7162a5cc218f059d11214801c622a9bc1d25 100644 (file)
@@ -37,9 +37,11 @@ extern "C" {
  * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
  * to cause an immediate reject. */
 typedef enum {
-       MOD_ACTION_RETURN = -1,
-       MOD_ACTION_REJECT = -2,
+       MOD_ACTION_NOT_SET = -4,
        MOD_ACTION_RETRY = -3,
+       MOD_ACTION_REJECT = -2,
+       MOD_ACTION_RETURN = -1,
+
 
        MOD_PRIORITY_MIN = 0,
        MOD_PRIORITY_1 = 1,
index 5b50d837676986d68ef0c2f42f5a6ee929177f59..05f2c0d9811136c8ab0854a72613804fa546b9f2 100644 (file)
@@ -264,7 +264,7 @@ unlang_action_t unlang_module_yield_to_section(rlm_rcode_t *p_result,
                 *      frame->result will be overwritten
                 *      anyway when we return.
                 */
-               stack->result = frame->result = default_rcode;
+               *p_result = default_rcode;
                state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
 
                return resume(p_result,
index c8efa28e7637bb174298605681b77f810b9c4e87..62269bcc77b2bb5b4bb170cfcb4e826e30262939 100644 (file)
@@ -140,6 +140,8 @@ static unlang_action_t unlang_parallel_resume(rlm_rcode_t *p_result, request_t *
        fr_assert(state->num_runnable == 0);
 
        for (i = 0; i < state->num_children; i++) {
+               unlang_stack_frame_t *child_frame;
+
                if (state->children[i].state != CHILD_EXITED) continue;
 
                REQUEST_VERIFY(state->children[i].request);
@@ -150,8 +152,10 @@ static unlang_action_t unlang_parallel_resume(rlm_rcode_t *p_result, request_t *
 
                state->children[i].state = CHILD_DONE;
 
-               priority = ((unlang_stack_t *)state->children[i].request->stack)->priority;
-               result = ((unlang_stack_t *)state->children[i].request->stack)->result;
+               child_frame = frame_current(state->children[i].request);
+
+               priority = child_frame->result.priority;
+               result = child_frame->result.rcode;
 
                /*
                 *      Return isn't allowed to make it back
@@ -390,6 +394,6 @@ void unlang_parallel_init(void)
                                .name = "parallel",
                                .interpret = unlang_parallel,
                                .signal = unlang_parallel_signal,
-                               .flag = UNLANG_OP_FLAG_DEBUG_BRACES | UNLANG_OP_FLAG_RCODE_SET | UNLANG_OP_FLAG_NO_CANCEL
+                               .flag = UNLANG_OP_FLAG_DEBUG_BRACES | UNLANG_OP_FLAG_RCODE_SET | UNLANG_OP_FLAG_NO_FORCE_UNWIND
                           });
 }
index 2bb9e011083f67c6adcdcabb9560b2698f77d9fb..9a5cbf3e0f69653311f5c7c62b130570a3860809 100644 (file)
@@ -31,7 +31,13 @@ unlang_action_t unlang_return(rlm_rcode_t *p_result, request_t *request, unlang_
 {
        RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
 
-       *p_result = frame->result;
+       /*
+        *      As we're unwinding intermediary frames we
+        *      won't be taking their rcodes or priorities
+        *      into account.  We do however want to record
+        *      the current section rcode.
+        */
+       *p_result = frame->result.rcode;
 
        /*
         *      Stop at the next return point, or if we hit
index 06fb3ba4fa974b3569dfec812b2b9494c65490ef..5fcb17451093c389630957ceffb41d872811c20b 100644 (file)
@@ -28,6 +28,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/state.h>
 #include <freeradius-devel/server/tmpl_dcursor.h>
 #include <freeradius-devel/server/request.h>
+#include <freeradius-devel/server/rcode.h>
 #include <freeradius-devel/unlang/action.h>
 #include "unlang_priv.h"
 #include "interpret_priv.h"
@@ -119,8 +120,11 @@ static unlang_action_t unlang_subrequest_parent_resume(rlm_rcode_t *p_result, re
        RDEBUG3("subrequest completeed with rcode %s",
                fr_table_str_by_value(mod_rcode_table, cr->result.rcode, "<invalid>"));
 
+       /*
+        *      FIXME - We should pass in priority
+        */
        *p_result = cr->result.rcode;
-       frame->priority = cr->result.priority;
+       frame->result.priority = cr->result.priority;
 
        /*
         *      If there's a no destination tmpl, we're done.
@@ -263,7 +267,7 @@ static unlang_action_t unlang_subrequest_init(rlm_rcode_t *p_result, request_t *
         *      Push the first instruction the child's
         *      going to run.
         */
-       if (unlang_interpret_push(child, g->children, frame->result,
+       if (unlang_interpret_push(child, g->children, RLM_MODULE_NOT_SET,
                                  UNLANG_NEXT_SIBLING, UNLANG_SUB_FRAME) < 0) goto fail;
 
        /*
@@ -320,7 +324,7 @@ static unlang_action_t unlang_subrequest_child_done(rlm_rcode_t *p_result, UNUSE
        }
 
        if (cr->result.p_result) *cr->result.p_result = cr->result.rcode;
-       cr->result.priority = frame->priority;
+       cr->result.priority = frame->result.priority;
 
        /*
         *      We can free the child here as we're its parent
@@ -531,7 +535,7 @@ int unlang_subrequest_op_init(void)
                                 *      to end normally so that non-detachable requests are
                                 *      guaranteed the parent still exists.
                                 */
-                               .flag = UNLANG_OP_FLAG_DEBUG_BRACES | UNLANG_OP_FLAG_RCODE_SET | UNLANG_OP_FLAG_NO_CANCEL,
+                               .flag = UNLANG_OP_FLAG_DEBUG_BRACES | UNLANG_OP_FLAG_RCODE_SET | UNLANG_OP_FLAG_NO_FORCE_UNWIND,
                                .frame_state_size = sizeof(unlang_child_request_t),
                                .frame_state_type = "unlang_child_request_t",
                        });
index 21eb6e388e158957c2c20efb9e26d8709a1eb443..2d1739eee36eca32ffa854ce16685ce7e238615c 100644 (file)
@@ -24,6 +24,7 @@
  */
 RCSID("$Id$")
 
+#include <freeradius-devel/server/rcode.h>
 #include "group_priv.h"
 #include "switch_priv.h"
 
@@ -110,7 +111,7 @@ do_null_case:
         */
        if (!found) return UNLANG_ACTION_EXECUTE_NEXT;
 
-       if (unlang_interpret_push(request, found, frame->result, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
+       if (unlang_interpret_push(request, found, RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, UNLANG_SUB_FRAME) < 0) {
                return UNLANG_ACTION_STOP_PROCESSING;
        }
 
index d9e6b6e2f65e4fcec1856e2c52e5d637acb6e677..c4af970979b854c441c1b52685153435ae263af6 100644 (file)
@@ -134,7 +134,7 @@ static unlang_action_t unlang_timeout_set(rlm_rcode_t *p_result, request_t *requ
 
        frame_repeat(frame, unlang_timeout_resume_done);
 
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 static unlang_action_t unlang_timeout_done(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
index 6b2fe61966bc3ad6a30e3c76af8c0dba81c89b05..98e232a0045293735cdec1196374e1c4a0314eb1 100644 (file)
@@ -94,7 +94,7 @@ static unlang_action_t unlang_transaction(rlm_rcode_t *p_result, request_t *requ
 
        frame_repeat(frame, unlang_transaction_final);
 
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 fr_edit_list_t *unlang_interpret_edit_list(request_t *request)
index 69d2ee5f85a5c97e8f256e6f675d40d8de628d23..a1d22cd7b138c2a191feead3d33f0027a5cebcb4 100644 (file)
@@ -36,7 +36,7 @@ static unlang_action_t unlang_try(rlm_rcode_t *p_result, request_t *request, unl
         */
        frame_repeat(frame, unlang_interpret_skip_to_catch);
 
-       return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING);
+       return unlang_interpret_push_children(p_result, request, RLM_MODULE_NOT_SET, UNLANG_NEXT_SIBLING);
 }
 
 void unlang_try_init(void)
index 6821cec71821fb9875da86b29fb6ff37ca90bdfd..617028d2f6ec73c5361fc7220752755b8dbaf69a 100644 (file)
@@ -216,18 +216,18 @@ typedef int (*unlang_thread_instantiate_t)(unlang_t const *instruction, void *th
 
 DIAG_OFF(attributes)
 typedef enum CC_HINT(flag_enum) {
-       UNLANG_OP_FLAG_NONE             = 0x00,                 //!< No flags.
-       UNLANG_OP_FLAG_DEBUG_BRACES     = 0x01,                 //!< Print debug braces.
-       UNLANG_OP_FLAG_RCODE_SET        = 0x02,                 //!< Set request->rcode to the result of this operation.
-       UNLANG_OP_FLAG_NO_CANCEL        = 0x04,                 //!< Must not be cancelled.
-                                                               ///< @Note Slightly confusingly, a cancellation signal
-                                                               ///< can still be delivered to a frame that is not
-                                                               ///< cancellable, but the frame won't be automatically
-                                                               ///< unwound.  This lets the frame know that cancellation
-                                                               ///< is desired, but can be ignored.
-       UNLANG_OP_FLAG_BREAK_POINT      = 0x08,                 //!< Break point.
-       UNLANG_OP_FLAG_RETURN_POINT     = 0x10,                 //!< Return point.
-       UNLANG_OP_FLAG_CONTINUE_POINT   = 0x20                  //!< Continue point.
+       UNLANG_OP_FLAG_NONE                     = 0x00,                 //!< No flags.
+       UNLANG_OP_FLAG_DEBUG_BRACES             = 0x01,                 //!< Print debug braces.
+       UNLANG_OP_FLAG_RCODE_SET                = 0x02,                 //!< Set request->rcode to the result of this operation.
+       UNLANG_OP_FLAG_NO_FORCE_UNWIND          = 0x04,                 //!< Must not be cancelled.
+                                                                       ///< @Note Slightly confusingly, a cancellation signal
+                                                                       ///< can still be delivered to a frame that is not
+                                                                       ///< cancellable, but the frame won't be automatically
+                                                                       ///< unwound.  This lets the frame know that cancellation
+                                                                       ///< is desired, but can be ignored.
+       UNLANG_OP_FLAG_BREAK_POINT              = 0x08,                 //!< Break point.
+       UNLANG_OP_FLAG_RETURN_POINT             = 0x10,                 //!< Return point.
+       UNLANG_OP_FLAG_CONTINUE_POINT           = 0x20                  //!< Continue point.
 } unlang_op_flag_t;
 DIAG_ON(attributes)
 
@@ -295,6 +295,12 @@ typedef struct {
        fr_timer_t              *ev;
 } unlang_retry_t;
 
+typedef struct {
+       rlm_rcode_t             rcode;                          //!< The current rcode, from executing the instruction
+                                                               ///< or merging the result from a frame.
+       unlang_mod_action_t     priority;                       //!< The priority or action for that rcode.
+} unlang_result_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
@@ -325,13 +331,16 @@ struct unlang_stack_frame_s {
         */
        void                    *state;
 
+       /** Running priority and rcode associated with the stack
+        *
+        * If this frame is cancelled, the rcode and priority are not merged into
+        * the frame above and are discarded.
+        */
+       unlang_result_t         result;
+
        unlang_retry_t          *retry;                         //!< if the frame is being retried.
 
-       rlm_rcode_t             result;                         //!< The result from executing the instruction.
-       unlang_mod_action_t     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
+
        rindent_t               indent;                         //!< Indent level of the request when the frame was
                                                                ///< created.  This is used to restore the indent
                                                                ///< level when the stack is being forcefully unwound.
@@ -348,8 +357,15 @@ struct unlang_stack_frame_s {
 typedef struct {
        unlang_interpret_t      *intp;                          //!< Interpreter that the request is currently
                                                                ///< associated with.
-       unlang_mod_action_t     priority;                       //!< Current priority.
-       rlm_rcode_t             result;                         //!< The current stack rcode.
+
+       unlang_result_t         scratch;                        //!< This holds the current rcode and
+                                                               ///< priority for the current instruction.
+                                                               ///< It's located in the stack struct because
+                                                               ///< we only need it for the current frame
+                                                               ///< executing, and we need it to persist
+                                                               ///< across yields.  It should be reset for
+                                                               ///< each new instruction executed.
+
        int                     depth;                          //!< Current depth we're executing at.
        uint8_t                 unwind;                         //!< Unwind to this frame if it exists.
                                                                ///< This is used for break and return.
@@ -390,7 +406,7 @@ static inline bool _frame_has_debug_braces(unlang_stack_frame_t const *frame)       {
                        unlang_stack_frame_t const *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)) \
                   )
 static inline bool is_rcode_set(unlang_stack_frame_t const *frame)             { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_RCODE_SET; }
-static inline bool is_cancellable(unlang_stack_frame_t const *frame)           { return !(unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_NO_CANCEL); }
+static inline bool is_cancellable(unlang_stack_frame_t const *frame)           { return !(unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_NO_FORCE_UNWIND); }
 static inline bool is_break_point(unlang_stack_frame_t const *frame)           { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_BREAK_POINT; }
 static inline bool is_return_point(unlang_stack_frame_t const *frame)          { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_RETURN_POINT; }
 static inline bool is_continue_point(unlang_stack_frame_t const *frame)        { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_CONTINUE_POINT; }
index 4255bd4f98ed474ceab12a83b3d198f96b249702..66745869d0669f381638205a405b9721a48efc78 100644 (file)
@@ -459,7 +459,7 @@ RESUME(auth_type)
                [RLM_MODULE_DISALLOW] = FR_RADIUS_CODE_ACCESS_REJECT,
        };
 
-       rlm_rcode_t                     rcode = *p_result;
+       rlm_rcode_t                     rcode = unlang_interpret_stack_result(request);
        fr_pair_t                       *vp;
        fr_process_state_t const        *state;