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: 4ab8e32f20d42090b656cd63420ef5c19a03fdef $
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: 4ab8e32f20d42090b656cd63420ef5c19a03fdef $")
26
27#include <freeradius-devel/unlang/action.h>
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 "unlang_priv.h"
36#include "module_priv.h"
37
38
39/** The default interpreter instance for this thread
40 */
42
44 { L("fail"), UNLANG_ACTION_FAIL },
45 { L("calculate-result"), UNLANG_ACTION_CALCULATE_RESULT },
46 { L("next"), UNLANG_ACTION_EXECUTE_NEXT },
47 { L("pushed-child"), UNLANG_ACTION_PUSHED_CHILD },
48 { L("yield"), UNLANG_ACTION_YIELD }
49};
51
58
59#ifndef NDEBUG
60#include <freeradius-devel/unlang/module_priv.h>
61
70
71/** Try and figure out where p_result points to
72 *
73 * If it's somewhere other than these three locations, it's probably wrong.
74 */
75static int find_p_result_location(p_result_location_t *location, void **chunk, request_t *request, void *ptr)
76{
77 unlang_stack_t *stack = request->stack;
79 unsigned int i;
80
81 for (i = 0; i <= (unsigned int)stack->depth; i++) {
82 frame = &stack->frame[i];
83 if (frame->state && (ptr >= (void *)frame->state) &&
84 (ptr < ((void *)((uint8_t *)frame->state + talloc_get_size(frame->state))))) {
85 *location = P_RESULT_LOCATION_STATE;
86 *chunk = frame->state;
87 return i;
88 }
89
90 if (ptr == &frame->section_result) {
91 *location = P_RESULT_LOCATION_FRAME;
92 *chunk = NULL;
93 return i;
94 }
95
96 if (ptr == &frame->scratch_result) {
97 *location = P_RESULT_LOCATION_SCRATCH;
98 *chunk = NULL;
99 return i;
100 }
101
102 if (!frame->instruction) continue;
103
104 switch (frame->instruction->type) {
106 {
107 unlang_frame_state_module_t *mod_state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
108
109 if (!mod_state->rctx) continue;
110
111 if ((ptr >= (void *)mod_state->rctx) &&
112 (ptr < ((void *)((uint8_t *)mod_state->rctx + talloc_get_size(mod_state->rctx))))) {
114 *chunk = mod_state->rctx;
115 return i;
116 }
117
118 /*
119 * We don't know where the child frame is, so we can't
120 * determine where the p_result is.
121 */
122 }
123 continue;
124
125 default:
126 break;
127 }
128 }
129
130 *location = P_RESULT_LOCATION_UNKNOWN;
131 *chunk = NULL;
132 return -1;
133}
134
136 { L("frame"), P_RESULT_LOCATION_FRAME },
137 { L("module_rctx"), P_RESULT_LOCATION_MODULE_RCTX },
138 { L("scratch"), P_RESULT_LOCATION_SCRATCH },
139 { L("state"), P_RESULT_LOCATION_STATE },
140 { L("unknown"), P_RESULT_LOCATION_UNKNOWN }
141};
143
144static void instruction_dump(request_t *request, unlang_t const *instruction)
145{
146 RINDENT();
147 if (!instruction) {
148 RDEBUG2("instruction <none>");
149 REXDENT();
150 return;
151 }
152
153 RDEBUG2("type %s", unlang_ops[instruction->type].name);
154 RDEBUG2("name %s", instruction->name);
155 RDEBUG2("debug_name %s", instruction->debug_name);
156 REXDENT();
157}
158
159static void CC_HINT(nonnull) actions_dump(request_t *request, unlang_t const *instruction)
160{
161 int i;
162
163 RDEBUG2("actions");
164 RINDENT();
165 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
166 RDEBUG2("%s: %s",
167 fr_table_str_by_value(mod_rcode_table, i, "<invalid>"),
168 mod_action_name[instruction->actions.actions[i]]);
169 }
170 REXDENT();
171}
172
173static void frame_dump(request_t *request, unlang_stack_frame_t *frame, bool with_actions)
174{
175 unlang_op_t *op = NULL;
176
177 if (frame->instruction) {
178 op = &unlang_ops[frame->instruction->type];
179 instruction_dump(request, frame->instruction);
180 }
181
182 RINDENT();
183 if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
184 if (frame->next) {
185 RDEBUG2("next %s", frame->next->debug_name);
186 } else {
187 RDEBUG2("next <none>");
188 }
189
191
192 if (is_private_result(frame)) {
193 int location;
195 void *chunk;
196
197 RDEBUG2("p_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"));
198 RDEBUG2("p_priority %s", mod_action_name[frame->p_result->priority]);
199
200 location = find_p_result_location(&type, &chunk, request, frame->p_result);
201 RDEBUG2("p_location %s [%i] %p (%s)", fr_table_str_by_value(p_result_location_table, type, "<invalid>"),
202 location, frame->p_result, chunk ? talloc_get_name(chunk) : "<none>"
203 );
204 } else {
205 RDEBUG2("sec_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->section_result.rcode, "<invalid>"));
206 RDEBUG2("sec_priority %s", mod_action_name[frame->section_result.priority]);
207 }
208 RDEBUG2("scr_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->scratch_result.rcode, "<invalid>"));
209 RDEBUG2("scr_priority %s", mod_action_name[frame->scratch_result.priority]);
210 RDEBUG2("top_frame %s", is_top_frame(frame) ? "yes" : "no");
211 RDEBUG2("repeat %s", is_repeatable(frame) ? "yes" : "no");
212 RDEBUG2("yielded %s", is_yielded(frame) ? "yes" : "no");
213 RDEBUG2("unwind %s", is_unwinding(frame) ? "yes" : "no");
214
215 if (frame->instruction) {
216 RDEBUG2("control %s%s%s",
217 is_break_point(frame) ? "b" : "-",
218 is_return_point(frame) ? "r" : "-",
219 is_continue_point(frame) ? "c" : "-"
220 );
221 if (with_actions) actions_dump(request, frame->instruction);
222 }
223
224 /*
225 * Call the custom frame dump function
226 */
227 if (op && op->dump) op->dump(request, frame);
228 REXDENT();
229}
230
231static void stack_dump_body(request_t *request, bool with_actions)
232{
233 int i;
234 unlang_stack_t *stack = request->stack;
235
236 RDEBUG2("----- Begin stack debug [depth %i] -----",
237 stack->depth);
238 for (i = stack->depth; i >= 0; i--) {
239 unlang_stack_frame_t *frame = &stack->frame[i];
240 RDEBUG2("[%d] Frame contents", i);
241 frame_dump(request, frame, with_actions);
242 }
243 RDEBUG2("----- End stack debug [depth %i] -------", stack->depth);
244}
245
246void stack_dump(request_t *request)
247{
248 stack_dump_body(request, false);
249}
250
252{
253 stack_dump_body(request, true);
254}
255#define DUMP_STACK if (DEBUG_ENABLED5) stack_dump(request)
256#else
257#define DUMP_STACK
258#endif
259
260/** Push a new frame onto the stack
261 *
262 * @param[in] p_result Where to write the result of evaluating the section.
263 * If NULL, results will be written to frame->section_result and will
264 * be automatically merged with the next highest frame when this one
265 * is popped.
266 * @param[in] request to push the frame onto.
267 * @param[in] instruction One or more unlang_t nodes describing the operations to execute.
268 * @param[in] conf Configuration for the frame. If NULL, the following values areused:
269 * - default result = UNLANG_RESULT_NOT_SET
270 * - top_frame = UNLANG_SUB_FRAME
271 * - no_rcode = false
272 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
273 * or to execute subsequent nodes.
274 * @return
275 * - 0 on success.
276 * - -1 on call stack too deep.
277 */
279 unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
280{
281 unlang_stack_t *stack = request->stack;
283
284 static unlang_frame_conf_t default_conf = {
286 .top_frame = UNLANG_SUB_FRAME
287 };
288
289 if (!conf) conf = &default_conf;
290
291 if (!instruction) return -1;
292
293#ifndef NDEBUG
294 if (DEBUG_ENABLED5) RDEBUG3("unlang_interpret_push called with instruction type \"%s\" - args %s %s",
295 instruction->debug_name,
296 do_next_sibling ? "UNLANG_NEXT_SIBLING" : "UNLANG_NEXT_STOP",
297 conf->top_frame ? "UNLANG_TOP_FRAME" : "UNLANG_SUB_FRAME");
298#endif
299
300 /*
301 * This is not a cancellation point.
302 *
303 * If we cancel here bad things happen inside the interpret.
304 */
305 if (stack->depth >= (UNLANG_STACK_MAX - 1)) {
306 RERROR("Call stack is too deep");
307 return - 1;
308 }
309
310 stack->depth++;
311
312 /*
313 * Initialize the next stack frame.
314 */
315 frame = &stack->frame[stack->depth];
316 memset(frame, 0, sizeof(*frame));
317
318 frame->instruction = instruction;
319
320 if (do_next_sibling && instruction->list) {
321 frame->next = unlang_list_next(instruction->list, instruction);
322 }
323 /* else frame->next MUST be NULL */
324
326 if (conf->top_frame) top_frame_set(frame);
327
328 frame->p_result = p_result ? p_result : &frame->section_result;
329 *frame->p_result = conf->default_result;
330
331 frame->indent = request->log.indent;
332
333 frame_state_init(stack, frame);
334
335 return 0;
336}
337
338typedef struct {
339 fr_dict_t const *old_dict; //!< the previous dictionary for the request
340 request_t *request; //!< the request
342
344{
345 fr_pair_t *vp, *prev;
346
347 /*
348 * Local variables are appended to the end of the list. So we remove them by walking backwards
349 * from the end of the list.
350 */
351 vp = fr_pair_list_tail(&ref->request->local_pairs);
352 while (vp) {
353 fr_assert(vp->da->flags.local);
354
355 prev = fr_pair_list_prev(&ref->request->local_pairs, vp);
356 if (vp->da->dict != ref->request->local_dict) {
357 break;
358 }
359
360 (void) fr_pair_delete(&ref->request->local_pairs, vp);
361 vp = prev;
362 }
363
364 ref->request->local_dict = ref->old_dict;
365
366 return 0;
367}
368
369/** Push the children of the current frame onto a new frame onto the stack
370 *
371 * @param[out] p_result set to RLM_MODULE_FAIL if pushing the children fails
372 * @param[in] request to push the frame onto.
373 * @param[in] default_rcode The default result.
374 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
375 * or to execute subsequent nodes.
376 * @return
377 * - UNLANG_ACTION_PUSHED_CHILD on success.
378 * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
379 * - UNLANG_ACTION_FAIL, fatal error, usually stack overflow.
380 */
382 rlm_rcode_t default_rcode, bool do_next_sibling)
383{
384 unlang_stack_t *stack = request->stack;
385 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
388
390
392
393 /*
394 * The compiler catches most of these, EXCEPT for the
395 * top-level 'recv Access-Request' etc. Which can exist,
396 * and can be empty.
397 */
398 if (unlang_list_empty(&g->children)) {
399 RDEBUG2("... ignoring empty subsection ...");
401 }
402
403 if (unlang_interpret_push(p_result, request, unlang_list_head(&g->children),
404 FRAME_CONF(default_rcode, UNLANG_SUB_FRAME), do_next_sibling) < 0) {
406 }
407
409
410 /*
411 * Note that we do NOT create the variables, This way we don't have to worry about any
412 * uninitialized values. If the admin tries to use the variable without initializing it, they
413 * will get a "no such attribute" error.
414 */
415 if (!frame->state) {
416 MEM(ref = talloc(stack, unlang_variable_ref_t));
417 frame->state = ref;
418 } else {
419 MEM(ref = talloc(frame->state, unlang_variable_ref_t));
420 }
421
422 /*
423 * Set the destructor to clean up local variables.
424 */
425 ref->request = request;
426 ref->old_dict = request->local_dict;
427 request->local_dict = g->variables->dict;
428 talloc_set_destructor(ref, _local_variables_free);
429
431}
432
433static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx);
434
435/** Update the current result after each instruction, and after popping each stack frame
436 *
437 * @note Sets stack->scratch to be the the result of the frame being popped.
438 *
439 * @param[in] request The current request.
440 * @param[in] frame The current stack frame.
441 * @param[in] result from the previous action.
442 * @return
443 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions.
444 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
445 */
446static inline CC_HINT(always_inline)
448{
449 unlang_t const *instruction = frame->instruction;
450 unlang_stack_t *stack = request->stack;
451 unlang_result_t *frame_result = frame->p_result;
452
453 if (is_unwinding(frame)) {
454 RDEBUG4("** [%i] %s - unwinding frame", stack->depth, __FUNCTION__);
456 }
457
458 /*
459 * Don't calculate a new return code for the frame, just skip
460 * to the next instruction.
461 */
462 if (result->rcode == RLM_MODULE_NOT_SET) {
463 RDEBUG4("** [%i] %s - skipping frame, no result set",
464 stack->depth, __FUNCTION__);
466 }
467
468 fr_assert(MOD_ACTION_VALID(frame_result->priority));
469 fr_assert(MOD_ACTION_VALID(result->priority));
470
471 RDEBUG4("** [%i] %s - have (%s %s) frame or module returned (%s %s)",
472 stack->depth, __FUNCTION__,
473 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
474 mod_action_name[frame_result->priority],
475 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
476 mod_action_name[result->priority]);
477
478 /*
479 * Update request->rcode if the instruction says we should
480 * We don't care about priorities for this.
481 *
482 * This is the field that's evaluated in unlang conditions
483 * like `if (ok)`.
484 */
485 if (is_rcode_set(frame) && (request->rcode != result->rcode)) {
486 RDEBUG3("Setting request->rcode to '%s'",
487 fr_table_str_by_value(rcode_table, result->rcode, "<INVALID>"));
488 request->rcode = result->rcode;
489 }
490
491 /*
492 * The array holds a default priority for this return
493 * code. Grab it in preference to any unset priority.
494 */
495 if (result->priority == MOD_ACTION_NOT_SET) {
496 result->priority = instruction->actions.actions[result->rcode];
497
498 fr_assert(MOD_ACTION_VALID(result->priority));
499
500 RDEBUG4("** [%i] %s - using default instruction priority for %s, %s",
501 stack->depth, __FUNCTION__,
502 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
503 mod_action_name[result->priority]);
504 }
505
506 /*
507 * Deal with special priorities which indicate we need
508 * to do something in addition to modifying the frame's
509 * rcode.
510 */
511 switch (result->priority) {
512 /*
513 * The child's prioriy value indicates we
514 * should return from this frame.
515 */
517 RDEBUG4("** [%i] %s - action says to return with (%s %s)",
518 stack->depth, __FUNCTION__,
519 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
520 mod_action_name[result->priority]);
521
522 *frame_result = UNLANG_RESULT_RCODE(result->rcode);
524
525 /*
526 * Reject means we should return, but
527 * with a reject rcode. This allows the
528 * user to change normally positive rcodes
529 * into negative ones.
530 *
531 * They could also just check the rcode
532 * after the module returns...
533 */
535 RDEBUG4("** [%i] %s - action says to return with (%s %s)",
536 stack->depth, __FUNCTION__,
538 mod_action_name[result->priority]);
539
540 *frame_result = UNLANG_RESULT_RCODE(RLM_MODULE_REJECT);
542
543 case MOD_ACTION_RETRY:
544 {
545 unlang_retry_t *retry = frame->retry;
546
547 RDEBUG4("** [%i] %s - action says to retry with",
548 stack->depth, __FUNCTION__);
549
550 /*
551 * If this is the first time doing the retry,
552 * then allocate the structure and set the timer.
553 */
554 if (!retry) {
555 MEM(frame->retry = retry = talloc_zero(stack, unlang_retry_t));
556
557 retry->request = request;
558 retry->depth = stack->depth;
559 retry->state = FR_RETRY_CONTINUE;
560 retry->count = 1;
561
562 /*
563 * Set a timer which automatically fires
564 * if there's a timeout. And parent it
565 * from the retry structure, so that the
566 * timer is automatically freed when the
567 * frame is cleaned up.
568 */
569 if (fr_time_delta_ispos(instruction->actions.retry.mrd)) {
570 if (fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, instruction->actions.retry.mrd,
571 false, instruction_retry_handler, retry) < 0) {
572 RPEDEBUG("Failed inserting retry event");
573 *frame_result = UNLANG_RESULT_RCODE(RLM_MODULE_FAIL);
574 goto finalize;
575 }
576 }
577
578 } else {
579 /*
580 * We've been told to stop doing retries,
581 * probably from a timeout.
582 */
583 if (retry->state != FR_RETRY_CONTINUE) goto timeout;
584
585 /*
586 * Clamp it at the maximum count.
587 */
588 if (instruction->actions.retry.mrc > 0) {
589 retry->count++;
590
591 if (retry->count >= instruction->actions.retry.mrc) {
592 retry->state = FR_RETRY_MRC;
593
594 REDEBUG("Retries hit max_rtx_count (%u) - returning 'timeout'", instruction->actions.retry.mrc);
595
596 timeout:
598 goto finalize;
599 }
600 }
601 }
602
603 RINDENT();
604 if (instruction->actions.retry.mrc) {
605 RDEBUG("... retrying (%u/%u)", retry->count, instruction->actions.retry.mrc);
606 } else {
607 RDEBUG("... retrying");
608 }
609 REXDENT();
610
611 TALLOC_FREE(frame->state);
613 frame_state_init(stack, frame); /* Don't change p_result */
615 }
616
617 default:
618 break;
619 }
620
621finalize:
622 /*
623 * We're higher or equal to previous priority, remember this
624 * return code and priority.
625 */
626 if (result->priority >= frame_result->priority) {
627 fr_assert(MOD_ACTION_VALID(result->priority));
628 fr_assert(MOD_ACTION_VALID(frame_result->priority));
629
630 RDEBUG4("** [%i] %s - overwriting existing result (%s %s) with higher priority (%s %s)",
631 stack->depth, __FUNCTION__,
632 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
633 mod_action_name[frame_result->priority],
634 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
635 mod_action_name[result->priority]);
636 *frame->p_result = *result;
637 }
638
639 /*
640 * Determine if we should continue processing siblings
641 * or pop the frame ending the section.
642 */
644}
645
646/** Function called to merge inter-stack-frame results
647 *
648 * This function is called whenever a frame is popped from the stack.
649 *
650 * 'result' is the result from the frame being popped, and 'frame' is the next highest frame in the stack.
651 *
652 * The logic here is very similar to result_eval(), with two important differences:
653 * - The priority of the lower frame is ignored, and the default priority of the higher frame is used.
654 * Unless the higher frame's priority is MOD_ACTION_NOT_SET, in which case the lower frame's priority is used.
655 */
656static inline CC_HINT(always_inline)
658{
659 unlang_stack_t *stack = request->stack;
660 unlang_result_t our_result = *result;
661
662 fr_assert(MOD_ACTION_VALID(result->priority));
663
664 /*
665 * When a stack frame is being popped, the priority of the
666 * source (lower) frame is ignored, and the default priority
667 * of the destination (higher) frame is used.
668 *
669 * We could (easily) add support for preserving the priority
670 * from the lower frame, if the priority of the higher frame
671 * was MOD_ACTION_NOT_SET, but there are no concrete use
672 * cases for this yet.
673 */
674 if (result->rcode != RLM_MODULE_NOT_SET) {
675 fr_assert(MOD_ACTION_VALID(frame->instruction->actions.actions[result->rcode]));
676 our_result.priority = frame->instruction->actions.actions[result->rcode];
677 }
678
679 RDEBUG4("** [%i] %s - using instruction priority for higher frame (%s, %s)",
680 stack->depth, __FUNCTION__,
681 fr_table_str_by_value(mod_rcode_table, our_result.rcode, "<invalid>"),
682 mod_action_name[our_result.priority]);
683
684 return result_calculate(request, frame, &our_result);
685}
686
687static inline CC_HINT(always_inline) void instruction_done_debug(request_t *request, unlang_stack_frame_t *frame, unlang_t const *instruction)
688{
689 if (has_debug_braces(instruction)) {
690 REXDENT();
691
692 /*
693 * If we're at debug level 1, don't emit the closing
694 * brace as the opening brace wasn't emitted.
695 *
696 * Not a typo, we don't want to print the scratch_result
697 * here, aka the ones the section actually returned,
698 * vs the section result, which may have just been left
699 * at defaults.
700 */
702 RDEBUG("# %s %s%s%s", frame->instruction->debug_name,
703 frame->p_result == &frame->section_result ? "(" : "((",
705 frame->p_result == &frame->section_result ? ")" : "))");
706 } else {
707 RDEBUG2("} # %s %s%s%s", frame->instruction->debug_name,
708 frame->p_result == &frame->section_result ? "(" : "((",
710 frame->p_result == &frame->section_result ? ")" : "))");
711 }
712 }
713}
714
715/** Evaluates all the unlang nodes in a section
716 *
717 * This function interprets a list of unlang instructions at a given level using the same
718 * stack frame, and pushes additional frames onto the stack as needed.
719 *
720 * This function can be seen as moving horizontally.
721 *
722 * @param[in] request The current request.
723 * @param[in] frame The current stack frame.
724 * @return
725 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions in the current stack frame
726 * which may not be the same frame as when this function
727 * was called.
728 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
729 */
730static inline CC_HINT(always_inline)
732{
733 unlang_stack_t *stack = request->stack;
734 unlang_result_t *scratch = &frame->scratch_result;
735
736 /*
737 * Loop over all the instructions in this list.
738 */
739 while (frame->instruction) {
740 unlang_t const *instruction = frame->instruction;
743
745
746 fr_assert(instruction->debug_name != NULL); /* if this happens, all bets are off. */
747 fr_assert(unlang_ops[instruction->type].interpret != NULL);
748 fr_assert(frame->process != NULL);
749
750 REQUEST_VERIFY(request);
751
752 /*
753 * We're running this frame, so it can't possibly be yielded.
754 */
755 if (is_yielded(frame)) {
756 RDEBUG("%s - Resuming execution", instruction->debug_name);
757 yielded_clear(frame);
758 }
759
760#ifndef NDEBUG
761 /*
762 * Failure testing!
763 */
764 if (request->ins_max) {
765 request->ins_count++;
766
767 if (request->ins_count >= request->ins_max) {
768 RERROR("Failing request due to maximum instruction count %" PRIu64, request->ins_max);
769
771 }
772 }
773#endif
774
775 /*
776 * We're not re-entering this frame, this is the first
777 * time we're evaluating this instruction, so we should
778 * print debug braces and indent.
779 */
780 if (!is_repeatable(frame)) {
781 if (has_debug_braces(frame)) {
782 RDEBUG2("%s {", instruction->debug_name);
783 RINDENT();
784 }
785 /*
786 * Clear the repeatable flag so this frame
787 * won't get executed again unless it specifically
788 * requests it.
789 *
790 * The flag may still be set again during the
791 * process function to indicate that the frame
792 * should be evaluated again.
793 */
794 } else {
795 repeatable_clear(frame);
796 }
797
798 /*
799 * Execute an operation
800 */
801 RDEBUG4("** [%i] %s >> %s", stack->depth, __FUNCTION__,
802 unlang_ops[instruction->type].name);
803
805
806 /*
807 * catch plays games with the frame so we skip
808 * to the next catch section at a given depth,
809 * it's not safe to access frame->instruction
810 * after this point, and the cached instruction
811 * should be used instead.
812 */
813 ua = frame->process(&frame->scratch_result, request, frame);
814
816
817 RDEBUG4("** [%i] %s << %s (%s %s)", stack->depth, __FUNCTION__,
819 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<INVALID>"),
820 mod_action_name[scratch->priority]);
821
822 /*
823 * If the frame is cancelled we ignore the
824 * return code of the process function and
825 * pop the frame. We'll keep popping
826 * frames until we hit a non-cancelled frame
827 * or the top frame.
828 */
829 if (is_unwinding(frame)) goto calculate_result;
830
831 switch (ua) {
832 /*
833 * The operation resulted in additional frames
834 * being pushed onto the stack, execution should
835 * now continue at the deepest frame.
836 */
838 fr_assert_msg(&stack->frame[stack->depth] > frame,
839 "Instruction %s returned UNLANG_ACTION_PUSHED_CHILD, "
840 "but stack depth was not increased",
841 instruction->name);
844
845 /*
846 * Yield control back to the scheduler, or whatever
847 * called the interpreter.
848 */
850 fr_assert_msg(&stack->frame[stack->depth] == frame,
851 "Instruction %s returned UNLANG_ACTION_YIELD, but pushed additional "
852 "frames for evaluation. Instruction should return UNLANG_ACTION_PUSHED_CHILD "
853 "instead", instruction->name);
855 yielded_set(frame);
856 RDEBUG4("** [%i] %s - yielding with current (%s %s)", stack->depth, __FUNCTION__,
857 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"),
858 mod_action_name[scratch->priority]);
860
861 /*
862 * This action is intended to be returned by library
863 * functions. It reduces boilerplate.
864 */
866 /*
867 * Let unlang_calculate figure out if this is the final result
868 */
869 frame->scratch_result = UNLANG_RESULT_RCODE(RLM_MODULE_FAIL);
871
872 /*
873 * Instruction finished execution,
874 * check to see what we need to do next, and update
875 * the section rcode and priority.
876 */
878 calculate_result:
879 /*
880 * Merge in the scratch result _before_ printing
881 * out the rcode for the frame, so get what we'll
882 * actually return.
883 */
884 fa = result_calculate(request, frame, &frame->scratch_result);
885
886 instruction_done_debug(request, frame, instruction);
887
888 switch (fa) {
890 goto pop;
891
893 if (has_debug_braces(instruction)) {
894 REXDENT();
895 RDEBUG2("} # retrying the same section");
896 }
897 continue; /* with the current instruction */
898
899 default:
900 break;
901 }
902 break;
903
904 /*
905 * Execute the next instruction in this frame
906 */
908 if (has_debug_braces(instruction)) {
909 REXDENT();
910 RDEBUG2("}");
911 }
912 break;
913 } /* switch over return code from the interpret function */
914
915 frame_next(stack, frame);
916 }
917
918pop:
919 fr_assert(MOD_ACTION_VALID(frame->p_result->priority));
920
921 RDEBUG4("** [%i] %s - done current subsection with (%s %s), %s",
922 stack->depth, __FUNCTION__,
923 fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"),
924 mod_action_name[frame->p_result->priority],
925 frame->p_result == &(frame->section_result) ? "will set higher frame rcode" : "will NOT set higher frame rcode (p_result)");
926
928}
929
930/** Run the interpreter for a current request
931 *
932 * This function runs the interpreter for a request. It deals with popping
933 * stack frames, and calculating the final result for the frame.
934 *
935 * @param[in] request to run. If this is an internal request
936 * the request may be freed by the interpreter.
937 * @param[in] running Is the interpreter already running.
938 * @return The final request rcode.
939 */
940CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
941{
942 unlang_stack_t *stack = request->stack;
943 unlang_interpret_t *intp = stack->intp;
944 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
945
946 /*
947 * This is needed to ensure that if a frame is marked
948 * for unwinding whilst the request is yielded, we
949 * unwind the cancelled frame correctly, instead of
950 * continuing.
951 */
953
954#ifndef NDEBUG
955 if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
957#endif
958
959 fr_assert(!unlang_request_is_scheduled(request)); /* if we're running it, it can't be scheduled */
960 fr_assert_msg(intp, "request has no interpreter associated");
961
962 RDEBUG4("** [%i] %s - interpret entered", stack->depth, __FUNCTION__);
963 if (!running) intp->funcs.resume(request, intp->uctx);
964
965 for (;;) {
966 fr_assert(stack->depth > 0);
968
969 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
971 switch (fa) {
972 next:
973 RDEBUG4("** [%i] %s - frame action next", stack->depth, __FUNCTION__);
975
976 case UNLANG_FRAME_ACTION_NEXT: /* Evaluate the current frame */
977 frame = &stack->frame[stack->depth];
978 fa = frame_eval(request, frame);
979 if (fa != UNLANG_FRAME_ACTION_POP) continue;
980
981 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
984
985 case UNLANG_FRAME_ACTION_POP: /* Pop this frame and check the one beneath it */
986 {
987 bool top_frame = is_top_frame(frame);
988 bool private_result = is_private_result(frame);
989
990 unlang_result_t section_result = frame->section_result; /* record the result of the frame before we pop it*/
991
993
994 /*
995 * Triggers can run modules which pop, and then the stack is empty.
996 */
997 if (unlikely(stack->depth == 0)) {
998 break;
999 }
1000
1001 /*
1002 * Head on back up the stack
1003 */
1004 frame_pop(request, stack);
1005 RDEBUG4("** [%i] %s - frame popped", stack->depth + 1, __FUNCTION__);
1006
1007 /*
1008 * Update the stack frame
1009 */
1010 frame = &stack->frame[stack->depth];
1011 DUMP_STACK;
1012
1013 /*
1014 * Transition back to the C stack
1015 *
1016 * We still need to merge in the previous frame's result,
1017 * but we don't care about the action, as we're returning.
1018 */
1019 if (top_frame) {
1020 if (!private_result) result_calculate(request, frame, &section_result);
1021 break; /* stop */
1022 }
1023
1024 /*
1025 * Don't process the section result for a frame if
1026 * the result is being consumed by a module.
1027 */
1028 if (private_result) {
1030 /*
1031 * Merge lower frame into higher frame.
1032 *
1033 * this _MUST_ be done, even on resume, because the
1034 * section result needs to be updated for the frame
1035 * being resumed, in case it cares about the rcode
1036 * like transaction sections.
1037 */
1038 } else {
1039 fa = result_pop(request, frame, &section_result);
1040 }
1041
1042 /*
1043 * Resume a "foreach" loop, or a "load-balance" section
1044 * or anything else that needs to be checked on the way
1045 * back on up the stack. Here we just resume evaluating
1046 * the frame, we don't advance the instruction.
1047 */
1048 if (!is_unwinding(frame) && is_repeatable(frame)) goto next;
1049
1050 /*
1051 * Close out the section we entered earlier
1052 *
1053 * @todo - this arguably accesses the
1054 * frame after it's been popped, but this
1055 * is usually OK. :(
1056 */
1057 instruction_done_debug(request, frame, frame->instruction);
1058
1060
1061 /*
1062 * If we're continuing after popping a frame
1063 * then we advance the instruction else we
1064 * end up executing the same code over and over...
1065 */
1066 switch (fa) {
1068 DEBUG4("** [%i] %s - continuing after subsection with (%s %s)",
1069 stack->depth, __FUNCTION__,
1072 frame_next(stack, frame);
1073 goto next;
1074
1075 /*
1076 * Else if we're really done with this frame
1077 * print some helpful debug...
1078 */
1079 default:
1080 RDEBUG4("** [%i] %s - done current subsection with (%s %s)",
1081 stack->depth, __FUNCTION__,
1084 continue;
1085 }
1086
1087 }
1088
1090 /* Cannot yield from a nested call to unlang_interpret */
1091 fr_assert(!running);
1092
1093 RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
1094 intp->funcs.yield(request, intp->uctx);
1095 return RLM_MODULE_NOT_SET;
1096
1097 case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
1098 goto next;
1099 }
1100 break;
1101 }
1102
1103 fr_assert(stack->depth >= 0);
1104
1105 /*
1106 * We're at the top frame, return the result from the
1107 * stack, and get rid of the top frame.
1108 */
1109 RDEBUG4("** [%i] %s - interpret exiting, returning (%s)", stack->depth, __FUNCTION__,
1111
1112 DUMP_STACK;
1113
1114 {
1115 rlm_rcode_t rcode;
1116 /*
1117 * Record this now as the done functions may free
1118 * the request.
1119 *
1120 * Note: We use p_result here, as that's where the
1121 * result of evaluating the frame was written.
1122 * We don't use the section_result, as that may have
1123 * been left as its default value which may be 0
1124 * (reject).
1125 */
1126 rcode = frame->p_result->rcode;
1127
1128 /*
1129 * This usually means the request is complete in its
1130 * entirety.
1131 */
1132 if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
1133
1134 return rcode;
1135 }
1136}
1137
1139 .self = {
1141 .name = "empty-group",
1142 .debug_name = "empty-group",
1143 .actions = {
1144 .actions = {
1156 },
1157 .retry = RETRY_INIT,
1158 },
1159 },
1160 .children = {
1161 .head = {
1162 .entry = {
1163 .prev = &empty_group.children.head.entry,
1164 .next = &empty_group.children.head.entry,
1165 }
1166 },
1167 },
1168};
1169
1170/** Push a configuration section onto the request stack for later interpretation.
1171 *
1172 */
1174{
1175 unlang_t *instruction = NULL;
1176
1177 /*
1178 * Interpretable unlang instructions are stored as CONF_DATA
1179 * associated with sections.
1180 */
1181 if (cs) {
1182 instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
1183 if (!instruction) {
1184 REDEBUG("Failed to find pre-compiled unlang for section %s ... { ... }",
1185 cf_section_name1(cs));
1186 return -1;
1187 }
1188 }
1189
1190 return unlang_interpret_push_instruction(p_result, request, instruction, conf);
1191}
1192
1193/** Push an instruction onto the request stack for later interpretation.
1194 *
1195 */
1197{
1198 unlang_stack_t *stack = request->stack;
1199
1200 if (!instruction) {
1201 instruction = unlang_group_to_generic(&empty_group);
1202 }
1203
1204 /*
1205 * Push the default action, and the instruction which has
1206 * no action.
1207 */
1208 if (unlang_interpret_push(p_result, request, instruction, conf, UNLANG_NEXT_SIBLING) < 0) {
1209 return -1;
1210 }
1211
1212 RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
1213
1214 return 0;
1215}
1216
1217/** Allocate a new unlang stack
1218 *
1219 * @param[in] ctx to allocate stack in.
1220 * @return
1221 * - A new stack on success.
1222 * - NULL on OOM.
1223 */
1224void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
1225{
1226 /*
1227 * Should never be evaluated, is just here to reduce
1228 * branches, so we don't need to check for frame->instruction.
1229 */
1230 static unlang_t unlang_instruction = {
1231 .debug_name = "top",
1232 .actions = DEFAULT_MOD_ACTIONS,
1233 };
1234
1236
1237 /*
1238 * If we have talloc_pooled_object allocate the
1239 * stack as a combined chunk/pool, with memory
1240 * to hold at mutable data for at least a quarter
1241 * of the maximum number of stack frames.
1242 *
1243 * Having a dedicated pool for mutable stack data
1244 * means we don't have memory fragmentations issues
1245 * as we would if request were used as the pool.
1246 *
1247 * This number is pretty arbitrary, but it seems
1248 * like too low level to make into a tuneable.
1249 */
1250 MEM(stack = talloc_zero_pooled_object(ctx, unlang_stack_t, UNLANG_STACK_MAX, 128)); /* 128 bytes per state */
1251 stack->frame[0].p_result = &stack->frame[0].section_result;
1252 stack->frame[0].scratch_result = UNLANG_RESULT_NOT_SET;
1253 stack->frame[0].section_result = UNLANG_RESULT_NOT_SET;
1254 stack->frame[0].instruction = &unlang_instruction; /* The top frame has no instruction, so we use a dummy one */
1255
1256 return stack;
1257}
1258
1259/** Indicate to the caller of the interpreter that this request is complete
1260 *
1261 */
1263{
1264 unlang_stack_t *stack = request->stack;
1265 unlang_interpret_t *intp;
1266
1267 if (!fr_cond_assert(stack != NULL)) return;
1268
1269 intp = stack->intp;
1270
1271 request->master_state = REQUEST_DONE;
1272 switch (request->type) {
1274 intp->funcs.done_external(request, frame_current(request)->section_result.rcode, intp->uctx);
1275 break;
1276
1278 intp->funcs.done_internal(request, frame_current(request)->section_result.rcode, intp->uctx);
1279 break;
1280
1282 intp->funcs.done_detached(request, frame_current(request)->section_result.rcode, intp->uctx); /* Callback will usually free the request */
1283 break;
1284 }
1285}
1286
1287/** Tell the interpreter to detach the request
1288 *
1289 * This function should not be called directly use unlang_interpret_signal(request, FR_SIGNAL_DETACH) instead.
1290 * This will ensure all frames on the request's stack receive the detach signal.
1291 */
1292static inline CC_HINT(always_inline)
1294{
1295 unlang_stack_t *stack = request->stack;
1296 unlang_interpret_t *intp;
1297
1298 if (!fr_cond_assert(stack != NULL)) return;
1299
1300 if (!request_is_detachable(request)) return;
1301
1302 intp = stack->intp;
1303
1304 intp->funcs.detach(request, intp->uctx);
1305}
1306
1308{
1309 unlang_stack_t *stack = request->stack;
1310 unlang_interpret_t *intp;
1311
1312 if (!fr_cond_assert(stack != NULL)) return;
1313
1314 intp = stack->intp;
1315
1316 request->priority = priority;
1317
1318 if (intp->funcs.prioritise) intp->funcs.prioritise(request, intp->uctx);
1319}
1320
1321/** Cancel any pending retry
1322 *
1323 * @param[in] request The current request.
1324 */
1326{
1327 unlang_stack_t *stack = request->stack;
1328 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1329
1330 TALLOC_FREE(frame->retry);
1331}
1332
1333
1334/** Delivers a frame to one or more frames in the stack
1335 *
1336 * This is typically called via an "async" action, i.e. an action outside
1337 * of the normal processing of the request.
1338 *
1339 * For FR_SIGNAL_CANCEL all frames are marked up for cancellation, but the
1340 * cancellation is handled by the interpret.
1341 *
1342 * Other signal types are delivered immediately, inrrespecitve of whether
1343 * the request is currently being processed or not.
1344 *
1345 * Signaling stops at the "limit" frame. This is so that keywords
1346 * such as "timeout" and "limit" can signal frames *lower* than theirs
1347 * to stop, but then continue with their own work.
1348 *
1349 * @note It's better (clearer) to use one of the unwind_* functions
1350 * unless the entire request is being cancelled.
1351 *
1352 * @param[in] request The current request.
1353 * @param[in] action to signal.
1354 * @param[in] limit the frame at which to stop signaling.
1355 */
1356void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
1357{
1358 unlang_stack_frame_t *frame;
1359 unlang_stack_t *stack = request->stack;
1360 int i, depth = stack->depth;
1361
1362 (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1363
1364 fr_assert(stack->depth >= 1);
1365
1366 /*
1367 * Does not complete the unwinding here, just marks
1368 * up the frames for unwinding. The request must
1369 * be marked as runnable to complete the cancellation.
1370 */
1371 if (action == FR_SIGNAL_CANCEL) unwind_to_depth(stack, limit);
1372
1373 /*
1374 * Walk back up the stack, calling signal handlers
1375 * to cancel any pending operations and free/release
1376 * any resources.
1377 *
1378 * There may be multiple resumption points in the
1379 * stack, as modules can push xlats and function
1380 * calls.
1381 *
1382 * Note: Slightly confusingly, a cancellation signal
1383 * can still be delivered to a frame that is not
1384 * cancellable, but the frame won't be automatically
1385 * unwound.
1386 */
1387 for (i = depth; i >= limit; i--) {
1388 frame = &stack->frame[i];
1389 if (frame->signal) {
1390 frame->signal(request, frame, action);
1391
1392 /*
1393 * Once the cancellation function has been
1394 * called, the frame is no longer in a state
1395 * where it can accept further signals.
1396 */
1397 if (action == FR_SIGNAL_CANCEL) frame->signal = NULL;
1398
1399 /*
1400 * If the frame is cancelled, we don't do any retries.
1401 */
1402 TALLOC_FREE(frame->retry);
1403 }
1404 }
1405}
1406
1407/** Send a signal (usually stop) to a request
1408 *
1409 * This is typically called via an "async" action, i.e. an action
1410 * outside of the normal processing of the request.
1411 *
1412 * @note This does NOT immediately stop the request, it just deliveres
1413 * signals, and in the case of a cancel, marks up frames for unwinding
1414 * and adds it to the runnable queue if it's yielded.
1415 *
1416 * @note This function should be safe to call anywhere.
1417 *
1418 * @param[in] request The current request.
1419 * @param[in] action to signal.
1420 */
1422{
1423 unlang_stack_t *stack = request->stack;
1424
1425 switch (action) {
1426 case FR_SIGNAL_DETACH:
1427 /*
1428 * Ensure the request is able to be detached
1429 * else don't signal.
1430 */
1431 if (!fr_cond_assert(request_is_detachable(request))) return;
1432 break;
1433
1434 default:
1435 break;
1436 }
1437
1438 /*
1439 * Requests that haven't been run through the interpreter
1440 * yet should have a stack depth of zero, so we don't
1441 * need to do anything.
1442 */
1443 if (!stack || stack->depth == 0) return;
1444
1445 unlang_stack_signal(request, action, 1);
1446
1447 switch (action) {
1448 case FR_SIGNAL_CANCEL:
1449 {
1450 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1451 /*
1452 * Let anything that cares, know that the
1453 * request was forcefully stopped.
1454 */
1455 request->master_state = REQUEST_STOP_PROCESSING;
1456
1457 /*
1458 * Give cancelled requests the highest priority
1459 * to get them to release resources ASAP.
1460 */
1461 unlang_interpret_request_prioritise(request, UINT32_MAX);
1462
1463 /*
1464 * If the request is yielded, mark it as runnable
1465 *
1466 * If the request was _not_ cancelled, it means
1467 * it's not cancellable, and we need to let the
1468 * request progress normally.
1469 *
1470 * A concrete example of this, is the parent of
1471 * subrequests, which must not continue until
1472 * the subrequest is done.
1473 */
1474 if (stack && is_yielded(frame) && is_unwinding(frame) && !unlang_request_is_scheduled(request)) {
1476 }
1477 }
1478 break;
1479
1480 case FR_SIGNAL_DETACH:
1481 /*
1482 * Cleanup any cross-request pointers, and mark the
1483 * request as detached. When the request completes it
1484 * should by automatically freed.
1485 */
1487 break;
1488
1489 default:
1490 break;
1491 }
1492}
1493
1495{
1496 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1497 request_t *request = talloc_get_type_abort(retry->request, request_t);
1498
1499 RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1500
1501 /*
1502 * Signal all lower frames to exit.
1503 */
1504 unlang_stack_signal(request, FR_SIGNAL_CANCEL, retry->depth + 1);
1505
1506 retry->state = FR_RETRY_MRD;
1508}
1509
1511{
1512 request_t *request = talloc_get_type_abort(ctx, request_t);
1513
1514 RDEBUG("Maximum timeout reached, signalling interpreter to stop the request.");
1515
1516 /*
1517 * Stop the entire request.
1518 */
1520}
1521
1522
1523/** Set a timeout for a request.
1524 *
1525 * The timeout is associated with the current stack frame.
1526 *
1527 */
1529{
1530 unlang_stack_t *stack = request->stack;
1531 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1532 unlang_retry_t *retry;
1533
1534 fr_assert(!frame->retry);
1536
1537 frame->retry = retry = talloc_zero(stack, unlang_retry_t);
1538 if (!frame->retry) return -1;
1539
1540 retry->request = request;
1541 retry->depth = stack->depth;
1542 retry->state = FR_RETRY_CONTINUE;
1543 retry->count = 1;
1544
1545 return fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, timeout,
1546 false, instruction_timeout_handler, request);
1547}
1548
1549
1550/** Return the depth of the request's stack
1551 *
1552 */
1554{
1555 unlang_stack_t *stack = request->stack;
1556
1557 return stack->depth;
1558}
1559
1560/** Get the last instruction result OR the last frame that was popped
1561 *
1562 * @param[in] request The current request.
1563 * @return the current rcode for the frame.
1564 */
1566{
1567 return frame_current(request)->p_result->rcode;
1568}
1569
1570/** Get the last instruction priority OR the last frame that was popped
1571 *
1572 * @param[in] request The current request.
1573 * @return the current rcode for the frame.
1574 */
1579
1580/** Get the last instruction result OR the last frame that was popped
1581 *
1582 * @param[in] request The current request.
1583 * @return the current result for the frame.
1584 */
1586{
1587 return frame_current(request)->p_result;
1588}
1589
1590/** Return whether a request is currently scheduled
1591 *
1592 */
1594{
1595 unlang_stack_t *stack = request->stack;
1596 unlang_interpret_t *intp = stack->intp;
1597
1598 return intp->funcs.scheduled(request, intp->uctx);
1599}
1600
1601/** Return whether a request has been cancelled
1602 */
1604{
1605 return (request->master_state == REQUEST_STOP_PROCESSING);
1606}
1607
1608/** Return whether a request has been marked done
1609 */
1611{
1612 return (request->master_state == REQUEST_DONE);
1613}
1614
1615/** Check if a request as resumable.
1616 *
1617 * @param[in] request The current request.
1618 * @return
1619 * - true if the request is resumable (i.e. has yielded)
1620 * - false if the request is not resumable (i.e. has not yielded)
1621 */
1623{
1624 unlang_stack_t *stack = request->stack;
1625 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1626
1627 return is_yielded(frame);
1628}
1629
1630/** Mark a request as resumable.
1631 *
1632 * It's not called "unlang_interpret", because it doesn't actually
1633 * resume the request, it just schedules it for resumption.
1634 *
1635 * @note that this schedules the request for resumption. It does not immediately
1636 * start running the request.
1637 *
1638 * @param[in] request The current request.
1639 */
1641{
1642 unlang_stack_t *stack = request->stack;
1643 unlang_interpret_t *intp = stack->intp;
1644 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1645
1646 bool scheduled = unlang_request_is_scheduled(request);
1647
1648 /*
1649 * The request hasn't yielded, OR it's already been
1650 * marked as runnable. Don't do anything.
1651 *
1652 * The IO code, or children have no idea where they're
1653 * being called from. They just ask to mark the parent
1654 * resumable when they're done. So we have to check here
1655 * if this request is resumable.
1656 *
1657 * If the parent called the child directly, then the
1658 * parent hasn't yielded, so it isn't resumable. When
1659 * the child is done, the parent will automatically
1660 * continue running. We therefore don't need to insert
1661 * the parent into the backlog.
1662 *
1663 * Multiple child request may also mark a parent request
1664 * runnable, before the parent request starts running.
1665 */
1666 if (!is_yielded(frame) || scheduled) {
1667 RDEBUG3("Not marking request %s as runnable due to%s%s",
1668 request->name,
1669 !is_yielded(frame) ?
1670 " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
1671 return;
1672 }
1673
1674 RDEBUG3("Interpreter - Request marked as runnable");
1675
1676 intp->funcs.mark_runnable(request, intp->uctx);
1677}
1678
1679/** Get a talloc_ctx which is valid only for this frame
1680 *
1681 * @param[in] request The current request.
1682 * @return
1683 * - a TALLOC_CTX which is valid only for this stack frame
1684 */
1686{
1687 unlang_stack_t *stack = request->stack;
1688 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1689
1690 if (frame->state) return (TALLOC_CTX *)frame->state;
1691
1692 /*
1693 * If the frame doesn't ordinarily have a
1694 * state, assume the caller knows what it's
1695 * doing and allocate one.
1696 */
1697 return (TALLOC_CTX *)(frame->state = talloc_new(stack));
1698}
1699
1701 { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
1703};
1704
1705static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
1706 UNUSED xlat_ctx_t const *xctx,
1707 request_t *request, fr_value_box_list_t *args);
1708
1709/** Signal the request to stop executing
1710 *
1711 * The request can't be running at this point because we're in the event
1712 * loop. This means the request is always in a consistent state when
1713 * the timeout event fires, even if that's state is waiting on I/O.
1714 */
1716{
1717 request_t *request = talloc_get_type_abort(uctx, request_t);
1718
1719 RDEBUG2("Request canceled by dynamic timeout");
1720 /*
1721 * Cleans up the memory allocated to hold
1722 * the pointer, not the event itself.
1723 */
1724 talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
1725
1727}
1728
1729/** Allows a request to dynamically alter its own lifetime
1730 *
1731 * %cancel(<timeout>)
1732 *
1733 * If timeout is 0, then the request is immediately cancelled.
1734 */
1736 UNUSED xlat_ctx_t const *xctx,
1737 request_t *request, fr_value_box_list_t *args)
1738{
1739 fr_value_box_t *timeout;
1741 fr_timer_t **ev_p, **ev_p_og;
1742 fr_value_box_t *vb;
1743 fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
1744
1745 fr_assert(el != NULL);
1746
1747 XLAT_ARGS(args, &timeout);
1748
1749 /*
1750 * No timeout means cancel immediately, so yield allowing
1751 * the interpreter to run the event we added to cancel
1752 * the request.
1753 *
1754 * We call unlang_xlat_yield to keep the interpreter happy
1755 * as it expects to see a resume function set.
1756 */
1757 if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
1759 return XLAT_ACTION_DONE;
1760 }
1761
1762 /*
1763 * First see if we already have a timeout event
1764 * that was previously added by this xlat.
1765 */
1766 ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
1767 if (ev_p) {
1768 fr_assert(*ev_p);
1769
1770 when = fr_timer_when(*ev_p);
1771 } else {
1772 /*
1773 * Must not be parented from the request
1774 * as this is freed by request data.
1775 */
1776 MEM(ev_p = talloc_zero(NULL, fr_timer_t *));
1777 }
1778
1779 if (unlikely(fr_timer_in(ev_p, el->tl, ev_p,
1780 timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
1781 false, unlang_cancel_event, request) < 0)) {
1782 RPERROR("Failed inserting cancellation event");
1783 talloc_free(ev_p);
1784 return XLAT_ACTION_FAIL;
1785 }
1786 if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
1787 UNCONST(fr_timer_t **, ev_p), true, true, false) < 0)) {
1788 RPERROR("Failed associating cancellation event with request");
1789 talloc_free(ev_p);
1790 return XLAT_ACTION_FAIL;
1791 }
1792
1793 if (ev_p_og) {
1794 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
1795
1796 /*
1797 * Return how long before the previous
1798 * cancel event would have fired.
1799 *
1800 * This can be useful for doing stacked
1801 * cancellations in policy.
1802 */
1803 vb->vb_time_delta = fr_time_sub(when, unlang_interpret_event_list(request)->tl->time());
1805 }
1806
1807 /*
1808 * No value if this is the first cleanup event
1809 */
1810 return XLAT_ACTION_DONE;
1811}
1812
1814 { .required = true, .single = true, .type = FR_TYPE_STRING },
1816};
1817
1818/** Get information about the interpreter state
1819 *
1820 * @ingroup xlat_functions
1821 */
1823 UNUSED xlat_ctx_t const *xctx,
1824 request_t *request, fr_value_box_list_t *in)
1825{
1826 unlang_stack_t *stack = request->stack;
1827 int depth = stack->depth;
1828 unlang_stack_frame_t *frame;
1829 unlang_t const *instruction;
1830 fr_value_box_t *arg = fr_value_box_list_head(in);
1831 char const *fmt = arg->vb_strvalue;
1832 fr_value_box_t *vb;
1833
1834 MEM(vb = fr_value_box_alloc_null(ctx));
1835
1836 /*
1837 * Find the correct stack frame.
1838 */
1839 while (*fmt == '.') {
1840 if (depth <= 1) {
1841 if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
1842 error:
1843 talloc_free(vb);
1844 return XLAT_ACTION_FAIL;
1845 }
1846 goto finish;
1847 }
1848
1849 fmt++;
1850 depth--;
1851 }
1852
1853 /*
1854 * Get the current instruction.
1855 */
1856 frame = &stack->frame[depth];
1857 instruction = frame->instruction;
1858
1859 /*
1860 * Nothing there...
1861 */
1862 if (!instruction) goto clear;
1863
1864 /*
1865 * How deep the current stack is.
1866 */
1867 if (strcmp(fmt, "depth") == 0) {
1868 fr_value_box_int32(vb, NULL, depth, false);
1869 goto finish;
1870 }
1871
1872 /*
1873 * The current module
1874 */
1875 if (strcmp(fmt, "module") == 0) {
1876 if (!request->module) goto clear;
1877
1878 if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
1879
1880 goto finish;
1881 }
1882
1883 /*
1884 * Name of the instruction.
1885 */
1886 if (strcmp(fmt, "name") == 0) {
1887 if (!instruction->name) goto clear;
1888
1889 if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
1890 strlen(instruction->name), false) < 0) goto error;
1891 goto finish;
1892 }
1893
1894 /*
1895 * The request processing stage.
1896 */
1897 if (strcmp(fmt, "processing_stage") == 0) {
1898 if (!request->component) goto clear;
1899
1900 if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
1901
1902 goto finish;
1903 }
1904
1905 /*
1906 * The current return code.
1907 */
1908 if (strcmp(fmt, "rcode") == 0) {
1909 if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
1910
1911 goto finish;
1912 }
1913
1914 /*
1915 * The virtual server handling the request
1916 */
1917 if (strcmp(fmt, "server") == 0) {
1918 request_t *our_request;
1919 CONF_SECTION *server = NULL;
1920
1921 /*
1922 * If we're being pedantic subrequests don't have a virtual
1923 * server associated with them unless they go call {}.
1924 *
1925 * But we're not being pendantic, so go back up the request
1926 * list ooking for a call frame.
1927 *
1928 * Unfortunately for detached subrequests we still won't find
1929 * the actual virtual server...
1930 */
1931 for (our_request = request; our_request && server == NULL; our_request = our_request->parent) {
1932 server = unlang_call_current(our_request);
1933 }
1934 if (server == NULL) goto finish;
1935
1936 if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(server), false) < 0) goto error;
1937
1938 goto finish;
1939 }
1940
1941 /*
1942 * Unlang instruction type.
1943 */
1944 if (strcmp(fmt, "type") == 0) {
1945 if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
1946 strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
1947
1948 goto finish;
1949 }
1950
1951 /*
1952 * All of the remaining things need a CONF_ITEM.
1953 */
1954 if (!instruction->ci) {
1955 if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 9, false) < 0) goto error;
1956
1957 goto finish;
1958 }
1959
1960 /*
1961 * Line number of the current section.
1962 */
1963 if (strcmp(fmt, "line") == 0) {
1964 fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
1965
1966 goto finish;
1967 }
1968
1969 /*
1970 * Filename of the current section.
1971 */
1972 if (strcmp(fmt, "filename") == 0) {
1973 if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
1974
1975 goto finish;
1976 }
1977
1978finish:
1979 if (vb->type != FR_TYPE_NULL) {
1981 } else {
1982 clear:
1983 talloc_free(vb);
1984 }
1985
1986 return XLAT_ACTION_DONE;
1987}
1988
1989/** Initialize a unlang compiler / interpret.
1990 *
1991 * @param[in] ctx to bind lifetime of the interpret to.
1992 * Shouldn't be any free order issues here as
1993 * the interpret itself has no state.
1994 * But event loop should be stopped before
1995 * freeing the interpret.
1996 * @param[in] el for any timer or I/O events.
1997 * @param[in] funcs Callbacks to used to communicate request
1998 * state to our owner.
1999 * @param[in] uctx Data to pass to callbacks.
2000 */
2002 fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
2003{
2004 unlang_interpret_t *intp;
2005
2006 fr_assert(funcs->init_internal);
2007
2008 fr_assert(funcs->done_internal);
2009 fr_assert(funcs->done_detached);
2010 fr_assert(funcs->done_external);
2011
2012 fr_assert(funcs->detach);
2013 fr_assert(funcs->yield);
2014 fr_assert(funcs->resume);
2015 fr_assert(funcs->mark_runnable);
2016 fr_assert(funcs->scheduled);
2017
2018 MEM(intp = talloc(ctx, unlang_interpret_t));
2019 *intp = (unlang_interpret_t){
2020 .el = el,
2021 .funcs = *funcs,
2022 .uctx = uctx
2023 };
2024
2025 return intp;
2026}
2027
2028/** Discard the bottom most frame on the request's stack
2029 *
2030 * This is used for cleaning up after errors. i.e. the caller
2031 * uses a push function, and experiences an error and needs to
2032 * remove the frame that was just pushed.
2033 */
2035{
2036 frame_pop(request, request->stack);
2037}
2038
2039/** Set a specific interpreter for a request
2040 *
2041 */
2043{
2044 unlang_stack_t *stack = request->stack;
2045 stack->intp = intp;
2046}
2047
2048/** Get the interpreter set for a request
2049 *
2050 */
2052{
2053 unlang_stack_t *stack = request->stack;
2054
2055 return stack->intp;
2056}
2057
2058/** Get the event list for the current interpreter
2059 *
2060 */
2062{
2063 unlang_stack_t *stack = request->stack;
2064
2065 if (!stack->intp) return NULL;
2066
2067 return stack->intp->el;
2068}
2069
2070/** Set the default interpreter for this thread
2071 *
2072 */
2074{
2075 if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
2076
2077 intp_thread_default = intp;
2078}
2079
2080/** Get the default interpreter for this thread
2081 *
2082 * This allows detached requests to be executed asynchronously
2083 */
2085{
2086 if (!intp_thread_default) return NULL;
2087
2088 return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
2089}
2090
2092{
2093 xlat_t *xlat;
2094 /*
2095 * Should be void, but someone decided not to register multiple xlats
2096 * breaking the convention we use everywhere else in the server...
2097 */
2098 if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2100
2101 if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2103
2104 return 0;
2105}
#define RETURN_UNLANG_ACTION_FATAL
Definition action.h:44
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_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:186
#define RCSID(id)
Definition build.h:506
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:343
#define unlikely(_x)
Definition build.h:402
#define UNUSED
Definition build.h:336
#define NUM_ELEMENTS(_t)
Definition build.h:358
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition call.c:214
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:1187
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1750
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1173
#define cf_lineno(_cf)
Definition cf_util.h:101
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:240
#define cf_filename(_cf)
Definition cf_util.h:104
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:74
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:141
#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:212
#define MEM(x)
Definition debug.h:46
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static fr_slen_t in
Definition dict.h:882
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:1822
talloc_free(hp)
void unlang_interpret_request_prioritise(request_t *request, uint32_t priority)
Definition interpret.c:1307
static size_t unlang_action_table_len
Definition interpret.c:50
void stack_dump_with_actions(request_t *request)
Definition interpret.c:251
static fr_table_num_ordered_t const unlang_frame_action_table[]
Definition interpret.c:52
static void unlang_interpret_request_detach(request_t *request)
Tell the interpreter to detach the request.
Definition interpret.c:1293
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:940
bool unlang_request_is_done(request_t const *request)
Return whether a request has been marked done.
Definition interpret.c:1610
static void stack_dump_body(request_t *request, bool with_actions)
Definition interpret.c:231
static unlang_group_t empty_group
Definition interpret.c:1138
unlang_result_t * unlang_interpret_result(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1585
static int find_p_result_location(p_result_location_t *location, void **chunk, request_t *request, void *ptr)
Try and figure out where p_result points to.
Definition interpret.c:75
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:2034
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1528
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1262
static unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame)
Evaluates all the unlang nodes in a section.
Definition interpret.c:731
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:2042
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:2051
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1553
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1640
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition interpret.c:1813
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1685
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1593
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition interpret.c:2091
void stack_dump(request_t *request)
Definition interpret.c:246
p_result_location_t
Definition interpret.c:62
@ P_RESULT_LOCATION_FRAME
Definition interpret.c:64
@ P_RESULT_LOCATION_FUNCTION_RCTX
Definition interpret.c:68
@ P_RESULT_LOCATION_UNKNOWN
Definition interpret.c:63
@ P_RESULT_LOCATION_SCRATCH
Definition interpret.c:65
@ P_RESULT_LOCATION_MODULE_RCTX
Definition interpret.c:67
@ P_RESULT_LOCATION_STATE
Definition interpret.c:66
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:2084
fr_dict_t const * old_dict
the previous dictionary for the request
Definition interpret.c:339
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition interpret.c:1224
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition interpret.c:2073
static fr_table_num_ordered_t const p_result_location_table[]
Definition interpret.c:135
#define DUMP_STACK
Definition interpret.c:255
unlang_mod_action_t unlang_interpret_priority(request_t *request)
Get the last instruction priority OR the last frame that was popped.
Definition interpret.c:1575
static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1494
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:2001
static void instruction_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1510
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition interpret.c:1603
int unlang_interpret_push_instruction(unlang_result_t *p_result, request_t *request, void *instruction, unlang_frame_conf_t const *conf)
Push an instruction onto the request stack for later interpretation.
Definition interpret.c:1196
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:1715
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1421
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition interpret.c:1700
int unlang_interpret_push_section(unlang_result_t *p_result, request_t *request, CONF_SECTION *cs, unlang_frame_conf_t const *conf)
Push a configuration section onto the request stack for later interpretation.
Definition interpret.c:1173
static unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t *frame, unlang_result_t *result)
Update the current result after each instruction, and after popping each stack frame.
Definition interpret.c:447
static fr_table_num_ordered_t const unlang_action_table[]
Definition interpret.c:43
static int _local_variables_free(unlang_variable_ref_t *ref)
Definition interpret.c:343
static size_t p_result_location_table_len
Definition interpret.c:142
static void instruction_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:144
bool unlang_interpret_is_resumable(request_t *request)
Check if a request as resumable.
Definition interpret.c:1622
int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
Push a new frame onto the stack.
Definition interpret.c:278
static void instruction_done_debug(request_t *request, unlang_stack_frame_t *frame, unlang_t const *instruction)
Definition interpret.c:687
request_t * request
the request
Definition interpret.c:340
void unlang_interpret_request_cancel_retry(request_t *request)
Cancel any pending retry.
Definition interpret.c:1325
static unlang_frame_action_t result_pop(request_t *request, unlang_stack_frame_t *frame, unlang_result_t *result)
Function called to merge inter-stack-frame results.
Definition interpret.c:657
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:1356
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:1735
static size_t unlang_frame_action_table_len
Definition interpret.c:57
rlm_rcode_t unlang_interpret_rcode(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1565
static void frame_dump(request_t *request, unlang_stack_frame_t *frame, bool with_actions)
Definition interpret.c:173
unlang_action_t unlang_interpret_push_children(unlang_result_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:381
static void actions_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:159
static _Thread_local unlang_interpret_t * intp_thread_default
The default interpreter instance for this thread.
Definition interpret.c:41
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2061
unlang_result_t default_result
The default result for the frame.
Definition interpret.h:146
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:39
unlang_request_prioritise_t prioritise
Function to re-prioritise a request in the runnable queue.
Definition interpret.h:129
unlang_mod_action_t priority
The priority or action for that rcode.
Definition interpret.h:136
#define UNLANG_RESULT_NOT_SET
Definition interpret.h:139
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:152
unlang_request_done_t done_internal
Function called when an internal request completes.
Definition interpret.h:119
unlang_request_resume_t resume
Function called when a request is resumed.
Definition interpret.h:124
#define UNLANG_SUB_FRAME
Definition interpret.h:37
unlang_request_done_t done_external
Function called when a external request completes.
Definition interpret.h:118
unlang_request_init_t detach
Function called when a request is detached.
Definition interpret.h:122
unlang_request_runnable_t mark_runnable
Function called when a request needs to be added back to the runnable queue.
Definition interpret.h:125
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:134
unlang_request_yield_t yield
Function called when a request yields.
Definition interpret.h:123
unlang_request_done_t done_detached
Function called when a detached request completes.
Definition interpret.h:120
unlang_request_scheduled_t scheduled
Function to check if a request is already scheduled.
Definition interpret.h:127
#define UNLANG_RESULT_RCODE(_x)
Definition interpret.h:140
unlang_request_init_t init_internal
Function called to initialise an internal request.
Definition interpret.h:116
struct unlang_interpret_s unlang_interpret_t
Interpreter handle.
Definition interpret.h:48
Configuration structure to make it easier to pass configuration options to initialise the frame with.
Definition interpret.h:144
External functions provided by the owner of the interpret.
Definition interpret.h:110
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:455
#define DEBUG_ENABLED5
True if global debug level 1-5 messages are enabled.
Definition log.h:261
#define RDEBUG3(fmt,...)
Definition log.h:355
#define RERROR(fmt,...)
Definition log.h:310
#define DEBUG4(_fmt,...)
Definition log.h:267
#define RPERROR(fmt,...)
Definition log.h:314
#define RPEDEBUG(fmt,...)
Definition log.h:388
#define RDEBUG4(fmt,...)
Definition log.h:356
#define RINDENT()
Indent R* messages by one level.
Definition log.h:442
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
Definition base.c:31
Stores all information relating to an event list.
Definition event.c:377
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 int uint32_t
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
const char * mod_action_name[MOD_PRIORITY_MAX+1]
Definition mod_action.c:112
#define DEFAULT_MOD_ACTIONS
Definition mod_action.h:73
unlang_mod_action_t
Definition mod_action.h:37
@ MOD_ACTION_NOT_SET
default "not set by anything"
Definition mod_action.h:38
@ MOD_ACTION_RETURN
stop processing the section, and return the rcode with unset priority
Definition mod_action.h:41
@ MOD_ACTION_REJECT
change the rcode to REJECT, with unset priority
Definition mod_action.h:40
@ MOD_ACTION_RETRY
retry the instruction, MUST also set a retry config
Definition mod_action.h:39
#define MOD_ACTION_VALID(_x)
Definition mod_action.h:65
fr_retry_config_t retry
Definition mod_action.h:70
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:69
Declarations for the unlang module interface.
void * rctx
for resume / signal
Definition module_priv.h:63
A module stack entry.
Definition module_priv.h:45
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:1833
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG_ENABLED2()
#define RDEBUG2(fmt,...)
#define RDEBUG(fmt,...)
#define RDEBUG_ENABLED()
static rs_t * conf
Definition radsniff.c:52
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:44
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:48
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:47
@ RLM_MODULE_TIMEOUT
Module (or section) timed out.
Definition rcode.h:56
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:45
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:57
#define REQUEST_VERIFY(_x)
Definition request.h:309
@ 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_aka_sim_id_type_t type
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:201
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:49
A timer event.
Definition timer.c:83
#define fr_timer_in(...)
Definition timer.h:87
static fr_event_list_t * el
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
unsigned int required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
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 consumed by an xlat function.
Definition xlat.h:145
Private interpreter structures and functions.
fr_retry_state_t state
#define unlang_frame_perf_resume(_x)
unlang_result_t section_result
The aggregate result of executing all siblings in this section.
static void frame_pop(request_t *request, unlang_stack_t *stack)
Pop a stack frame, removing any associated dynamically allocated state.
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:99
unlang_result_t * p_result
Where to write the result of executing the current instruction.
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)
Initialise memory and instruction for a frame when a new instruction is to be evaluated.
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.
unlang_result_t scratch_result
The result of executing the current instruction.
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)
static unlang_stack_frame_t * frame_current(request_t *request)
unlang_list_t children
static bool is_private_result(unlang_stack_frame_t const *frame)
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:51
@ UNLANG_TYPE_MODULE
Module method.
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
char const * name
Name of the keyword.
unlang_frame_action_t
Allows the frame evaluator to signal the interpreter.
Definition unlang_priv.h:89
@ 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:90
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
Definition unlang_priv.h:94
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
Definition unlang_priv.h:93
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
Definition unlang_priv.h:92
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_frame_flag_t flag
Flags that mark up the frame for various things such as being the point where break,...
unlang_list_t * list
so we have fewer run-time dereferences
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:4604
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:4823
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:644
int nonnull(2, 5))
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:655
static size_t char ** out
Definition value.h:1030
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