From: Alan T. DeKok Date: Thu, 14 Dec 2023 18:01:57 +0000 (-0500) Subject: implement try / catch X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2817f91154b60ecbb8f241e93c07d8490184480c;p=thirdparty%2Ffreeradius-server.git implement try / catch there's no compilation, but the intended functionality is present. --- diff --git a/src/lib/unlang/all.mk b/src/lib/unlang/all.mk index 5d8c86623ce..2ad383d62c5 100644 --- a/src/lib/unlang/all.mk +++ b/src/lib/unlang/all.mk @@ -4,6 +4,7 @@ SOURCES := base.c \ call.c \ call_env.c \ caller.c \ + catch.c \ compile.c \ condition.c \ detach.c \ @@ -25,6 +26,7 @@ SOURCES := base.c \ switch.c \ timeout.c \ tmpl.c \ + try.c \ transaction.c \ xlat.c \ xlat_alloc.c \ diff --git a/src/lib/unlang/base.c b/src/lib/unlang/base.c index 11d25d90b6c..6315efb20cb 100644 --- a/src/lib/unlang/base.c +++ b/src/lib/unlang/base.c @@ -123,6 +123,8 @@ int unlang_init_global(void) unlang_timeout_init(); unlang_limit_init(); unlang_transaction_init(); + unlang_try_init(); + unlang_catch_init(); instance_count++; diff --git a/src/lib/unlang/catch.c b/src/lib/unlang/catch.c new file mode 100644 index 00000000000..a5f5934e145 --- /dev/null +++ b/src/lib/unlang/catch.c @@ -0,0 +1,121 @@ +/* + * 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 of the License, 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file unlang/catch.c + * @brief Unlang "catch" keyword evaluation. + * + * @copyright 2023 Network RADIUS SAS (legal@networkradius.com) + */ +RCSID("$Id$") + +#include "unlang_priv.h" +#include "catch_priv.h" + +static unlang_action_t cleanup(unlang_stack_frame_t *frame, unlang_t *unlang) +{ + + /* + * Clean up this frame now, so that stats, etc. will be + * processed using the correct frame. + */ + frame_cleanup(frame); + + /* + * frame_next() will call cleanup *before* resetting the frame->instruction. + * but since the instruction is NULL, no duplicate cleanups will happen. + * + * frame_next() will then set frame->instruction = frame->next, and everything will be OK. + */ + frame->instruction = NULL; + frame->next = unlang; + return UNLANG_ACTION_EXECUTE_NEXT; +} + +static unlang_action_t catch_skip_to_next(UNUSED rlm_rcode_t *p_result, UNUSED request_t *request, unlang_stack_frame_t *frame) +{ + unlang_t *unlang; + + fr_assert(frame->instruction->type == UNLANG_TYPE_CATCH); + + for (unlang = frame->instruction->next; + unlang != NULL; + unlang = unlang->next) { + if (unlang->type == UNLANG_TYPE_CATCH) continue; + + break; + } + + return cleanup(frame, unlang); +} + +static unlang_action_t unlang_catch(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame) +{ +#ifndef NDEBUG + unlang_catch_t const *c = unlang_generic_to_catch(frame->instruction); + + fr_assert(c->catching[*p_result]); +#endif + + /* + * Skip over any "catch" statementa after this one. + */ + frame_repeat(frame, catch_skip_to_next); + + return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING); +} + + +/** Skip ahead to a particular "catch" instruction. + * + */ +unlang_action_t unlang_interpret_skip_to_catch(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame) +{ + unlang_t *unlang; + + fr_assert(frame->instruction->type == UNLANG_TYPE_TRY); + + for (unlang = frame->instruction->next; + unlang != NULL; + unlang = unlang->next) { + unlang_catch_t const *c; + + if (unlang->type != UNLANG_TYPE_CATCH) { + REDEBUG("Failed to 'catch' error %s", + fr_table_str_by_value(mod_rcode_table, *p_result, "")); + return UNLANG_ACTION_CALCULATE_RESULT; + } + + c = unlang_generic_to_catch(unlang); + if (c->catching[*p_result]) break; + } + + fr_assert(unlang != NULL); + + return cleanup(frame, unlang); +} + +void unlang_catch_init(void) +{ + unlang_register(UNLANG_TYPE_CATCH, + &(unlang_op_t){ + .name = "catch", + .interpret = unlang_catch, + .debug_braces = true + }); +} diff --git a/src/lib/unlang/catch_priv.h b/src/lib/unlang/catch_priv.h new file mode 100644 index 00000000000..c394348cfa3 --- /dev/null +++ b/src/lib/unlang/catch_priv.h @@ -0,0 +1,58 @@ +#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/catch_priv.h + * @brief Declarations for the "catch" keyword + * + * @copyright 2006-2019 The FreeRADIUS server project + */ +#include "unlang_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + unlang_group_t group; + + bool catching[RLM_MODULE_NUMCODES]; +} unlang_catch_t; + +unlang_action_t unlang_interpret_skip_to_catch(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame); + +/** Cast a group structure to the transaction keyword extension + * + */ +static inline unlang_catch_t *unlang_group_to_catch(unlang_group_t *g) +{ + return talloc_get_type_abort(g, unlang_catch_t); +} + +/** Cast a generic structure to the catch keyword extension + * + */ +static inline unlang_catch_t const *unlang_generic_to_catch(unlang_t const *g) +{ + return talloc_get_type_abort_const(g, unlang_catch_t); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index 8fc3fb42304..2b213f3ba87 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -456,6 +456,8 @@ static void unlang_dump(unlang_t *instruction, int depth) case UNLANG_TYPE_TIMEOUT: case UNLANG_TYPE_LIMIT: case UNLANG_TYPE_TRANSACTION: + case UNLANG_TYPE_TRY: + case UNLANG_TYPE_CATCH: /* @todo - print out things we catch, too */ g = unlang_generic_to_group(c); DEBUG("%.*s%s {", depth, unlang_spaces, c->debug_name); unlang_dump(g->children, depth + 1); diff --git a/src/lib/unlang/interpret.c b/src/lib/unlang/interpret.c index c73ebb4238a..8c44f9d1635 100644 --- a/src/lib/unlang/interpret.c +++ b/src/lib/unlang/interpret.c @@ -973,7 +973,6 @@ static unlang_group_t empty_group = { }, }; - /** Push a configuration section onto the request stack for later interpretation. * */ diff --git a/src/lib/unlang/try.c b/src/lib/unlang/try.c new file mode 100644 index 00000000000..434fc14ffc6 --- /dev/null +++ b/src/lib/unlang/try.c @@ -0,0 +1,50 @@ +/* + * 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 of the License, 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @file unlang/try.c + * @brief Unlang "try" keyword evaluation. + * + * @copyright 2023 Network RADIUS SAS (legal@networkradius.com) + */ +RCSID("$Id$") + +#include "unlang_priv.h" +#include "catch_priv.h" + +static unlang_action_t unlang_try(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame) +{ + /* + * When this frame finishes, jump ahead to the appropriate "catch". + * + * All of the magic is done in the compile phase. + */ + frame_repeat(frame, unlang_interpret_skip_to_catch); + + return unlang_interpret_push_children(p_result, request, frame->result, UNLANG_NEXT_SIBLING); +} + +void unlang_try_init(void) +{ + unlang_register(UNLANG_TYPE_TRY, + &(unlang_op_t){ + .name = "try", + .interpret = unlang_try, + .debug_braces = true + }); +} diff --git a/src/lib/unlang/try_priv.h b/src/lib/unlang/try_priv.h new file mode 100644 index 00000000000..6b6c91da4f7 --- /dev/null +++ b/src/lib/unlang/try_priv.h @@ -0,0 +1,38 @@ +#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/try_priv.h + * @brief Declarations for unlang trys + * + * @copyright 2023 Network RADIUS SAS (legal@networkradius.com) + */ +#include "unlang_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + unlang_group_t group; +} unlang_try_t; + +#ifdef __cplusplus +} +#endif diff --git a/src/lib/unlang/unlang_priv.h b/src/lib/unlang/unlang_priv.h index 9c4b7f5bf25..96e2988aba2 100644 --- a/src/lib/unlang/unlang_priv.h +++ b/src/lib/unlang/unlang_priv.h @@ -78,6 +78,8 @@ typedef enum { UNLANG_TYPE_TIMEOUT, //!< time-based timeouts. UNLANG_TYPE_LIMIT, //!< limit number of requests in a section UNLANG_TYPE_TRANSACTION, //!< transactions for editing lists + UNLANG_TYPE_TRY, //!< try / catch blocks + UNLANG_TYPE_CATCH, //!< catch a previous try UNLANG_TYPE_POLICY, //!< Policy section. UNLANG_TYPE_XLAT, //!< Represents one level of an xlat expansion. UNLANG_TYPE_TMPL, //!< asynchronously expand a tmpl_t @@ -635,6 +637,10 @@ void unlang_transaction_init(void); void unlang_limit_init(void); +void unlang_try_init(void); + +void unlang_catch_init(void); + /** @} */ #ifdef __cplusplus