]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add "detach" keyword
authorAlan T. DeKok <aland@freeradius.org>
Mon, 11 Sep 2017 19:53:57 +0000 (15:53 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 11 Sep 2017 19:58:02 +0000 (15:58 -0400)
and functionality.  Its parent has to be "create"

src/include/interpreter.h
src/main/unlang_compile.c
src/main/unlang_interpret.c

index 2c922822ce081756075a617075a64169aa740603..eabb2375cf42b6ed87815420236df4e720da8844 100644 (file)
@@ -68,6 +68,7 @@ typedef enum {
        UNLANG_TYPE_MAP,                        //!< Mapping section (like #UNLANG_TYPE_UPDATE, but uses
                                                //!< values from a #map_proc_t call).
        UNLANG_TYPE_CREATE,                     //!< create a child
+       UNLANG_TYPE_DETACH,                     //!< detach a child
 #endif
        UNLANG_TYPE_POLICY,                     //!< Policy section.
        UNLANG_TYPE_XLAT_INLINE,                //!< xlat statement, inline in "unlang"
index b6021531f708917f06a6025390453072e63eb8c6..4c9e7a11c522a6f5eec1ea16e9fea72b3ea97755 100644 (file)
@@ -2120,6 +2120,26 @@ static unlang_t *compile_break(unlang_t *parent, unlang_compile_t *unlang_ctx, C
        return compile_empty(parent, unlang_ctx, NULL, UNLANG_GROUP_TYPE_SIMPLE, UNLANG_GROUP_TYPE_SIMPLE,
                             UNLANG_TYPE_BREAK, COND_TYPE_INVALID);
 }
+
+static unlang_t *compile_detach(unlang_t *parent, unlang_compile_t *unlang_ctx, CONF_ITEM const *ci)
+{
+       if (parent->type != UNLANG_TYPE_CREATE) {
+               cf_log_err(ci, "'detach' can only be used in a 'create' section");
+               return NULL;
+       }
+
+       /*
+        *      This really overloads the functionality of
+        *      cf_item_next().
+        */
+       if (!cf_item_next(ci, ci)) {
+               cf_log_err(ci, "'detach' cannot be used as the last entry in a section");
+               return NULL;
+       }
+
+       return compile_empty(parent, unlang_ctx, NULL, UNLANG_GROUP_TYPE_SIMPLE, UNLANG_GROUP_TYPE_SIMPLE,
+                            UNLANG_TYPE_DETACH, COND_TYPE_INVALID);
+}
 #endif
 
 static unlang_t *compile_xlat_inline(unlang_t *parent,
@@ -2811,6 +2831,10 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
                        cf_log_err(ci, "Invalid use of 'break'");
                        return NULL;
 
+               } else if (strcmp(modrefname, "detach") == 0) {
+                       cf_log_err(ci, "Invalid use of 'detach'");
+                       return NULL;
+
                } else if (strcmp(modrefname, "return") == 0) {
                        cf_log_err(ci, "Invalid use of 'return'");
                        return NULL;
@@ -2857,6 +2881,10 @@ static unlang_t *compile_item(unlang_t *parent, unlang_compile_t *unlang_ctx, CO
                return compile_break(parent, unlang_ctx, ci);
        }
 
+       if (strcmp(modrefname, "detach") == 0) {
+               return compile_detach(parent, unlang_ctx, ci);
+       }
+
        if (strcmp(modrefname, "return") == 0) {
                return compile_empty(parent, unlang_ctx, NULL, UNLANG_GROUP_TYPE_SIMPLE, UNLANG_GROUP_TYPE_SIMPLE, UNLANG_TYPE_RETURN, COND_TYPE_INVALID);
        }
index 3448bb227305ac8f5bff89b4ff57de79267cad89..636d1fd8397273122914269eef38837bdafadad2 100644 (file)
@@ -646,6 +646,33 @@ static rlm_rcode_t unlang_create_resume(UNUSED REQUEST *request, unlang_stack_t
        return RLM_MODULE_YIELD;
 }
 
+static unlang_action_t unlang_detach(REQUEST *request, unlang_stack_t *stack,
+                                    rlm_rcode_t *presult, int *priority)
+{
+       unlang_stack_frame_t    *frame = &stack->frame[stack->depth];
+       unlang_t                *instruction = frame->instruction;
+
+       rad_assert(instruction->parent->type == UNLANG_TYPE_CREATE);
+       RDEBUG2("%s", unlang_ops[instruction->type].name);
+
+       if (request_detach(request) < 0) {
+               ERROR("Failed detaching child");
+               *presult = RLM_MODULE_FAIL;
+               *priority = 0;
+               return UNLANG_ACTION_CALCULATE_RESULT;
+       }
+
+       /*
+        *      request_detach() doesn't set the "detached" flag, but
+        *      it does set the backlog...
+        */
+       request->async->detached = true;
+       rad_assert(request->backlog != NULL);
+
+       *presult = RLM_MODULE_YIELD;
+       return UNLANG_ACTION_CALCULATE_RESULT;
+}
+
 static unlang_action_t unlang_create(REQUEST *request, unlang_stack_t *stack,
                                     rlm_rcode_t *presult, int *priority)
 {
@@ -716,6 +743,33 @@ static unlang_action_t unlang_create(REQUEST *request, unlang_stack_t *stack,
                return UNLANG_ACTION_CALCULATE_RESULT;
        }
 
+       /*
+        *      As a special case, if the child is "detach", detach
+        *      the child, insert the child into the runnable queue,
+        *      and keep going with the parent.
+        */
+       {
+               unlang_stack_t          *child_stack = child->stack;
+               unlang_stack_frame_t    *child_frame = &child_stack->frame[child_stack->depth];
+               unlang_t                *child_instruction = child_frame->instruction;
+
+               if (child_instruction->type == UNLANG_TYPE_DETACH) {
+                       rad_assert(child->backlog != NULL);
+                       fr_heap_insert(child->backlog, child);
+
+                       /*
+                        *      Tell the interpreter to skip the "detach"
+                        *      stack frame when it continues.
+                        */
+                       child_frame->instruction = child_frame->next;
+                       if (child_frame->instruction) child_frame->next = child_frame->instruction->next;
+
+                       *presult = RLM_MODULE_NOOP;
+                       *priority = 0;
+                       return UNLANG_ACTION_CALCULATE_RESULT;
+               } /* else the child yielded, so we have to yield */
+       }
+
        /*
         *      Create the "resume" stack frame, and have it replace our stack frame.
         */
@@ -1727,6 +1781,11 @@ unlang_op_t unlang_ops[] = {
                .func = unlang_create,
                .debug_braces = true
        },
+       [UNLANG_TYPE_DETACH] = {
+               .name = "detach",
+               .func = unlang_detach,
+               .debug_braces = false
+       },
 #endif
        [UNLANG_TYPE_XLAT_INLINE] = {
                .name = "xlat_inline",
@@ -1851,6 +1910,20 @@ resume_subsection:
 
                case UNLANG_ACTION_CALCULATE_RESULT:
                        if (result == RLM_MODULE_YIELD) {
+                               /*
+                                *      Detach is magic.  The parent
+                                *      "create" function takes care
+                                *      of bumping the instruction
+                                *      pointer...
+                                */
+                               if (frame->instruction->type == UNLANG_TYPE_DETACH) {
+                                       RDEBUG4("** [%i] %s - detaching child with current (%s %d)", stack->depth, __FUNCTION__,
+                                               fr_int2str(mod_rcode_table, frame->result, "<invalid>"),
+                                               frame->priority);
+                                       DUMP_STACK;
+                                       return RLM_MODULE_YIELD;
+                               }
+
                                rad_assert(frame->instruction->type == UNLANG_TYPE_RESUME);
                                frame->resume = true;
                                RDEBUG4("** [%i] %s - yielding with current (%s %d)", stack->depth, __FUNCTION__,