The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
interpret.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 3af377b157d5957ba4b3b1dfbae86a800f8ab5f4 $
19 *
20 * @file unlang/interpret.c
21 * @brief Execute compiled unlang structures using an iterative interpret.
22 *
23 * @copyright 2006-2016 The FreeRADIUS server project
24 */
25
26RCSID("$Id: 3af377b157d5957ba4b3b1dfbae86a800f8ab5f4 $")
27
28#include <freeradius-devel/unlang/interpret.h>
29#include <freeradius-devel/util/timer.h>
30#include <freeradius-devel/server/base.h>
31#include <freeradius-devel/server/modpriv.h>
32#include <freeradius-devel/unlang/xlat_func.h>
33
34#include "interpret_priv.h"
35#include "module_priv.h"
36
37
38/** The default interpreter instance for this thread
39 */
41
43 { L("calculate-result"), UNLANG_ACTION_CALCULATE_RESULT },
44 { L("next"), UNLANG_ACTION_EXECUTE_NEXT },
45 { L("pushed-child"), UNLANG_ACTION_PUSHED_CHILD },
47 { L("yield"), UNLANG_ACTION_YIELD }
48};
50
57
58#ifndef NDEBUG
59static void instruction_dump(request_t *request, unlang_t const *instruction)
60{
61 RINDENT();
62 if (!instruction) {
63 RDEBUG2("instruction <none>");
64 REXDENT();
65 return;
66 }
67
68 RDEBUG2("type %s", unlang_ops[instruction->type].name);
69 RDEBUG2("name %s", instruction->name);
70 RDEBUG2("debug_name %s", instruction->debug_name);
71 REXDENT();
72}
73
74static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
75{
76 unlang_op_t *op = NULL;
77
78 if (frame->instruction) op = &unlang_ops[frame->instruction->type];
79
80 instruction_dump(request, frame->instruction);
81
82 RINDENT();
83 if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
84 if (frame->next) {
85 RDEBUG2("next %s", frame->next->debug_name);
86 } else {
87 RDEBUG2("next <none>");
88 }
89 RDEBUG2("result %s", fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
90 RDEBUG2("priority %d", frame->priority);
91 RDEBUG2("top_frame %s", is_top_frame(frame) ? "yes" : "no");
92 RDEBUG2("repeat %s", is_repeatable(frame) ? "yes" : "no");
93 RDEBUG2("resumable %s", is_yielded(frame) ? "yes" : "no");
94 RDEBUG2("unwind %s", is_unwinding(frame) ? "yes" : "no");
95
96 if (frame->instruction) {
97 RDEBUG2("control %s%s%s",
98 is_break_point(frame) ? "b" : "-",
99 is_return_point(frame) ? "r" : "-",
100 is_continue_point(frame) ? "c" : "-"
101 );
102 }
103 /*
104 * Call the custom frame dump function
105 */
106 if (op && op->dump) op->dump(request, frame);
107
108 REXDENT();
109}
110
111static void stack_dump(request_t *request)
112{
113 int i;
114 unlang_stack_t *stack = request->stack;
115
116 RDEBUG2("----- Begin stack debug [depth %i] -----", stack->depth);
117 for (i = stack->depth; i >= 0; i--) {
118 unlang_stack_frame_t *frame = &stack->frame[i];
119
120 RDEBUG2("[%d] Frame contents", i);
121 frame_dump(request, frame);
122 }
123 RDEBUG2("----- End stack debug [depth %i] -------", stack->depth);
124}
125#define DUMP_STACK if (DEBUG_ENABLED5) stack_dump(request)
126#else
127#define DUMP_STACK
128#endif
129
130/** Push a new frame onto the stack
131 *
132 * @param[in] request to push the frame onto.
133 * @param[in] instruction One or more unlang_t nodes describing the operations to execute.
134 * @param[in] default_rcode The default result.
135 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
136 * or to execute subsequent nodes.
137 * @param[in] top_frame Return out of the unlang interpret when popping this frame.
138 * Hands execution back to whatever called the interpret.
139 * @return
140 * - 0 on success.
141 * - -1 on call stack too deep.
142 */
143int unlang_interpret_push(request_t *request, unlang_t const *instruction,
144 rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
145{
146 unlang_stack_t *stack = request->stack;
148
149 fr_assert(instruction || top_frame);
150
151#ifndef NDEBUG
152 if (DEBUG_ENABLED5) RDEBUG3("unlang_interpret_push called with instruction type \"%s\" - args %s %s",
153 instruction ? instruction->debug_name : "<none>",
154 do_next_sibling ? "UNLANG_NEXT_SIBLING" : "UNLANG_NEXT_STOP",
155 top_frame ? "UNLANG_TOP_FRAME" : "UNLANG_SUB_FRAME");
156#endif
157
158 /*
159 * This is not a cancellation point.
160 *
161 * If we cancel here bad things happen inside the interpret.
162 */
163 if (stack->depth >= (UNLANG_STACK_MAX - 1)) {
164 RERROR("Call stack is too deep");
165 return - 1;
166 }
167
168 stack->depth++;
169
170 /*
171 * Initialize the next stack frame.
172 */
173 frame = &stack->frame[stack->depth];
174 memset(frame, 0, sizeof(*frame));
175
176 frame->instruction = instruction;
177
178 if (do_next_sibling) {
179 fr_assert(instruction != NULL);
180 frame->next = instruction->next;
181 }
182 /* else frame->next MUST be NULL */
183
185 if (top_frame) top_frame_set(frame);
186
187 frame->result = default_rcode;
188 frame->priority = -1;
189 frame->indent = request->log.indent;
190
191 if (!instruction) return 0;
192
193 frame_state_init(stack, frame);
194
195 return 0;
196}
197
198typedef struct {
199 fr_dict_t const *old_dict; //!< the previous dictionary for the request
200 request_t *request; //!< the request
202
204{
205 fr_pair_t *vp, *prev;
206
207 /*
208 * Local variables are appended to the end of the list. So we remove them by walking backwards
209 * from the end of the list.
210 */
211 vp = fr_pair_list_tail(&ref->request->local_pairs);
212 while (vp) {
213 prev = fr_pair_list_prev(&ref->request->local_pairs, vp);
214 if (vp->da->dict != ref->request->local_dict) {
215 break;
216 }
217
218 (void) fr_pair_delete(&ref->request->local_pairs, vp);
219 vp = prev;
220 }
221
222 ref->request->local_dict = ref->old_dict;
223
224 return 0;
225}
226
227/** Push the children of the current frame onto a new frame onto the stack
228 *
229 * @param[out] p_result set to RLM_MOULDE_FAIL if pushing the children fails
230 * @param[in] request to push the frame onto.
231 * @param[in] default_rcode The default result.
232 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
233 * or to execute subsequent nodes.
234 * @return
235 * - UNLANG_ACTION_PUSHED_CHILD on success.
236 * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
237 * - UNLANG_ACTION_STOP_PROCESSING, fatal error, usually stack overflow.
238 */
240 rlm_rcode_t default_rcode, bool do_next_sibling)
241{
242 unlang_stack_t *stack = request->stack;
243 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
246
248
250
251 /*
252 * The compiler catches most of these, EXCEPT for the
253 * top-level 'recv Access-Request' etc. Which can exist,
254 * and can be empty.
255 */
256 if (!g->children) {
257 RDEBUG2("<ignoring empty subsection>");
259 }
260
261 if (unlang_interpret_push(request, g->children, default_rcode, do_next_sibling, UNLANG_SUB_FRAME) < 0) {
263 }
264
266
267 /*
268 * Note that we do NOT create the variables, This way we don't have to worry about any
269 * uninitialized values. If the admin tries to use the variable without initializing it, they
270 * will get a "no such attribute" error.
271 */
272 if (!frame->state) {
273 MEM(ref = talloc(stack, unlang_variable_ref_t));
274 frame->state = ref;
275 } else {
276 MEM(ref = talloc(frame->state, unlang_variable_ref_t));
277 }
278
279 /*
280 * Set the destructor to clean up local variables.
281 */
282 ref->request = request;
283 ref->old_dict = request->local_dict;
284 request->local_dict = g->variables->dict;
285 talloc_set_destructor(ref, _local_variables_free);
286
288}
289
290static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx);
291
292/** Update the current result after each instruction, and after popping each stack frame
293 *
294 * @param[in] request The current request.
295 * @param[in] frame The current stack frame.
296 * @param[in,out] result The current section result.
297 * @param[in,out] priority The current section priority.
298 * @return
299 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions.
300 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
301 */
302static inline CC_HINT(always_inline)
304 rlm_rcode_t *result, int *priority)
305{
306 unlang_t const *instruction = frame->instruction;
307 unlang_stack_t *stack = request->stack;
308
309 RDEBUG4("** [%i] %s - have (%s %d) module returned (%s %d)",
310 stack->depth, __FUNCTION__,
311 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
312 frame->priority,
313 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
314 *priority);
315
316 if (is_unwinding(frame)) {
317 RDEBUG4("** [%i] %s - frame is cancelled",
318 stack->depth, __FUNCTION__);
319 frame->result = *result;
320 frame->priority = *priority;
322 }
323
324 /*
325 * Update request->rcode if the instruction says we should
326 * We don't care about priorities for this.
327 */
328 if (is_rcode_set(frame)) {
329 RDEBUG3("Setting rcode to '%s'",
330 fr_table_str_by_value(rcode_table, *result, "<INVALID>"));
331 request->rcode = *result;
332 }
333
334 /*
335 * Don't set action or priority if we don't have one.
336 */
337 if (*result == RLM_MODULE_NOT_SET) return UNLANG_FRAME_ACTION_NEXT;
338
339 /*
340 * The child's action says return. Do so.
341 */
342 if (instruction->actions.actions[*result] == MOD_ACTION_RETURN) {
343 if (*priority < 0) *priority = 0;
344
345 RDEBUG4("** [%i] %s - action says to return with (%s %d)",
346 stack->depth, __FUNCTION__,
347 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
348 *priority);
349 frame->result = *result;
350 frame->priority = *priority;
352 }
353
354 /*
355 * If "reject", break out of the loop and return
356 * reject.
357 */
358 if (instruction->actions.actions[*result] == MOD_ACTION_REJECT) {
359 if (*priority < 0) *priority = 0;
360
361 RDEBUG4("** [%i] %s - action says to return with (%s %d)",
362 stack->depth, __FUNCTION__,
364 *priority);
365 frame->result = RLM_MODULE_REJECT;
366 frame->priority = *priority;
368 }
369
370 /*
371 * The instruction says it should be retried from the beginning.
372 */
373 if (instruction->actions.actions[*result] == MOD_ACTION_RETRY) {
374 unlang_retry_t *retry = frame->retry;
375
376 RDEBUG4("** [%i] %s - action says to retry with",
377 stack->depth, __FUNCTION__);
378
379 if (*priority < 0) *priority = 0;
380
381 /*
382 * If this is the first time doing the retry,
383 * then allocate the structure and set the timer.
384 */
385 if (!retry) {
386 MEM(frame->retry = retry = talloc_zero(stack, unlang_retry_t));
387
388 retry->request = request;
389 retry->depth = stack->depth;
390 retry->state = FR_RETRY_CONTINUE;
391 retry->count = 1;
392
393 /*
394 * Set a timer which automatically fires
395 * if there's a timeout. And parent it
396 * from the retry structure, so that the
397 * timer is automatically freed when the
398 * frame is cleaned up.
399 */
400 if (fr_time_delta_ispos(instruction->actions.retry.mrd)) {
401 if (fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, instruction->actions.retry.mrd,
402 false, instruction_retry_handler, request) < 0) {
403 RPEDEBUG("Failed inserting retry event");
404 *result = RLM_MODULE_FAIL;
405 goto finalize;
406 }
407 }
408
409 } else {
410 /*
411 * We've been told to stop doing retries,
412 * probably from a timeout.
413 */
414 if (retry->state != FR_RETRY_CONTINUE) goto timeout;
415
416 /*
417 * Clamp it at the maximum count.
418 */
419 if (instruction->actions.retry.mrc > 0) {
420 retry->count++;
421
422 if (retry->count >= instruction->actions.retry.mrc) {
423 retry->state = FR_RETRY_MRC;
424
425 REDEBUG("Retries hit max_rtx_count (%u) - returning 'timeout'", instruction->actions.retry.mrc);
426
427 timeout:
428 *result = RLM_MODULE_TIMEOUT;
429 goto finalize;
430 }
431 }
432 }
433
434 RINDENT();
435 if (instruction->actions.retry.mrc) {
436 RDEBUG("... retrying (%u/%u)", retry->count, instruction->actions.retry.mrc);
437 } else {
438 RDEBUG("... retrying");
439 }
440 REXDENT();
441
442 talloc_free(frame->state);
444 frame_state_init(stack, frame);
446 }
447
448finalize:
449 /*
450 * The array holds a default priority for this return
451 * code. Grab it in preference to any unset priority.
452 */
453 if (*priority < 0) {
454 *priority = instruction->actions.actions[*result];
455
456 RDEBUG4("** [%i] %s - setting priority to (%s %d)",
457 stack->depth, __FUNCTION__,
458 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
459 *priority);
460 }
461
462 /*
463 * We're higher than any previous priority, remember this
464 * return code and priority.
465 */
466 if (*priority > frame->priority) {
467 frame->result = *result;
468 frame->priority = *priority;
469
470 RDEBUG4("** [%i] %s - over-riding result from higher priority to (%s %d)",
471 stack->depth, __FUNCTION__,
472 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
473 *priority);
474 }
475
477}
478
479/** Evaluates all the unlang nodes in a section
480 *
481 * This function interprets a list of unlang instructions at a given level using the same
482 * stack frame, and pushes additional frames onto the stack as needed.
483 *
484 * This function can be seen as moving horizontally.
485 *
486 * @param[in] request The current request.
487 * @param[in] frame The current stack frame.
488 * @param[in,out] result The current section result.
489 * @param[in,out] priority The current section priority.
490 * @return
491 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions in the current stack frame
492 * which may not be the same frame as when this function
493 * was called.
494 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
495 */
496static inline CC_HINT(always_inline)
498{
499 unlang_stack_t *stack = request->stack;
500
501 /*
502 * Loop over all the instructions in this list.
503 */
504 while (frame->instruction) {
505 unlang_t const *instruction = frame->instruction;
508
510
511 fr_assert(instruction->debug_name != NULL); /* if this happens, all bets are off. */
512 fr_assert(unlang_ops[instruction->type].interpret != NULL);
513
514 REQUEST_VERIFY(request);
515
516 /*
517 * We're running this frame, so it can't possibly be yielded.
518 */
519 if (is_yielded(frame)) {
520 RDEBUG("%s - Resuming execution", instruction->debug_name);
521 yielded_clear(frame);
522 }
523
524#ifndef NDEBUG
525 /*
526 * Failure testing!
527 */
528 if (request->ins_max) {
529 request->ins_count++;
530
531 if (request->ins_count >= request->ins_max) {
532 RERROR("Failing request due to maximum instruction count %" PRIu64, request->ins_max);
533
535 }
536 }
537#endif
538
539 if (!is_repeatable(frame) && has_debug_braces(frame)) {
540 RDEBUG2("%s {", instruction->debug_name);
541 RINDENT();
542 }
543
544 /*
545 * Execute an operation
546 */
547 RDEBUG4("** [%i] %s >> %s", stack->depth, __FUNCTION__,
548 unlang_ops[instruction->type].name);
549
550 fr_assert(frame->process != NULL);
551
552 /*
553 * Clear the repeatable flag so this frame
554 * won't get executed again unless it specifically
555 * requests it.
556 *
557 * The flag may still be set again during the
558 * process function to indicate that the frame
559 * should be evaluated again.
560 */
561 repeatable_clear(frame);
563
564 /*
565 * catch plays games with the frame so we skip
566 * to the next catch section at a given depth,
567 * it's not safe to access frame->instruction
568 * after this point, and the cached instruction
569 * should be used instead.
570 */
571 ua = frame->process(result, request, frame);
572
573 RDEBUG4("** [%i] %s << %s (%d)", stack->depth, __FUNCTION__,
574 fr_table_str_by_value(unlang_action_table, ua, "<INVALID>"), *priority);
575
576 fr_assert(*priority >= -1);
577 fr_assert(*priority <= MOD_PRIORITY_MAX);
578
579 /*
580 * If the frame is cancelled we ignore the
581 * return code of the process function and
582 * jump to calculate result (which tells us
583 * to start popping frames). This is because
584 * the cancellation can be signalled
585 * asynchronously, and the process function
586 * may not be aware that it's happened.
587 */
588 if (is_unwinding(frame)) goto calculate_result;
589
590 switch (ua) {
593 goto calculate_result;
594
595 /*
596 * The operation resulted in additional frames
597 * being pushed onto the stack, execution should
598 * now continue at the deepest frame.
599 */
601 fr_assert_msg(&stack->frame[stack->depth] > frame,
602 "Instruction %s returned UNLANG_ACTION_PUSHED_CHILD, "
603 "but stack depth was not increased",
604 instruction->name);
606 *result = frame->result;
608
609 /*
610 * Yield control back to the scheduler, or whatever
611 * called the interpreter.
612 */
614 fr_assert_msg(&stack->frame[stack->depth] == frame,
615 "Instruction %s returned UNLANG_ACTION_YIELD, but pushed additional "
616 "frames for evaluation. Instruction should return UNLANG_ACTION_PUSHED_CHILD "
617 "instead", instruction->name);
619 yielded_set(frame);
620 RDEBUG4("** [%i] %s - yielding with current (%s %d)", stack->depth, __FUNCTION__,
621 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
622 frame->priority);
625
626 /*
627 * This action is intended to be returned by library
628 * functions. It reduces boilerplate.
629 */
631 *result = RLM_MODULE_FAIL;
633
634 /*
635 * Instruction finished execution,
636 * check to see what we need to do next, and update
637 * the section rcode and priority.
638 */
640 calculate_result:
641 if (has_debug_braces(instruction)) {
642 REXDENT();
643
644 /*
645 * If we're at debug level 1, don't emit the closing
646 * brace as the opening brace wasn't emitted.
647 */
649 RDEBUG("# %s (%s)", instruction->debug_name,
650 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
651 } else {
652 RDEBUG2("} # %s (%s)", instruction->debug_name,
653 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
654 }
655 }
656
657 /*
658 * RLM_MODULE_NOT_SET means the instruction
659 * doesn't want to modify the result.
660 */
661 if (*result != RLM_MODULE_NOT_SET) *priority = instruction->actions.actions[*result];
662
663 fa = result_calculate(request, frame, result, priority);
664 switch (fa) {
667
669 if (has_debug_braces(instruction)) {
670 REXDENT();
671 RDEBUG2("} # retrying the same section");
672 }
673 continue; /* with the current frame */
674
675 default:
676 break;
677 }
678 break;
679
680 /*
681 * Execute the next instruction in this frame
682 */
684 if (has_debug_braces(instruction)) {
685 REXDENT();
686 RDEBUG2("}");
687 }
688 break;
689 } /* switch over return code from the interpret function */
690
691 frame_next(stack, frame);
692 }
693
694 RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
695 stack->depth, __FUNCTION__,
696 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
697 frame->priority);
698
700}
701
702/** Run the interpreter for a current request
703 *
704 * This function runs the interpreter for a request. It deals with popping
705 * stack frames, and calaculating the final result for the frame.
706 *
707 * @param[in] request to run. If this is an internal request
708 * the request may be freed by the interpreter.
709 * @param[in] running Is the interpreter already running.
710 * @return The final request rcode.
711 */
712CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
713{
714 rlm_rcode_t rcode;
715
716 /*
717 * We don't have a return code yet.
718 */
719 unlang_stack_t *stack = request->stack;
720 unlang_interpret_t *intp = stack->intp;
721 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
722
723 /*
724 * This is needed to ensure that if a frame is marked
725 * for unwinding whilst the request is yielded, we
726 * unwind the cancelled frame correctly, instead of
727 * continuing.
728 */
730
731 stack->priority = -1; /* Reset */
732
733#ifndef NDEBUG
734 if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
736#endif
737
738 fr_assert(!unlang_request_is_scheduled(request)); /* if we're running it, it can't be scheduled */
739 fr_assert_msg(intp, "request has no interpreter associated");
740
741 RDEBUG4("** [%i] %s - interpret entered", stack->depth, __FUNCTION__);
742 if (!running) intp->funcs.resume(request, intp->uctx);
743
744 for (;;) {
745 fr_assert(stack->depth > 0);
747
748 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
750 switch (fa) {
751 case UNLANG_FRAME_ACTION_NEXT: /* Evaluate the current frame */
752 frame = &stack->frame[stack->depth];
753 fa = frame_eval(request, frame, &stack->result, &stack->priority);
754
755 if (fa != UNLANG_FRAME_ACTION_POP) continue;
757
758 case UNLANG_FRAME_ACTION_POP: /* Pop this frame and check the one beneath it */
759 {
760 bool top_frame = is_top_frame(frame);
761 /*
762 * The result / priority is returned from the sub-section,
763 * and made into our current result / priority, as
764 * if we had performed a module call.
765 */
766 stack->result = frame->result;
767 stack->priority = frame->priority;
768
769 /*
770 * Head on back up the stack
771 */
772 frame_pop(request, stack);
773
774 /*
775 * Transition back to the C stack
776 */
777 if (top_frame) break; /* stop */
778
779 frame = &stack->frame[stack->depth];
781
782 /*
783 * Resume a "foreach" loop, or a "load-balance" section
784 * or anything else that needs to be checked on the way
785 * back on up the stack.
786 */
787
788 if (!is_unwinding(frame) && is_repeatable(frame)) {
790 continue;
791 }
792
793 /*
794 * Close out the section we entered earlier
795 */
796 if (has_debug_braces(frame)) {
797 REXDENT();
798
799 /*
800 * If we're at debug level 1, don't emit the closing
801 * brace as the opening brace wasn't emitted.
802 */
804 RDEBUG("# %s (%s)", frame->instruction->debug_name,
805 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
806 } else {
807 RDEBUG2("} # %s (%s)", frame->instruction->debug_name,
808 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
809 }
810 }
811
812 fa = result_calculate(request, frame, &stack->result, &stack->priority);
813
814 /*
815 * If we're continuing after popping a frame
816 * then we advance the instruction else we
817 * end up executing the same code over and over...
818 */
819 if (fa == UNLANG_FRAME_ACTION_NEXT) {
820 RDEBUG4("** [%i] %s - continuing after subsection with (%s %d)",
821 stack->depth, __FUNCTION__,
822 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
823 stack->priority);
824 frame_next(stack, frame);
825
826 /*
827 * Else if we're really done with this frame
828 * print some helpful debug...
829 */
830 } else {
831 RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
832 stack->depth, __FUNCTION__,
833 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
834 frame->priority);
835 }
836 continue;
837 }
838
840 /* Cannot yield from a nested call to unlang_interpret */
841 fr_assert(!running);
842
843 RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
844 intp->funcs.yield(request, intp->uctx);
845 return stack->result;
846
847 case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
849 continue;
850 }
851 break;
852 }
853
854 fr_assert(stack->depth >= 0);
855
856 /*
857 * Nothing in this section, use the top frame stack->result.
858 */
859 if ((stack->priority < 0) || (stack->result == RLM_MODULE_NOT_SET)) {
860 RDEBUG4("** [%i] %s - empty section, using stack result (%s %d)", stack->depth, __FUNCTION__,
861 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"), stack->priority);
862 stack->result = frame->result;
863 stack->priority = frame->priority;
864 }
865
866 if (stack->priority > frame->priority) {
867 frame->result = stack->result;
868 frame->priority = stack->priority;
869
870 RDEBUG4("** [%i] %s - over-riding stack->result from higher priority to (%s %d)",
871 stack->depth, __FUNCTION__,
872 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
873 stack->priority);
874 }
875
876 /*
877 * We're at the top frame, return the result from the
878 * stack, and get rid of the top frame.
879 */
880 RDEBUG4("** [%i] %s - interpret exiting, returning %s", stack->depth, __FUNCTION__,
881 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
882
883 stack->result = frame->result;
884
886
887 /*
888 * Record this now as the done functions may free
889 * the request.
890 */
891 rcode = stack->result;
892
893 /*
894 * This usually means the request is complete in its
895 * entirety.
896 */
897 if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
898
899 return rcode;
900}
901
903 .self = {
905 .debug_name = "empty-group",
906 .actions = {
907 .actions = {
917 },
918 .retry = RETRY_INIT,
919 },
920 },
921};
922
923/** Push a configuration section onto the request stack for later interpretation.
924 *
925 */
926int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs, rlm_rcode_t default_rcode, bool top_frame)
927{
928 unlang_t *instruction = NULL;
929
930 /*
931 * Interpretable unlang instructions are stored as CONF_DATA
932 * associated with sections.
933 */
934 if (cs) {
935 instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
936 if (!instruction) {
937 REDEBUG("Failed to find pre-compiled unlang for section %s %s { ... }",
939 return -1;
940 }
941 }
942
943 return unlang_interpret_push_instruction(request, instruction, default_rcode, top_frame);
944}
945
946/** Push an instruction onto the request stack for later interpretation.
947 *
948 */
949int unlang_interpret_push_instruction(request_t *request, void *instruction, rlm_rcode_t default_rcode, bool top_frame)
950{
951 unlang_stack_t *stack = request->stack;
952
953 if (!instruction) {
954 instruction = unlang_group_to_generic(&empty_group);
955 }
956
957 /*
958 * Push the default action, and the instruction which has
959 * no action.
960 */
961 if (unlang_interpret_push(request,
962 instruction, default_rcode, UNLANG_NEXT_SIBLING, top_frame) < 0) {
963 return -1;
964 }
965
966 RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
967
969
970 return 0;
971}
972
973/** Allocate a new unlang stack
974 *
975 * @param[in] ctx to allocate stack in.
976 * @return
977 * - A new stack on success.
978 * - NULL on OOM.
979 */
980void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
981{
983
984 /*
985 * If we have talloc_pooled_object allocate the
986 * stack as a combined chunk/pool, with memory
987 * to hold at mutable data for at least a quarter
988 * of the maximum number of stack frames.
989 *
990 * Having a dedicated pool for mutable stack data
991 * means we don't have memory fragmentations issues
992 * as we would if request were used as the pool.
993 *
994 * This number is pretty arbitrary, but it seems
995 * like too low level to make into a tuneable.
996 */
997 MEM(stack = talloc_zero_pooled_object(ctx, unlang_stack_t, UNLANG_STACK_MAX, 128)); /* 128 bytes per state */
998 stack->result = RLM_MODULE_NOT_SET;
999
1000 return stack;
1001}
1002
1003/** Indicate to the caller of the interpreter that this request is complete
1004 *
1005 */
1007{
1008 unlang_stack_t *stack = request->stack;
1009 unlang_interpret_t *intp;
1010
1011 if (!fr_cond_assert(stack != NULL)) return;
1012
1013 intp = stack->intp;
1014
1015 request->master_state = REQUEST_DONE;
1016 switch (request->type) {
1018 intp->funcs.done_external(request, stack->result, intp->uctx);
1019 break;
1020
1022 intp->funcs.done_internal(request, stack->result, intp->uctx);
1023 break;
1024
1026 intp->funcs.done_detached(request, stack->result, intp->uctx); /* Callback will usually free the request */
1027 break;
1028 }
1029}
1030
1031/** Tell the interpreter to detach the request
1032 *
1033 * This function should not be called directly use unlang_interpret_signal(request, FR_SIGNAL_DETACH) instead.
1034 * This will ensure all frames on the request's stack receive the detach signal.
1035 */
1036static inline CC_HINT(always_inline)
1038{
1039 unlang_stack_t *stack = request->stack;
1040 unlang_interpret_t *intp;
1041
1042 if (!fr_cond_assert(stack != NULL)) return;
1043
1044 if (!request_is_detachable(request)) return;
1045
1046 intp = stack->intp;
1047
1048 intp->funcs.detach(request, intp->uctx);
1049}
1050
1052{
1053 unlang_stack_t *stack = request->stack;
1054 unlang_interpret_t *intp;
1055
1056 if (!fr_cond_assert(stack != NULL)) return;
1057
1058 intp = stack->intp;
1059
1060 request->async->priority = priority;
1061
1062 if (intp->funcs.prioritise) intp->funcs.prioritise(request, intp->uctx);
1063}
1064
1065/** Delivers a frame to one or more frames in the stack
1066 *
1067 * This is typically called via an "async" action, i.e. an action outside
1068 * of the normal processing of the request.
1069 *
1070 * For FR_SIGNAL_CANCEL all frames are marked up for cancellation, but the
1071 * cancellation is handled by the interpret.
1072 *
1073 * Other signal types are delivered immediately, inrrespecitve of whether
1074 * the request is currently being processed or not.
1075 *
1076 * Signaling stops at the "limit" frame. This is so that keywords
1077 * such as "timeout" and "limit" can signal frames *lower* than theirs
1078 * to stop, but then continue with their own work.
1079 *
1080 * @note It's better (clearer) to use one of the unwind_* functions
1081 * unless the entire request is being cancelled.
1082 *
1083 * @param[in] request The current request.
1084 * @param[in] action to signal.
1085 * @param[in] limit the frame at which to stop signaling.
1086 */
1087void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
1088{
1089 unlang_stack_frame_t *frame;
1090 unlang_stack_t *stack = request->stack;
1091 int i, depth = stack->depth;
1092
1093 (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1094
1095 fr_assert(stack->depth >= 1);
1096
1097 /*
1098 * Does not complete the unwinding here, just marks
1099 * up the frames for unwinding. The request must
1100 * be marked as runnable to complete the cancellation.
1101 */
1102 if (action == FR_SIGNAL_CANCEL) unwind_to_depth(stack, limit);
1103
1104 /*
1105 * Walk back up the stack, calling signal handlers
1106 * to cancel any pending operations and free/release
1107 * any resources.
1108 *
1109 * There may be multiple resumption points in the
1110 * stack, as modules can push xlats and function
1111 * calls.
1112 *
1113 * Note: Slightly confusingly, a cancellation signal
1114 * can still be delivered to a frame that is not
1115 * cancellable, but the frame won't be automatically
1116 * unwound.
1117 */
1118 for (i = depth; i >= limit; i--) {
1119 frame = &stack->frame[i];
1120 if (frame->signal) {
1121 frame->signal(request, frame, action);
1122
1123 /*
1124 * Once the cancellation function has been
1125 * called, the frame is no longer in a state
1126 * where it can accept further signals.
1127 */
1128 if (action == FR_SIGNAL_CANCEL) frame->signal = NULL;
1129 }
1130 }
1131}
1132
1133/** Send a signal (usually stop) to a request
1134 *
1135 * This is typically called via an "async" action, i.e. an action
1136 * outside of the normal processing of the request.
1137 *
1138 * @note This does NOT immediately stop the request, it just deliveres
1139 * signals, and in the case of a cancel, marks up frames for unwinding
1140 * and adds it to the runnable queue if it's yielded.
1141 *
1142 * @note This function should be safe to call anywhere.
1143 *
1144 * @param[in] request The current request.
1145 * @param[in] action to signal.
1146 */
1148{
1149 unlang_stack_t *stack = request->stack;
1150
1151 switch (action) {
1152 case FR_SIGNAL_DETACH:
1153 /*
1154 * Ensure the request is able to be detached
1155 * else don't signal.
1156 */
1157 if (!fr_cond_assert(request_is_detachable(request))) return;
1158 break;
1159
1160 default:
1161 break;
1162 }
1163
1164 /*
1165 * Requests that haven't been run through the interpreter
1166 * yet should have a stack depth of zero, so we don't
1167 * need to do anything.
1168 */
1169 if (!stack || stack->depth == 0) return;
1170
1171 unlang_stack_signal(request, action, 1);
1172
1173 switch (action) {
1174 case FR_SIGNAL_CANCEL:
1175 {
1176 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1177 /*
1178 * Let anything that cares, know that the
1179 * request was forcefully stopped.
1180 */
1181 request->master_state = REQUEST_STOP_PROCESSING;
1182
1183 /*
1184 * Give cancelled requests the highest priority
1185 * to get them to release resources ASAP.
1186 */
1187 unlang_interpret_request_prioritise(request, UINT32_MAX);
1188
1189 /*
1190 * If the request is yielded, mark it as runnable
1191 *
1192 * If the request was _not_ cancelled, it means
1193 * it's not cancellable, and we need to let the
1194 * request progress normally.
1195 */
1196 if (stack && is_yielded(frame) && is_unwinding(frame) && !unlang_request_is_scheduled(request)) {
1198 }
1199 }
1200 break;
1201
1202 case FR_SIGNAL_DETACH:
1203 /*
1204 * Cleanup any cross-request pointers, and mark the
1205 * request as detached. When the request completes it
1206 * should by automatically freed.
1207 */
1209 break;
1210
1211 default:
1212 break;
1213 }
1214}
1215
1217{
1218 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1219 request_t *request = talloc_get_type_abort(retry->request, request_t);
1220
1221 RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1222
1223 /*
1224 * Signal all lower frames to exit.
1225 */
1226 unlang_stack_signal(request, FR_SIGNAL_CANCEL, retry->depth);
1227
1228 retry->state = FR_RETRY_MRD;
1230}
1231
1233{
1234 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1235 request_t *request = talloc_get_type_abort(retry->request, request_t);
1236
1237 RDEBUG("Maximum timeout reached, signalling interpreter to stop the request.");
1238
1239 /*
1240 * Stop the entire request.
1241 */
1243}
1244
1245
1246/** Set a timeout for a request.
1247 *
1248 * The timeout is associated with the current stack frame.
1249 *
1250 */
1252{
1253 unlang_stack_t *stack = request->stack;
1254 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1255 unlang_retry_t *retry;
1256
1257 fr_assert(!frame->retry);
1259
1260 frame->retry = retry = talloc_zero(frame, unlang_retry_t);
1261 if (!frame->retry) return -1;
1262
1263 retry->request = request;
1264 retry->depth = stack->depth;
1265 retry->state = FR_RETRY_CONTINUE;
1266 retry->count = 1;
1267
1268 return fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, timeout,
1269 false, instruction_timeout_handler, request);
1270}
1271
1272
1273/** Return the depth of the request's stack
1274 *
1275 */
1277{
1278 unlang_stack_t *stack = request->stack;
1279
1280 return stack->depth;
1281}
1282
1283/** Get the current rcode for the frame
1284 *
1285 * This can be useful for getting the result of unlang_function_t pushed
1286 * onto the stack for evaluation.
1287 *
1288 * @param[in] request The current request.
1289 * @return the current rcode for the frame.
1290 */
1292{
1293 unlang_stack_t *stack = request->stack;
1294
1295 return stack->result;
1296}
1297
1298/** Overwrite the current stack rcode
1299 *
1300 * @param[in] request The current request.
1301 * @param[in] rcode to set.
1302 */
1304{
1305 unlang_stack_t *stack = request->stack;
1306
1307 stack->result = rcode;
1308}
1309
1310/** Return whether a request is currently scheduled
1311 *
1312 */
1314{
1315 unlang_stack_t *stack = request->stack;
1316 unlang_interpret_t *intp = stack->intp;
1317
1318 return intp->funcs.scheduled(request, intp->uctx);
1319}
1320
1321/** Return whether a request has been cancelled
1322 */
1324{
1325 return (request->master_state == REQUEST_STOP_PROCESSING);
1326}
1327
1328/** Return whether a request has been marked done
1329 */
1331{
1332 return (request->master_state == REQUEST_DONE);
1333}
1334
1335/** Check if a request as resumable.
1336 *
1337 * @param[in] request The current request.
1338 * @return
1339 * - true if the request is resumable (i.e. has yielded)
1340 * - false if the request is not resumable (i.e. has not yielded)
1341 */
1343{
1344 unlang_stack_t *stack = request->stack;
1345 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1346
1347 return is_yielded(frame);
1348}
1349
1350/** Mark a request as resumable.
1351 *
1352 * It's not called "unlang_interpret", because it doesn't actually
1353 * resume the request, it just schedules it for resumption.
1354 *
1355 * @note that this schedules the request for resumption. It does not immediately
1356 * start running the request.
1357 *
1358 * @param[in] request The current request.
1359 */
1361{
1362 unlang_stack_t *stack = request->stack;
1363 unlang_interpret_t *intp = stack->intp;
1364 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1365
1366 bool scheduled = unlang_request_is_scheduled(request);
1367
1368 /*
1369 * The request hasn't yielded, OR it's already been
1370 * marked as runnable. Don't do anything.
1371 *
1372 * The IO code, or children have no idea where they're
1373 * being called from. They just ask to mark the parent
1374 * resumable when they're done. So we have to check here
1375 * if this request is resumable.
1376 *
1377 * If the parent called the child directly, then the
1378 * parent hasn't yielded, so it isn't resumable. When
1379 * the child is done, the parent will automatically
1380 * continue running. We therefore don't need to insert
1381 * the parent into the backlog.
1382 *
1383 * Multiple child request may also mark a parent request
1384 * runnable, before the parent request starts running.
1385 */
1386 if (!is_yielded(frame) || scheduled) {
1387 RDEBUG3("Not marking request %s as runnable due to%s%s",
1388 request->name,
1389 !is_yielded(frame) ?
1390 " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
1391 return;
1392 }
1393
1394 RDEBUG3("Interpreter - Request marked as runnable");
1395
1396 intp->funcs.mark_runnable(request, intp->uctx);
1397}
1398
1399/** Get a talloc_ctx which is valid only for this frame
1400 *
1401 * @param[in] request The current request.
1402 * @return
1403 * - a TALLOC_CTX which is valid only for this stack frame
1404 */
1406{
1407 unlang_stack_t *stack = request->stack;
1408 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1409
1410 if (frame->state) return (TALLOC_CTX *)frame->state;
1411
1412 /*
1413 * If the frame doesn't ordinarily have a
1414 * state, assume the caller knows what it's
1415 * doing and allocate one.
1416 */
1417 return (TALLOC_CTX *)(frame->state = talloc_new(request));
1418}
1419
1421 { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
1423};
1424
1425static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
1426 UNUSED xlat_ctx_t const *xctx,
1427 request_t *request, fr_value_box_list_t *args);
1428
1429/** Signal the request to stop executing
1430 *
1431 * The request can't be running at this point because we're in the event
1432 * loop. This means the request is always in a consistent state when
1433 * the timeout event fires, even if that's state is waiting on I/O.
1434 */
1436{
1437 request_t *request = talloc_get_type_abort(uctx, request_t);
1438
1439 RDEBUG2("Request canceled by dynamic timeout");
1440 /*
1441 * Cleans up the memory allocated to hold
1442 * the pointer, not the event itself.
1443 */
1444 talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
1445
1447}
1448
1449/** Allows a request to dynamically alter its own lifetime
1450 *
1451 * %cancel(<timeout>)
1452 *
1453 * If timeout is 0, then the request is immediately cancelled.
1454 */
1456 UNUSED xlat_ctx_t const *xctx,
1457 request_t *request, fr_value_box_list_t *args)
1458{
1459 fr_value_box_t *timeout;
1461 fr_timer_t **ev_p, **ev_p_og;
1462 fr_value_box_t *vb;
1463 fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
1464
1465 XLAT_ARGS(args, &timeout);
1466
1467 /*
1468 * No timeout means cancel immediately, so yield allowing
1469 * the interpreter to run the event we added to cancel
1470 * the request.
1471 *
1472 * We call unlang_xlat_yield to keep the interpreter happy
1473 * as it expects to see a resume function set.
1474 */
1475 if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
1477 return XLAT_ACTION_DONE;
1478 }
1479
1480 /*
1481 * First see if we already have a timeout event
1482 * that was previously added by this xlat.
1483 */
1484 ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
1485 if (ev_p) {
1486 if (*ev_p) when = fr_timer_when(*ev_p); /* *ev_p should never be NULL, really... */
1487 } else {
1488 /*
1489 * Must not be parented from the request
1490 * as this is freed by request data.
1491 */
1492 MEM(ev_p = talloc_zero(NULL, fr_timer_t *));
1493 }
1494
1495 if (unlikely(fr_timer_in(ev_p, el->tl, ev_p,
1496 timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
1497 false, unlang_cancel_event, request) < 0)) {
1498 RPERROR("Failed inserting cancellation event");
1499 talloc_free(ev_p);
1500 return XLAT_ACTION_FAIL;
1501 }
1502 if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
1503 UNCONST(fr_timer_t **, ev_p), true, true, false) < 0)) {
1504 RPERROR("Failed associating cancellation event with request");
1505 talloc_free(ev_p);
1506 return XLAT_ACTION_FAIL;
1507 }
1508
1509 if (ev_p_og) {
1510 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
1511
1512 /*
1513 * Return how long before the previous
1514 * cancel event would have fired.
1515 *
1516 * This can be useful for doing stacked
1517 * cancellations in policy.
1518 */
1519 vb->vb_time_delta = fr_time_sub(when, unlang_interpret_event_list(request)->tl->time());
1521 }
1522
1523 /*
1524 * No value if this is the first cleanup event
1525 */
1526 return XLAT_ACTION_DONE;
1527}
1528
1530 { .required = true, .single = true, .type = FR_TYPE_STRING },
1532};
1533
1534/** Get information about the interpreter state
1535 *
1536 * @ingroup xlat_functions
1537 */
1539 UNUSED xlat_ctx_t const *xctx,
1540 request_t *request, fr_value_box_list_t *in)
1541{
1542 unlang_stack_t *stack = request->stack;
1543 int depth = stack->depth;
1544 unlang_stack_frame_t *frame;
1545 unlang_t const *instruction;
1546 fr_value_box_t *arg = fr_value_box_list_head(in);
1547 char const *fmt = arg->vb_strvalue;
1548 fr_value_box_t *vb;
1549
1550 MEM(vb = fr_value_box_alloc_null(ctx));
1551
1552 /*
1553 * Find the correct stack frame.
1554 */
1555 while (*fmt == '.') {
1556 if (depth <= 1) {
1557 if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
1558 error:
1559 talloc_free(vb);
1560 return XLAT_ACTION_FAIL;
1561 }
1562 goto finish;
1563 }
1564
1565 fmt++;
1566 depth--;
1567 }
1568
1569 /*
1570 * Get the current instruction.
1571 */
1572 frame = &stack->frame[depth];
1573 instruction = frame->instruction;
1574
1575 /*
1576 * Nothing there...
1577 */
1578 if (!instruction) {
1579 talloc_free(vb);
1580 return XLAT_ACTION_DONE;
1581 }
1582
1583 /*
1584 * How deep the current stack is.
1585 */
1586 if (strcmp(fmt, "depth") == 0) {
1587 fr_value_box_int32(vb, NULL, depth, false);
1588 goto finish;
1589 }
1590
1591 /*
1592 * The current module
1593 */
1594 if (strcmp(fmt, "module") == 0) {
1595 if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
1596
1597 goto finish;
1598 }
1599
1600 /*
1601 * Name of the instruction.
1602 */
1603 if (strcmp(fmt, "name") == 0) {
1604 if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
1605 strlen(instruction->name), false) < 0) goto error;
1606 goto finish;
1607 }
1608
1609 /*
1610 * The request processing stage.
1611 */
1612 if (strcmp(fmt, "processing_stage") == 0) {
1613 if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
1614
1615 goto finish;
1616 }
1617
1618 /*
1619 * The current return code.
1620 */
1621 if (strcmp(fmt, "rcode") == 0) {
1622 if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
1623
1624 goto finish;
1625 }
1626
1627 /*
1628 * The virtual server handling the request
1629 */
1630 if (strcmp(fmt, "server") == 0) {
1631 if (!unlang_call_current(request)) goto finish;
1632
1633 if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(unlang_call_current(request)), false) < 0) goto error;
1634
1635 goto finish;
1636 }
1637
1638 /*
1639 * Unlang instruction type.
1640 */
1641 if (strcmp(fmt, "type") == 0) {
1642 if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
1643 strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
1644
1645 goto finish;
1646 }
1647
1648 /*
1649 * All of the remaining things need a CONF_ITEM.
1650 */
1651 if (!instruction->ci) {
1652 if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 3, false) < 0) goto error;
1653
1654 goto finish;
1655 }
1656
1657 /*
1658 * Line number of the current section.
1659 */
1660 if (strcmp(fmt, "line") == 0) {
1661 fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
1662
1663 goto finish;
1664 }
1665
1666 /*
1667 * Filename of the current section.
1668 */
1669 if (strcmp(fmt, "filename") == 0) {
1670 if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
1671
1672 goto finish;
1673 }
1674
1675finish:
1676 if (vb->type != FR_TYPE_NULL) {
1678 } else {
1679 talloc_free(vb);
1680 }
1681
1682 return XLAT_ACTION_DONE;
1683}
1684
1685/** Initialize a unlang compiler / interpret.
1686 *
1687 * @param[in] ctx to bind lifetime of the interpret to.
1688 * Shouldn't be any free order issues here as
1689 * the interpret itself has no state.
1690 * But event loop should be stopped before
1691 * freeing the interpret.
1692 * @param[in] el for any timer or I/O events.
1693 * @param[in] funcs Callbacks to used to communicate request
1694 * state to our owner.
1695 * @param[in] uctx Data to pass to callbacks.
1696 */
1698 fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
1699{
1700 unlang_interpret_t *intp;
1701
1702 fr_assert(funcs->init_internal);
1703
1704 fr_assert(funcs->done_internal);
1705 fr_assert(funcs->done_detached);
1706 fr_assert(funcs->done_external);
1707
1708 fr_assert(funcs->detach);
1709 fr_assert(funcs->yield);
1710 fr_assert(funcs->resume);
1711 fr_assert(funcs->mark_runnable);
1712 fr_assert(funcs->scheduled);
1713
1714 MEM(intp = talloc(ctx, unlang_interpret_t));
1715 *intp = (unlang_interpret_t){
1716 .el = el,
1717 .funcs = *funcs,
1718 .uctx = uctx
1719 };
1720
1721 return intp;
1722}
1723
1724/** Discard the bottom most frame on the request's stack
1725 *
1726 * This is used for cleaning up after errors. i.e. the caller
1727 * uses a push function, and experiences an error and needs to
1728 * remove the frame that was just pushed.
1729 */
1731{
1732 frame_pop(request, request->stack);
1733}
1734
1735/** Set a specific interpreter for a request
1736 *
1737 */
1739{
1740 unlang_stack_t *stack = request->stack;
1741 stack->intp = intp;
1742}
1743
1744/** Get the interpreter set for a request
1745 *
1746 */
1748{
1749 unlang_stack_t *stack = request->stack;
1750
1751 return stack->intp;
1752}
1753
1754/** Get the event list for the current interpreter
1755 *
1756 */
1758{
1759 unlang_stack_t *stack = request->stack;
1760
1761 if (!stack->intp) return NULL;
1762
1763 return stack->intp->el;
1764}
1765
1766/** Set the default interpreter for this thread
1767 *
1768 */
1770{
1771 if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
1772
1773 intp_thread_default = intp;
1774}
1775
1776/** Get the default interpreter for this thread
1777 *
1778 * This allows detached requests to be executed asynchronously
1779 */
1781{
1782 if (!intp_thread_default) return NULL;
1783
1784 return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
1785}
1786
1788{
1789 xlat_t *xlat;
1790 /*
1791 * Should be void, but someone decided not to register multiple xlats
1792 * breaking the convention we use everywhere else in the server...
1793 */
1794 if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
1796
1797 if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
1799
1800 return 0;
1801}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
Definition action.h:38
@ UNLANG_ACTION_STOP_PROCESSING
Break out of processing the current request (unwind).
Definition action.h:42
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
va_list args
Definition acutest.h:770
static int const char * fmt
Definition acutest.h:573
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition call.c:225
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1184
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1762
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1170
#define cf_lineno(_cf)
Definition cf_util.h:104
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:244
#define cf_filename(_cf)
Definition cf_util.h:107
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:78
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition dcursor.h:437
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:210
#define MEM(x)
Definition debug.h:36
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
static fr_slen_t in
Definition dict.h:840
static xlat_action_t unlang_interpret_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Get information about the interpreter state.
Definition interpret.c:1538
void unlang_interpret_request_prioritise(request_t *request, uint32_t priority)
Definition interpret.c:1051
static size_t unlang_action_table_len
Definition interpret.c:49
static fr_table_num_ordered_t const unlang_frame_action_table[]
Definition interpret.c:51
static void unlang_interpret_request_detach(request_t *request)
Tell the interpreter to detach the request.
Definition interpret.c:1037
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:712
bool unlang_request_is_done(request_t const *request)
Return whether a request has been marked done.
Definition interpret.c:1330
static unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame, rlm_rcode_t *result, int *priority)
Evaluates all the unlang nodes in a section.
Definition interpret.c:497
static unlang_group_t empty_group
Definition interpret.c:902
unlang_action_t unlang_interpret_push_children(UNUSED rlm_rcode_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
Push the children of the current frame onto a new frame onto the stack.
Definition interpret.c:239
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:1730
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1251
static unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t *frame, rlm_rcode_t *result, int *priority)
Update the current result after each instruction, and after popping each stack frame.
Definition interpret.c:303
int unlang_interpret_push_instruction(request_t *request, void *instruction, rlm_rcode_t default_rcode, bool top_frame)
Push an instruction onto the request stack for later interpretation.
Definition interpret.c:949
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1006
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:1738
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:1747
rlm_rcode_t unlang_interpret_stack_result(request_t *request)
Get the current rcode for the frame.
Definition interpret.c:1291
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1276
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1360
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition interpret.c:1529
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1405
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1313
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition interpret.c:1787
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:1780
fr_dict_t const * old_dict
the previous dictionary for the request
Definition interpret.c:199
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition interpret.c:980
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition interpret.c:1769
#define DUMP_STACK
Definition interpret.c:125
int unlang_interpret_push(request_t *request, unlang_t const *instruction, rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
Push a new frame onto the stack.
Definition interpret.c:143
static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1216
unlang_interpret_t * unlang_interpret_init(TALLOC_CTX *ctx, fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
Initialize a unlang compiler / interpret.
Definition interpret.c:1697
static void instruction_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1232
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition interpret.c:1323
static void unlang_cancel_event(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
Signal the request to stop executing.
Definition interpret.c:1435
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1147
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition interpret.c:1420
static fr_table_num_ordered_t const unlang_action_table[]
Definition interpret.c:42
static void stack_dump(request_t *request)
Definition interpret.c:111
static int _local_variables_free(unlang_variable_ref_t *ref)
Definition interpret.c:203
static void instruction_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:59
bool unlang_interpret_is_resumable(request_t *request)
Check if a request as resumable.
Definition interpret.c:1342
int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs, rlm_rcode_t default_rcode, bool top_frame)
Push a configuration section onto the request stack for later interpretation.
Definition interpret.c:926
void unlang_interpret_stack_result_set(request_t *request, rlm_rcode_t rcode)
Overwrite the current stack rcode.
Definition interpret.c:1303
request_t * request
the request
Definition interpret.c:200
static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
Definition interpret.c:74
void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
Delivers a frame to one or more frames in the stack.
Definition interpret.c:1087
static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *args)
Allows a request to dynamically alter its own lifetime.
Definition interpret.c:1455
static size_t unlang_frame_action_table_len
Definition interpret.c:56
static _Thread_local unlang_interpret_t * intp_thread_default
The default interpreter instance for this thread.
Definition interpret.c:40
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:1757
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:38
unlang_request_prioritise_t prioritise
Function to re-priotise a request in the runnable queue.
Definition interpret.h:128
unlang_request_done_t done_internal
Function called when an internal request completes.
Definition interpret.h:118
unlang_request_resume_t resume
Function called when a request is resumed.
Definition interpret.h:123
#define UNLANG_SUB_FRAME
Definition interpret.h:36
unlang_request_done_t done_external
Function called when a external request completes.
Definition interpret.h:117
unlang_request_init_t detach
Function called when a request is detached.
Definition interpret.h:121
unlang_request_runnable_t mark_runnable
Function called when a request needs to be added back to the runnable queue.
Definition interpret.h:124
unlang_request_yield_t yield
Function called when a request yields.
Definition interpret.h:122
unlang_request_done_t done_detached
Function called when a detached request completes.
Definition interpret.h:119
unlang_request_scheduled_t scheduled
Function to check if a request is already scheduled.
Definition interpret.h:126
unlang_request_init_t init_internal
Function called to initialise an internal request.
Definition interpret.h:115
struct unlang_interpret_s unlang_interpret_t
Interpreter handle.
Definition interpret.h:47
External functions provided by the owner of the interpret.
Definition interpret.h:109
Private declarations for the unlang interpreter.
fr_event_list_t * el
unlang_request_func_t funcs
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define DEBUG_ENABLED5
True if global debug level 1-5 messages are enabled.
Definition log.h:261
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RERROR(fmt,...)
Definition log.h:298
#define RPERROR(fmt,...)
Definition log.h:302
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RDEBUG4(fmt,...)
Definition log.h:344
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
Definition base.c:31
talloc_free(reap)
Stores all information relating to an event list.
Definition event.c:377
static char * stack[MAX_STACK]
Definition radmin.c:159
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VOID
User data.
unsigned int uint32_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
@ MOD_ACTION_RETURN
Definition mod_action.h:40
@ MOD_ACTION_REJECT
Definition mod_action.h:41
@ MOD_PRIORITY_MAX
Definition mod_action.h:58
@ MOD_ACTION_RETRY
Definition mod_action.h:42
fr_retry_config_t retry
Definition mod_action.h:63
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:62
Declarations for the unlang module interface.
int fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition pair.c:1832
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define RDEBUG_ENABLED()
Definition radclient.h:49
fr_table_num_sorted_t const rcode_table[]
Definition rcode.c:35
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_TIMEOUT
Module (or section) timed out.
Definition rcode.h:50
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:52
#define REQUEST_VERIFY(_x)
Definition request.h:305
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
Definition request.h:178
@ REQUEST_TYPE_INTERNAL
A request generated internally.
Definition request.h:179
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
Definition request.h:180
#define request_is_detachable(_x)
Definition request.h:187
@ REQUEST_DONE
Request has completed.
Definition request.h:89
@ REQUEST_STOP_PROCESSING
Request has been signalled to stop.
Definition request.h:88
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
#define request_data_add(_request, _unique_ptr, _unique_int, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
@ FR_SIGNAL_DETACH
Request is being detached from its parent.
Definition signal.h:45
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:177
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_delta_eq(_a, _b)
Definition time.h:287
static fr_time_t fr_time_from_sec(time_t when)
Convert a time_t (wallclock time) to a fr_time_t (internal time)
Definition time.h:858
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
fr_time_t fr_timer_when(fr_timer_t *ev)
Internal timestamp representing when the timer should fire.
Definition timer.c:719
An event timer list.
Definition timer.c:50
A timer event.
Definition timer.c:84
#define fr_timer_in(...)
Definition timer.h:87
static fr_event_list_t * el
uint8_t required
Argument must be present, and non-empty.
Definition xlat.h:145
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:382
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:169
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:144
fr_retry_state_t state
#define unlang_frame_perf_resume(_x)
static void frame_pop(request_t *request, unlang_stack_t *stack)
Pop a stack frame, removing any associated dynamically allocated state.
unlang_t * next
Next node (executed on UNLANG_ACTION_EXECUTE_NEXT et al).
static void frame_next(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Advance to the next sibling instruction.
@ UNLANG_FRAME_FLAG_NONE
No flags.
static bool is_repeatable(unlang_stack_frame_t const *frame)
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:98
static void repeatable_clear(unlang_stack_frame_t *frame)
static unlang_action_t unwind_to_depth(unlang_stack_t *stack, unsigned int to_depth)
Mark up frames as cancelled so they're immediately popped by the interpreter.
unlang_retry_t * retry
if the frame is being retried.
unlang_signal_t signal
function to call when signalling this stack frame
char const * debug_name
Printed in log messages when the node is executed.
void * state
Stack frame specialisations.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
static void frame_state_init(unlang_stack_t *stack, unlang_stack_frame_t *frame)
int priority
Result priority.
unlang_dump_t dump
Dump additional information about the frame state.
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
rindent_t indent
Indent level of the request when the frame was created.
fr_timer_t * ev
unlang_process_t interpret
Function to interpret the keyword.
int depth
of this retry structure
request_t * request
CONF_ITEM * ci
used to generate this item
static bool is_top_frame(unlang_stack_frame_t const *frame)
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
char const * name
Unknown...
static bool is_break_point(unlang_stack_frame_t const *frame)
#define has_debug_braces(_thing)
@ UNLANG_TYPE_GROUP
Grouping section.
Definition unlang_priv.h:49
unlang_t const * instruction
The unlang node we're evaluating.
static bool is_rcode_set(unlang_stack_frame_t const *frame)
static bool is_yielded(unlang_stack_frame_t const *frame)
static void top_frame_set(unlang_stack_frame_t *frame)
unlang_variable_t * variables
rarely used, so we don't usually need it
rlm_rcode_t result
The result from executing the instruction.
char const * name
Name of the operation.
unlang_frame_action_t
Allows the frame evaluator to signal the interpreter.
Definition unlang_priv.h:88
@ UNLANG_FRAME_ACTION_POP
Pop the current frame, and check the next one further up in the stack for what to do next.
Definition unlang_priv.h:89
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
Definition unlang_priv.h:93
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
Definition unlang_priv.h:92
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
Definition unlang_priv.h:91
static void yielded_set(unlang_stack_frame_t *frame)
static bool is_continue_point(unlang_stack_frame_t const *frame)
static void yielded_clear(unlang_stack_frame_t *frame)
#define unlang_frame_perf_yield(_x)
#define unlang_frame_perf_cleanup(_x)
unlang_t const * next
The next unlang node we will evaluate.
fr_dict_t * dict
our dictionary
static bool is_return_point(unlang_stack_frame_t const *frame)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
unlang_t * children
Children beneath this group.
unlang_frame_flag_t flag
Unwind flags.
static bool is_unwinding(unlang_stack_frame_t const *frame)
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
fr_pair_t * fr_pair_list_tail(fr_pair_list_t const *list)
Get the tail of a valuepair list.
Definition pair_inline.c:55
fr_pair_t * fr_pair_list_prev(fr_pair_list_t const *list, fr_pair_t const *item))
Get the previous item in a valuepair list before a specific entry.
Definition pair_inline.c:82
#define RETRY_INIT
Definition retry.h:39
uint32_t mrc
Maximum retransmission count.
Definition retry.h:36
@ FR_RETRY_MRC
reached maximum retransmission count
Definition retry.h:47
@ FR_RETRY_CONTINUE
Definition retry.h:46
@ FR_RETRY_MRD
reached maximum retransmission duration
Definition retry.h:48
fr_time_delta_t mrd
Maximum retransmission duration.
Definition retry.h:35
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition value.c:4158
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4379
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:640
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:651
static size_t char ** out
Definition value.h:1020
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition xlat_func.c:216