]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add unlang_timeout_section_push()
authorAlan T. DeKok <aland@freeradius.org>
Fri, 18 Apr 2025 15:41:55 +0000 (11:41 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 18 Apr 2025 15:41:55 +0000 (11:41 -0400)
not overly tested, but the actual timeout handler only has minor
changes from the existing one.

src/lib/unlang/interpret.c
src/lib/unlang/interpret_priv.h
src/lib/unlang/timeout.c
src/lib/unlang/timeout.h [new file with mode: 0644]

index 8e6cd1cb0cee927d3bf27edf65a51a970f3a1ce5..466a277038e69404ddaaffc63c2999d9d52ccf3a 100644 (file)
@@ -1113,7 +1113,6 @@ void unlang_interpret_request_done(request_t *request)
        request->master_state = REQUEST_DONE;
 }
 
-static inline CC_HINT(always_inline)
 void unlang_interpret_request_stop(request_t *request)
 {
        unlang_stack_t          *stack = request->stack;
index e504fd93aa082e2c742379ffb04987fda23f8ad3..74209bdfaf499ba51cfa68d3e094f85df608e857 100644 (file)
@@ -45,6 +45,8 @@ static inline void interpret_child_init(request_t *request)
        intp->funcs.init_internal(request, intp->uctx);
 }
 
+void   unlang_interpret_request_stop(request_t *request);
+
 #ifdef __cplusplus
 }
 #endif
index a7c724e24171443b1f48e012f8037506e10eed74..50e901ee8da5a4d7a834b077d6f00b61dc37664d 100644 (file)
  */
 RCSID("$Id$")
 
+#include <freeradius-devel/unlang/timeout.h>
 #include "group_priv.h"
 #include "timeout_priv.h"
+#include "interpret_priv.h"
 
 typedef struct {
        bool                                    success;
@@ -36,6 +38,8 @@ typedef struct {
        fr_timer_t                              *ev;
 
        fr_value_box_list_t                     result;
+
+       unlang_t                                *instruction;   //!< to run on timeout
 } unlang_frame_state_timeout_t;
 
 static void unlang_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
@@ -55,6 +59,13 @@ static void unlang_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t
         */
        unlang_frame_signal(request, FR_SIGNAL_CANCEL, state->depth);
        state->success = false;
+
+       if (!state->instruction) return;
+
+       if (unlang_interpret_push_instruction(request, state->instruction, RLM_MODULE_FAIL, true) < 0) {
+               REDEBUG("Failed pushing timeout instruction - cancelling the request");
+               unlang_interpret_request_stop(request);
+       }
 }
 
 static unlang_action_t unlang_timeout_resume_done(UNUSED rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
@@ -136,6 +147,80 @@ static unlang_action_t unlang_timeout(rlm_rcode_t *p_result, request_t *request,
        return UNLANG_ACTION_PUSHED_CHILD;
 }
 
+/** When a timeout fires, run the given section.
+ *
+ * @param[in] request          to push timeout onto
+ * @param[in] timeout          when to run the timeout
+ * @param[in] cs               section to run when the timeout fires.
+ *
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+int unlang_timeout_section_push(request_t *request, CONF_SECTION *cs, fr_time_delta_t timeout)
+{
+       /** Static instruction for performing xlat evaluations
+        *
+        */
+       static unlang_t timeout_instruction = {
+               .type = UNLANG_TYPE_TIMEOUT,
+               .name = "timeout",
+               .debug_name = "timeout",
+               .actions = {
+                       .actions = {
+                               [RLM_MODULE_REJECT]     = 0,
+                               [RLM_MODULE_FAIL]       = MOD_ACTION_RETURN,    /* Exit out of nested levels */
+                               [RLM_MODULE_OK]         = 0,
+                               [RLM_MODULE_HANDLED]    = 0,
+                               [RLM_MODULE_INVALID]    = 0,
+                               [RLM_MODULE_DISALLOW]   = 0,
+                               [RLM_MODULE_NOTFOUND]   = 0,
+                               [RLM_MODULE_NOOP]       = 0,
+                               [RLM_MODULE_UPDATED]    = 0
+                       },
+                       .retry = RETRY_INIT,
+               },
+       };
+
+       unlang_frame_state_timeout_t    *state;
+       unlang_stack_t                  *stack = request->stack;
+       unlang_stack_frame_t            *frame;
+       unlang_t                        *instruction;
+
+       /*
+        *      Get the instruction we are supposed to run on timeout.
+        */
+       instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
+       if (!instruction) {
+               REDEBUG("Failed to find pre-compiled unlang for section %s { ... }",
+                       cf_section_name1(cs));
+               return -1;
+       }
+
+       /*
+        *      Push a new timeout frame onto the stack
+        */
+       if (unlang_interpret_push(request, &timeout_instruction,
+                                 RLM_MODULE_NOT_SET, UNLANG_NEXT_STOP, true) < 0) return -1;
+       frame = &stack->frame[stack->depth];
+
+       /*
+        *      Allocate its state, and set the timeout.
+        */
+       MEM(frame->state = state = talloc_zero(stack, unlang_frame_state_timeout_t));
+
+       state->timeout = timeout;
+       state->instruction = instruction;
+
+       if (unlang_timeout_set(&request->rcode, request, frame) != UNLANG_ACTION_PUSHED_CHILD) {
+               REDEBUG("Failed set timer for section %s { ... }",
+                       cf_section_name1(cs));
+               return -1;
+       }
+
+       return 0;
+
+}
 
 void unlang_timeout_init(void)
 {
diff --git a/src/lib/unlang/timeout.h b/src/lib/unlang/timeout.h
new file mode 100644 (file)
index 0000000..6daf372
--- /dev/null
@@ -0,0 +1,36 @@
+#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/timeout.h
+ * @brief Declarations for unlang timeouts
+ *
+ * @copyright 2023 Network RADIUS SAS (legal@networkradius.com)
+ */
+#include <freeradius-devel/server/request.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int    unlang_timeout_section_push(request_t *request, CONF_SECTION *cs, fr_time_delta_t timeout) CC_HINT(nonnull);
+
+#ifdef __cplusplus
+}
+#endif