]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
implement try / catch
authorAlan T. DeKok <aland@freeradius.org>
Thu, 14 Dec 2023 18:01:57 +0000 (13:01 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 14 Dec 2023 21:43:52 +0000 (16:43 -0500)
there's no compilation, but the intended functionality is present.

src/lib/unlang/all.mk
src/lib/unlang/base.c
src/lib/unlang/catch.c [new file with mode: 0644]
src/lib/unlang/catch_priv.h [new file with mode: 0644]
src/lib/unlang/compile.c
src/lib/unlang/interpret.c
src/lib/unlang/try.c [new file with mode: 0644]
src/lib/unlang/try_priv.h [new file with mode: 0644]
src/lib/unlang/unlang_priv.h

index 5d8c86623cefa594be93bb37da48651ff2214b56..2ad383d62c593a4f0ec5d789e34a8348017458bf 100644 (file)
@@ -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 \
index 11d25d90b6ca055143b51e081e022ad90cb47bd3..6315efb20cb1eb96d27468dc17b52d01f860de64 100644 (file)
@@ -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 (file)
index 0000000..a5f5934
--- /dev/null
@@ -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, "<invalid>"));
+                       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 (file)
index 0000000..c394348
--- /dev/null
@@ -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
index 8fc3fb4230475f8d014678629072444e9ebfcd08..2b213f3ba8707cb094983e2617976794cd1526b2 100644 (file)
@@ -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);
index c73ebb4238ac021c7d7429913b4c446d5196f530..8c44f9d16355804e4cdaad33d729ac60d0a8a2e8 100644 (file)
@@ -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 (file)
index 0000000..434fc14
--- /dev/null
@@ -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 (file)
index 0000000..6b6c91d
--- /dev/null
@@ -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
index 9c4b7f5bf25424933c355802d9e768c8409833e8..96e2988aba29389960b1d0c4e52e463bd03bae06 100644 (file)
@@ -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