From: Alan T. DeKok Date: Fri, 18 Apr 2025 15:41:55 +0000 (-0400) Subject: add unlang_timeout_section_push() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=21f33e2cd34741bb88b754fa9c35b2d3c432b482;p=thirdparty%2Ffreeradius-server.git add unlang_timeout_section_push() not overly tested, but the actual timeout handler only has minor changes from the existing one. --- diff --git a/src/lib/unlang/interpret.c b/src/lib/unlang/interpret.c index 8e6cd1cb0ce..466a277038e 100644 --- a/src/lib/unlang/interpret.c +++ b/src/lib/unlang/interpret.c @@ -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; diff --git a/src/lib/unlang/interpret_priv.h b/src/lib/unlang/interpret_priv.h index e504fd93aa0..74209bdfaf4 100644 --- a/src/lib/unlang/interpret_priv.h +++ b/src/lib/unlang/interpret_priv.h @@ -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 diff --git a/src/lib/unlang/timeout.c b/src/lib/unlang/timeout.c index a7c724e2417..50e901ee8da 100644 --- a/src/lib/unlang/timeout.c +++ b/src/lib/unlang/timeout.c @@ -24,8 +24,10 @@ */ RCSID("$Id$") +#include #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 index 00000000000..6daf3729254 --- /dev/null +++ b/src/lib/unlang/timeout.h @@ -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 + +#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