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