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: 4a03492c1d7aa0aa511b259a93b87ebd460cf408 $
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: 4a03492c1d7aa0aa511b259a93b87ebd460cf408 $")
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 * Start of thread-local variables and functions.
40 */
41
42/** The default interpreter instance for this thread
43 */
45
46/*
47 * For simplicity, this is just array[unlang_number]. Once we
48 * call unlang_thread_instantiate(), the "unlang_number" above MUST
49 * NOT change.
50 */
52
53extern uint64_t unlang_number;
54uint64_t unlang_number = 1;
55
57
58static char const unlang_spaces[] = " ";
59
60/** Create thread-specific data structures for unlang
61 *
62 */
63int unlang_thread_instantiate(TALLOC_CTX *ctx)
64{
66 unlang_t *instruction;
67
69 fr_strerror_const("already initialized");
70 return -1;
71 }
72
73 MEM(unlang_thread_array = talloc_zero_array(ctx, unlang_thread_t, unlang_number + 1));
74// talloc_set_destructor(unlang_thread_array, _unlang_thread_array_free);
75
76 /*
77 * Instantiate each instruction with thread-specific data.
78 */
79 for (instruction = fr_rb_iter_init_inorder(unlang_instruction_tree, &iter);
80 instruction;
82 unlang_op_t *op;
83
84 unlang_thread_array[instruction->number].instruction = instruction;
85
86 op = &unlang_ops[instruction->type];
87
88 if (!op->thread_inst_size) continue;
89
90 /*
91 * Allocate any thread-specific instance data.
92 */
94 talloc_set_name_const(unlang_thread_array[instruction->number].thread_inst, op->thread_inst_type);
95
96 if (op->thread_instantiate && (op->thread_instantiate(instruction, unlang_thread_array[instruction->number].thread_inst) < 0)) {
97 TALLOC_FREE(unlang_thread_array);
98 return -1;
99 }
100 }
101
102 return 0;
103}
104
105/** Get the thread-instance data for an instruction.
106 *
107 * @param[in] instruction the instruction to use
108 * @return a pointer to thread-local data
109 */
110void *unlang_thread_instance(unlang_t const *instruction)
111{
112 if (!instruction->number || !unlang_thread_array) return NULL;
113
114 fr_assert(instruction->number <= unlang_number);
115
116 return unlang_thread_array[instruction->number].thread_inst;
117}
118
119/** Get the thread-instance data for an instruction.
120 *
121 * @param[in] instruction the instruction to use
122 * @return a pointer to thread-local data
123 */
124static inline unlang_thread_t *unlang_thread_data(unlang_t const *instruction)
125{
126 if (!instruction->number) return NULL;
127
129 fr_assert(instruction->number <= unlang_number);
130
131 return &unlang_thread_array[instruction->number];
132}
133
134
135#ifdef WITH_PERF
137{
139 fr_time_t now;
140 unlang_t const *instruction = frame->instruction;
141
142 if (!instruction->number || !unlang_thread_array) return;
143
144 fr_assert(instruction->number <= unlang_number);
145
146 t = &unlang_thread_array[instruction->number];
147
148 t->use_count++;
149 t->yielded++; // everything starts off as yielded
150 now = fr_time();
151
152 fr_time_tracking_start(NULL, &frame->tracking, now);
153 fr_time_tracking_yield(&frame->tracking, now);
154}
155
157{
158 unlang_t const *instruction = frame->instruction;
160
161 if (!instruction->number || !unlang_thread_array) return;
162
163 t = &unlang_thread_array[instruction->number];
164 t->yielded++;
165 t->running--;
166
167 fr_time_tracking_yield(&frame->tracking, fr_time());
168}
169
171{
172 unlang_t const *instruction = frame->instruction;
174
175 if (!instruction->number || !unlang_thread_array) return;
176
177 if (frame->tracking.state != FR_TIME_TRACKING_YIELDED) return;
178
179 t = &unlang_thread_array[instruction->number];
180 t->running++;
181 t->yielded--;
182
183 fr_time_tracking_resume(&frame->tracking, fr_time());
184}
185
187{
188 unlang_t const *instruction = frame->instruction;
190
191 if (!instruction || !instruction->number || !unlang_thread_array) return;
192
193 fr_assert(instruction->number <= unlang_number);
194
195 t = &unlang_thread_array[instruction->number];
196
197 if (frame->tracking.state == FR_TIME_TRACKING_YIELDED) {
198 t->yielded--;
199 fr_time_tracking_resume(&frame->tracking, fr_time());
200 } else {
201 t->running--;
202 }
203
204 fr_time_tracking_end(NULL, &frame->tracking, fr_time());
205 t->tracking.running_total = fr_time_delta_add(t->tracking.running_total, frame->tracking.running_total);
206 t->tracking.waiting_total = fr_time_delta_add(t->tracking.waiting_total, frame->tracking.waiting_total);
207}
208
209
210static void unlang_perf_dump(fr_log_t *log, unlang_t const *instruction, int depth)
211{
212 unlang_group_t const *g;
214 char const *file;
215 int line;
216
217 if (!instruction || !instruction->number) return;
218
219 /*
220 * Ignore any non-group instruction.
221 */
222 if (!((instruction->type > UNLANG_TYPE_MODULE) && (instruction->type <= UNLANG_TYPE_POLICY))) return;
223
224 /*
225 * Everything else is an unlang_group_t;
226 */
227 g = unlang_generic_to_group(instruction);
228
229 if (!g->cs) return;
230
231 file = cf_filename(g->cs);
232 line = cf_lineno(g->cs);
233
234 if (depth) {
235 fr_log(log, L_DBG, file, line, "%.*s", depth, unlang_spaces);
236 }
237
238 if (debug_braces(instruction->type)) {
239 fr_log(log, L_DBG, file, line, "%s { #", instruction->debug_name);
240 } else {
241 fr_log(log, L_DBG, file, line, "%s #", instruction->debug_name);
242 }
243
244 t = &unlang_thread_array[instruction->number];
245
246 fr_log(log, L_DBG, file, line, "count=%" PRIu64 " cpu_time=%" PRId64 " yielded_time=%" PRId64 ,
247 t->use_count, fr_time_delta_unwrap(t->tracking.running_total), fr_time_delta_unwrap(t->tracking.waiting_total));
248
249 if (!unlang_list_empty(&g->children)) {
250 unlang_list_foreach(&g->children, child) {
251 unlang_perf_dump(log, child, depth + 1);
252 }
253 }
254
255 if (debug_braces(instruction->type)) {
256 if (depth) {
257 fr_log(log, L_DBG, file, line, "%.*s", depth, unlang_spaces);
258 }
259
260 fr_log(log, L_DBG, file, line, "}");
261 }
262}
263
264void unlang_perf_virtual_server(fr_log_t *log, char const *name)
265{
266
268 CONF_SECTION *cs;
269 CONF_ITEM *ci;
270 char const *file;
271 int line;
272
273 if (!vs) return;
274
275 cs = virtual_server_cs(vs);
276
277 file = cf_filename(cs);
278 line = cf_lineno(cs);
279
280 fr_log(log, L_DBG, file, line, " server %s {\n", name);
281
282 /*
283 * Loop over the children of the virtual server, checking for unlang_t;
284 */
285 for (ci = cf_item_next(cs, NULL);
286 ci != NULL;
287 ci = cf_item_next(cs, ci)) {
288 char const *name1, *name2;
289 unlang_t *instruction;
290 CONF_SECTION *subcs;
291
292 if (!cf_item_is_section(ci)) continue;
293
294 instruction = (unlang_t *)cf_data_value(cf_data_find(ci, unlang_group_t, NULL));
295 if (!instruction) continue;
296
297 subcs = cf_item_to_section(ci);
298 name1 = cf_section_name1(subcs);
299 name2 = cf_section_name2(subcs);
300 file = cf_filename(ci);
301 line = cf_lineno(ci);
302
303 if (!name2) {
304 fr_log(log, L_DBG, file, line, " %s {\n", name1);
305 } else {
306 fr_log(log, L_DBG, file, line, " %s %s {\n", name1, name2);
307 }
308
309 unlang_perf_dump(log, instruction, 2);
310
311 fr_log(log, L_DBG, file, line, " }\n");
312 }
313
314 fr_log(log, L_DBG, file, line, "}\n");
315}
316#endif
317
318/** Get the current instruction
319 *
320 */
322{
323 unlang_stack_t *stack = request->stack;
325
326 frame = &stack->frame[stack->depth];
327 fr_assert(frame->instruction != NULL);
328
329 return frame->instruction;
330}
331
333{
334 unlang_thread_t *thread_data = ctx;
335
336 thread_data->use_forced_result = false;
337}
338
339/** Set (or clear) a forced result
340 *
341 * If timer list is passed, and a future expiry time, the function
342 * will set a timer that removes the forced result at that time.
343 */
346{
347 unlang_thread_t *thread_data;
348
349 thread_data = unlang_thread_data(instruction);
350 if (!thread_data) return -1;
351
352 if (!p_result) {
353 thread_data->use_forced_result = false;
354 if (thread_data->ev) (void) fr_timer_delete(&thread_data->ev);
355 return 0;
356 }
357
358 if (tl && fr_time_delta_ispos(expire)) {
359 if (fr_timer_in(tl, tl, &thread_data->ev, expire,
360 false, forced_result_expiry_handler, thread_data) < 0) {
361 return -1;
362 }
363 } else {
364 /*
365 * Delete any previous expiry timers.
366 */
367 if (thread_data->ev) (void) fr_timer_delete(&thread_data->ev);
368 }
369
370 thread_data->use_forced_result = true;
371 thread_data->forced_result = *p_result;
372 return 0;
373}
374
375/*
376 * End of thread-local variables and functions.
377 *
378 */
379
380
382 { L("fail"), UNLANG_ACTION_FAIL },
383 { L("calculate-result"), UNLANG_ACTION_CALCULATE_RESULT },
384 { L("next"), UNLANG_ACTION_EXECUTE_NEXT },
385 { L("pushed-child"), UNLANG_ACTION_PUSHED_CHILD },
386 { L("yield"), UNLANG_ACTION_YIELD }
387};
389
391 { L("pop"), UNLANG_FRAME_ACTION_POP },
392 { L("next"), UNLANG_FRAME_ACTION_NEXT },
393 { L("yield"), UNLANG_FRAME_ACTION_YIELD }
394};
396
397#ifndef NDEBUG
398#include <freeradius-devel/unlang/module_priv.h>
399
408
409/** Try and figure out where p_result points to
410 *
411 * If it's somewhere other than these three locations, it's probably wrong.
412 */
413static int find_p_result_location(p_result_location_t *location, void **chunk, request_t *request, void *ptr)
414{
415 unlang_stack_t *stack = request->stack;
417 unsigned int i;
418
419 for (i = 0; i <= (unsigned int)stack->depth; i++) {
420 frame = &stack->frame[i];
421 if (frame->state && (ptr >= (void *)frame->state) &&
422 (ptr < ((void *)((uint8_t *)frame->state + talloc_get_size(frame->state))))) {
423 *location = P_RESULT_LOCATION_STATE;
424 *chunk = frame->state;
425 return i;
426 }
427
428 if (ptr == &frame->section_result) {
429 *location = P_RESULT_LOCATION_FRAME;
430 *chunk = NULL;
431 return i;
432 }
433
434 if (ptr == &frame->scratch_result) {
435 *location = P_RESULT_LOCATION_SCRATCH;
436 *chunk = NULL;
437 return i;
438 }
439
440 if (!frame->instruction) continue;
441
442 switch (frame->instruction->type) {
444 {
445 unlang_frame_state_module_t *mod_state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
446
447 if (!mod_state->rctx) continue;
448
449 if ((ptr >= (void *)mod_state->rctx) &&
450 (ptr < ((void *)((uint8_t *)mod_state->rctx + talloc_get_size(mod_state->rctx))))) {
452 *chunk = mod_state->rctx;
453 return i;
454 }
455
456 /*
457 * We don't know where the child frame is, so we can't
458 * determine where the p_result is.
459 */
460 }
461 continue;
462
463 default:
464 break;
465 }
466 }
467
468 *location = P_RESULT_LOCATION_UNKNOWN;
469 *chunk = NULL;
470 return -1;
471}
472
474 { L("frame"), P_RESULT_LOCATION_FRAME },
475 { L("module_rctx"), P_RESULT_LOCATION_MODULE_RCTX },
476 { L("scratch"), P_RESULT_LOCATION_SCRATCH },
477 { L("state"), P_RESULT_LOCATION_STATE },
478 { L("unknown"), P_RESULT_LOCATION_UNKNOWN }
479};
481
482static void instruction_dump(request_t *request, unlang_t const *instruction)
483{
484 RINDENT();
485 if (!instruction) {
486 RDEBUG2("instruction <none>");
487 REXDENT();
488 return;
489 }
490
491 RDEBUG2("type %s", unlang_ops[instruction->type].name);
492 RDEBUG2("name %s", instruction->name);
493 RDEBUG2("debug_name %s", instruction->debug_name);
494 REXDENT();
495}
496
497static void CC_HINT(nonnull) actions_dump(request_t *request, unlang_t const *instruction)
498{
499 int i;
500
501 RDEBUG2("actions");
502 RINDENT();
503 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
504 RDEBUG2("%s: %s",
505 fr_table_str_by_value(mod_rcode_table, i, "<invalid>"),
506 mod_action_name[instruction->actions.actions[i]]);
507 }
508 REXDENT();
509}
510
511static void frame_dump(request_t *request, unlang_stack_frame_t *frame, bool with_actions)
512{
513 unlang_op_t *op = NULL;
514
515 if (frame->instruction) {
516 op = &unlang_ops[frame->instruction->type];
517 instruction_dump(request, frame->instruction);
518 }
519
520 RINDENT();
521 if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
522 if (frame->next) {
523 RDEBUG2("next %s", frame->next->debug_name);
524 } else {
525 RDEBUG2("next <none>");
526 }
527
529
530 if (is_private_result(frame)) {
531 int location;
533 void *chunk;
534
535 RDEBUG2("p_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"));
536 RDEBUG2("p_priority %s", mod_action_name[frame->p_result->priority]);
537
538 location = find_p_result_location(&type, &chunk, request, frame->p_result);
539 RDEBUG2("p_location %s [%i] %p (%s)", fr_table_str_by_value(p_result_location_table, type, "<invalid>"),
540 location, frame->p_result, chunk ? talloc_get_name(chunk) : "<none>"
541 );
542 } else {
543 RDEBUG2("sec_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->section_result.rcode, "<invalid>"));
544 RDEBUG2("sec_priority %s", mod_action_name[frame->section_result.priority]);
545 }
546 RDEBUG2("scr_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->scratch_result.rcode, "<invalid>"));
547 RDEBUG2("scr_priority %s", mod_action_name[frame->scratch_result.priority]);
548 RDEBUG2("top_frame %s", is_top_frame(frame) ? "yes" : "no");
549 RDEBUG2("repeat %s", is_repeatable(frame) ? "yes" : "no");
550 RDEBUG2("yielded %s", is_yielded(frame) ? "yes" : "no");
551 RDEBUG2("unwind %s", is_unwinding(frame) ? "yes" : "no");
552
553 if (frame->instruction) {
554 RDEBUG2("control %s%s%s",
555 is_break_point(frame) ? "b" : "-",
556 is_return_point(frame) ? "r" : "-",
557 is_continue_point(frame) ? "c" : "-"
558 );
559 if (with_actions) actions_dump(request, frame->instruction);
560 }
561
562 /*
563 * Call the custom frame dump function
564 */
565 if (op && op->dump) op->dump(request, frame);
566 REXDENT();
567}
568
569static void stack_dump_body(request_t *request, bool with_actions)
570{
571 int i;
572 unlang_stack_t *stack = request->stack;
573
574 RDEBUG2("----- Begin stack debug [depth %i] -----",
575 stack->depth);
576 for (i = stack->depth; i >= 0; i--) {
577 unlang_stack_frame_t *frame = &stack->frame[i];
578 RDEBUG2("[%d] Frame contents", i);
579 frame_dump(request, frame, with_actions);
580 }
581 RDEBUG2("----- End stack debug [depth %i] -------", stack->depth);
582}
583
584void stack_dump(request_t *request)
585{
586 stack_dump_body(request, false);
587}
588
590{
591 stack_dump_body(request, true);
592}
593#define DUMP_STACK if (DEBUG_ENABLED5) stack_dump(request)
594#else
595#define DUMP_STACK
596#endif
597
598/** Push a new frame onto the stack
599 *
600 * @param[in] p_result Where to write the result of evaluating the section.
601 * If NULL, results will be written to frame->section_result and will
602 * be automatically merged with the next highest frame when this one
603 * is popped.
604 * @param[in] request to push the frame onto.
605 * @param[in] instruction One or more unlang_t nodes describing the operations to execute.
606 * @param[in] conf Configuration for the frame. If NULL, the following values areused:
607 * - default result = UNLANG_RESULT_NOT_SET
608 * - top_frame = UNLANG_SUB_FRAME
609 * - no_rcode = false
610 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
611 * or to execute subsequent nodes.
612 * @return
613 * - 0 on success.
614 * - -1 on call stack too deep.
615 */
617 unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
618{
619 unlang_stack_t *stack = request->stack;
621
622 static unlang_frame_conf_t default_conf = {
624 .top_frame = UNLANG_SUB_FRAME
625 };
626
627 if (!conf) conf = &default_conf;
628
629 if (!instruction) return -1;
630
631#ifndef NDEBUG
632 if (DEBUG_ENABLED5) RDEBUG3("unlang_interpret_push called with instruction type \"%s\" - args %s %s",
633 instruction->debug_name,
634 do_next_sibling ? "UNLANG_NEXT_SIBLING" : "UNLANG_NEXT_STOP",
635 conf->top_frame ? "UNLANG_TOP_FRAME" : "UNLANG_SUB_FRAME");
636#endif
637
638 /*
639 * This is not a cancellation point.
640 *
641 * If we cancel here bad things happen inside the interpret.
642 */
643 if (stack->depth >= (UNLANG_STACK_MAX - 1)) {
644 RERROR("Call stack is too deep");
645 return - 1;
646 }
647
648 stack->depth++;
649
650 /*
651 * Initialize the next stack frame.
652 */
653 frame = &stack->frame[stack->depth];
654 memset(frame, 0, sizeof(*frame));
655
656 frame->instruction = instruction;
657
658 if (do_next_sibling && instruction->list) {
659 frame->next = unlang_list_next(instruction->list, instruction);
660 }
661 /* else frame->next MUST be NULL */
662
664 if (conf->top_frame) top_frame_set(frame);
665
666 frame->p_result = p_result ? p_result : &frame->section_result;
667 *frame->p_result = conf->default_result;
668
669 frame->indent = request->log.indent;
670
671 frame_state_init(stack, frame);
672
673 return 0;
674}
675
676typedef struct {
677 fr_dict_t const *old_dict; //!< the previous dictionary for the request
678 fr_dict_t const *to_free_dict; //!< Free entries matching this dictionary
679 request_t *request; //!< the request
681
683{
684 fr_pair_t *vp, *prev;
685
686 /*
687 * Local variables are appended to the end of the list. So we remove them by walking backwards
688 * from the end of the list.
689 */
690 vp = fr_pair_list_tail(&ref->request->local_pairs);
691 while (vp) {
692 fr_assert(vp->da->flags.local);
693
694 prev = fr_pair_list_prev(&ref->request->local_pairs, vp);
695 if (vp->da->dict != ref->to_free_dict) {
696 break;
697 }
698
699 (void) fr_pair_delete(&ref->request->local_pairs, vp);
700 vp = prev;
701 }
702
703 ref->request->local_dict = ref->old_dict;
704
705 return 0;
706}
707
708/** Push the children of the current frame onto a new frame onto the stack
709 *
710 * @param[out] p_result set to RLM_MODULE_FAIL if pushing the children fails
711 * @param[in] request to push the frame onto.
712 * @param[in] default_rcode The default result.
713 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
714 * or to execute subsequent nodes.
715 * @return
716 * - UNLANG_ACTION_PUSHED_CHILD on success.
717 * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
718 * - UNLANG_ACTION_FAIL, fatal error, usually stack overflow.
719 */
721 rlm_rcode_t default_rcode, bool do_next_sibling)
722{
723 unlang_stack_t *stack = request->stack;
724 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
727
729
731
732 /*
733 * The compiler catches most of these, EXCEPT for the
734 * top-level 'recv Access-Request' etc. Which can exist,
735 * and can be empty.
736 */
737 if (unlang_list_empty(&g->children)) {
738 RDEBUG2("... ignoring empty subsection ...");
740 }
741
742 if (unlang_interpret_push(p_result, request, unlang_list_head(&g->children),
743 FRAME_CONF(default_rcode, UNLANG_SUB_FRAME), do_next_sibling) < 0) {
745 }
746
748
749 /*
750 * Note that we do NOT create the variables, This way we don't have to worry about any
751 * uninitialized values. If the admin tries to use the variable without initializing it, they
752 * will get a "no such attribute" error.
753 */
754 if (!frame->state) {
755 MEM(ref = talloc(stack, unlang_variable_ref_t));
756 frame->state = ref;
757 } else {
758 MEM(ref = talloc(frame->state, unlang_variable_ref_t));
759 }
760
761 /*
762 * Set the destructor to clean up local variables.
763 */
764 ref->request = request;
765 ref->old_dict = request->local_dict;
766 ref->to_free_dict = g->variables->dict;
767 request->local_dict = g->variables->dict;
768 talloc_set_destructor(ref, _local_variables_free);
769
771}
772
773static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx);
774
775/** Update the current result after each instruction, and after popping each stack frame
776 *
777 * @note Sets stack->scratch to be the the result of the frame being popped.
778 *
779 * @param[in] request The current request.
780 * @param[in] frame The current stack frame.
781 * @param[in] result from the previous action.
782 * @return
783 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions.
784 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
785 */
786static inline CC_HINT(always_inline)
788{
789 unlang_t const *instruction = frame->instruction;
790 unlang_stack_t *stack = request->stack;
791 unlang_result_t *frame_result = frame->p_result;
792
793 if (is_unwinding(frame)) {
794 RDEBUG4("** [%i] %s - unwinding frame", stack->depth, __FUNCTION__);
796 }
797
798 /*
799 * Don't calculate a new return code for the frame, just skip
800 * to the next instruction.
801 */
802 if (result->rcode == RLM_MODULE_NOT_SET) {
803 RDEBUG4("** [%i] %s - skipping frame, no result set",
804 stack->depth, __FUNCTION__);
806 }
807
808 fr_assert(MOD_ACTION_VALID(frame_result->priority));
809 fr_assert(MOD_ACTION_VALID(result->priority));
810
811 RDEBUG4("** [%i] %s - have (%s %s) frame or module returned (%s %s)",
812 stack->depth, __FUNCTION__,
813 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
814 mod_action_name[frame_result->priority],
815 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
816 mod_action_name[result->priority]);
817
818 /*
819 * Update request->rcode if the instruction says we should
820 * We don't care about priorities for this.
821 *
822 * This is the field that's evaluated in unlang conditions
823 * like `if (ok)`.
824 */
825 if (is_rcode_set(frame) && (request->rcode != result->rcode)) {
826 RDEBUG3("Setting request->rcode to '%s'",
827 fr_table_str_by_value(rcode_table, result->rcode, "<INVALID>"));
828 request->rcode = result->rcode;
829 }
830
831 /*
832 * The array holds a default priority for this return
833 * code. Grab it in preference to any unset priority.
834 */
835 if (result->priority == MOD_ACTION_NOT_SET) {
836 result->priority = instruction->actions.actions[result->rcode];
837
838 fr_assert(MOD_ACTION_VALID(result->priority));
839
840 RDEBUG4("** [%i] %s - using default instruction priority for %s, %s",
841 stack->depth, __FUNCTION__,
842 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
843 mod_action_name[result->priority]);
844 }
845
846 /*
847 * Deal with special priorities which indicate we need
848 * to do something in addition to modifying the frame's
849 * rcode.
850 */
851 switch (result->priority) {
852 /*
853 * The child's prioriy value indicates we
854 * should return from this frame.
855 */
857 RDEBUG4("** [%i] %s - action says to return with (%s %s)",
858 stack->depth, __FUNCTION__,
859 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
860 mod_action_name[result->priority]);
861
862 *frame_result = UNLANG_RESULT_RCODE(result->rcode);
864
865 /*
866 * Reject means we should return, but
867 * with a reject rcode. This allows the
868 * user to change normally positive rcodes
869 * into negative ones.
870 *
871 * They could also just check the rcode
872 * after the module returns...
873 */
875 RDEBUG4("** [%i] %s - action says to return with (%s %s)",
876 stack->depth, __FUNCTION__,
878 mod_action_name[result->priority]);
879
880 *frame_result = UNLANG_RESULT_RCODE(RLM_MODULE_REJECT);
882
883 case MOD_ACTION_RETRY:
884 {
885 unlang_retry_t *retry = frame->retry;
886
887 RDEBUG4("** [%i] %s - action says to retry with",
888 stack->depth, __FUNCTION__);
889
890 /*
891 * If this is the first time doing the retry,
892 * then allocate the structure and set the timer.
893 */
894 if (!retry) {
895 MEM(frame->retry = retry = talloc_zero(stack, unlang_retry_t));
896
897 retry->request = request;
898 retry->depth = stack->depth;
899 retry->state = FR_RETRY_CONTINUE;
900 retry->count = 1;
901
902 /*
903 * Set a timer which automatically fires
904 * if there's a timeout. And parent it
905 * from the retry structure, so that the
906 * timer is automatically freed when the
907 * frame is cleaned up.
908 */
909 if (fr_time_delta_ispos(instruction->actions.retry.mrd)) {
910 if (fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, instruction->actions.retry.mrd,
911 false, instruction_retry_handler, retry) < 0) {
912 RPEDEBUG("Failed inserting retry event");
913 *frame_result = UNLANG_RESULT_RCODE(RLM_MODULE_FAIL);
914 goto finalize;
915 }
916 }
917
918 } else {
919 /*
920 * We've been told to stop doing retries,
921 * probably from a timeout.
922 */
923 if (retry->state != FR_RETRY_CONTINUE) goto timeout;
924
925 /*
926 * Clamp it at the maximum count.
927 */
928 if (instruction->actions.retry.mrc > 0) {
929 retry->count++;
930
931 if (retry->count >= instruction->actions.retry.mrc) {
932 retry->state = FR_RETRY_MRC;
933
934 REDEBUG("Retries hit max_rtx_count (%u) - returning 'timeout'", instruction->actions.retry.mrc);
935
936 timeout:
938 goto finalize;
939 }
940 }
941 }
942
943 RINDENT();
944 if (instruction->actions.retry.mrc) {
945 RDEBUG("... retrying (%u/%u)", retry->count, instruction->actions.retry.mrc);
946 } else {
947 RDEBUG("... retrying");
948 }
949 REXDENT();
950
951 TALLOC_FREE(frame->state);
953 frame_state_init(stack, frame); /* Don't change p_result */
955 }
956
957 default:
958 break;
959 }
960
961finalize:
962 /*
963 * We're higher or equal to previous priority, remember this
964 * return code and priority.
965 */
966 if (result->priority >= frame_result->priority) {
967 fr_assert(MOD_ACTION_VALID(result->priority));
968 fr_assert(MOD_ACTION_VALID(frame_result->priority));
969
970 RDEBUG4("** [%i] %s - overwriting existing result (%s %s) with higher priority (%s %s)",
971 stack->depth, __FUNCTION__,
972 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
973 mod_action_name[frame_result->priority],
974 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
975 mod_action_name[result->priority]);
976 *frame->p_result = *result;
977 }
978
979 /*
980 * Determine if we should continue processing siblings
981 * or pop the frame ending the section.
982 */
984}
985
986/** Function called to merge inter-stack-frame results
987 *
988 * This function is called whenever a frame is popped from the stack.
989 *
990 * 'result' is the result from the frame being popped, and 'frame' is the next highest frame in the stack.
991 *
992 * The logic here is very similar to result_eval(), with two important differences:
993 * - The priority of the lower frame is ignored, and the default priority of the higher frame is used.
994 * Unless the higher frame's priority is MOD_ACTION_NOT_SET, in which case the lower frame's priority is used.
995 */
996static inline CC_HINT(always_inline)
998{
999 unlang_stack_t *stack = request->stack;
1000 unlang_result_t our_result = *result;
1001
1002 fr_assert(MOD_ACTION_VALID(result->priority));
1003
1004 /*
1005 * When a stack frame is being popped, the priority of the
1006 * source (lower) frame is ignored, and the default priority
1007 * of the destination (higher) frame is used.
1008 *
1009 * We could (easily) add support for preserving the priority
1010 * from the lower frame, if the priority of the higher frame
1011 * was MOD_ACTION_NOT_SET, but there are no concrete use
1012 * cases for this yet.
1013 */
1014 if (result->rcode != RLM_MODULE_NOT_SET) {
1015 fr_assert(MOD_ACTION_VALID(frame->instruction->actions.actions[result->rcode]));
1016 our_result.priority = frame->instruction->actions.actions[result->rcode];
1017 }
1018
1019 RDEBUG4("** [%i] %s - using instruction priority for higher frame (%s, %s)",
1020 stack->depth, __FUNCTION__,
1021 fr_table_str_by_value(mod_rcode_table, our_result.rcode, "<invalid>"),
1022 mod_action_name[our_result.priority]);
1023
1024 return result_calculate(request, frame, &our_result);
1025}
1026
1027static inline CC_HINT(always_inline) void instruction_done_debug(request_t *request, unlang_stack_frame_t *frame, unlang_t const *instruction)
1028{
1029 if (has_debug_braces(instruction)) {
1030 REXDENT();
1031
1032 /*
1033 * If we're at debug level 1, don't emit the closing
1034 * brace as the opening brace wasn't emitted.
1035 *
1036 * Not a typo, we don't want to print the scratch_result
1037 * here, aka the ones the section actually returned,
1038 * vs the section result, which may have just been left
1039 * at defaults.
1040 */
1042 RDEBUG("# %s %s%s%s", frame->instruction->debug_name,
1043 frame->p_result == &frame->section_result ? "(" : "((",
1044 fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"),
1045 frame->p_result == &frame->section_result ? ")" : "))");
1046 } else {
1047 RDEBUG2("} # %s %s%s%s", frame->instruction->debug_name,
1048 frame->p_result == &frame->section_result ? "(" : "((",
1049 fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"),
1050 frame->p_result == &frame->section_result ? ")" : "))");
1051 }
1052 }
1053}
1054
1055/** Evaluates all the unlang nodes in a section
1056 *
1057 * This function interprets a list of unlang instructions at a given level using the same
1058 * stack frame, and pushes additional frames onto the stack as needed.
1059 *
1060 * This function can be seen as moving horizontally.
1061 *
1062 * @param[in] request The current request.
1063 * @param[in] frame The current stack frame.
1064 * @return
1065 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions in the current stack frame
1066 * which may not be the same frame as when this function
1067 * was called.
1068 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
1069 */
1070static inline CC_HINT(always_inline)
1072{
1073 unlang_stack_t *stack = request->stack;
1074 unlang_result_t *scratch = &frame->scratch_result;
1075
1076 /*
1077 * Loop over all the instructions in this list.
1078 */
1079 while (frame->instruction) {
1080 unlang_t const *instruction = frame->instruction;
1081 unlang_action_t ua;
1083 unlang_thread_t *thread_data;
1084
1085 DUMP_STACK;
1086
1087 fr_assert(instruction->debug_name != NULL); /* if this happens, all bets are off. */
1088 fr_assert(unlang_ops[instruction->type].interpret != NULL);
1089 fr_assert(frame->process != NULL);
1090
1091 REQUEST_VERIFY(request);
1092
1093 /*
1094 * We're running this frame, so it can't possibly be yielded.
1095 */
1096 if (is_yielded(frame)) {
1097 RDEBUG("%s - Resuming execution", instruction->debug_name);
1098 yielded_clear(frame);
1099 }
1100
1101#ifndef NDEBUG
1102 /*
1103 * Failure testing!
1104 */
1105 if (request->ins_max) {
1106 request->ins_count++;
1107
1108 if (request->ins_count >= request->ins_max) {
1109 RERROR("Failing request due to maximum instruction count %" PRIu64, request->ins_max);
1110
1112 }
1113 }
1114#endif
1115
1116 /*
1117 * We're not re-entering this frame, this is the first
1118 * time we're evaluating this instruction, so we should
1119 * print debug braces and indent.
1120 */
1121 if (!is_repeatable(frame)) {
1122 if (has_debug_braces(frame)) {
1123 RDEBUG2("%s {", instruction->debug_name);
1124 RINDENT();
1125 }
1126 /*
1127 * Clear the repeatable flag so this frame
1128 * won't get executed again unless it specifically
1129 * requests it.
1130 *
1131 * The flag may still be set again during the
1132 * process function to indicate that the frame
1133 * should be evaluated again.
1134 */
1135 } else {
1136 repeatable_clear(frame);
1137 }
1138
1139 /*
1140 * Execute an operation
1141 */
1142 RDEBUG4("** [%i] %s >> %s", stack->depth, __FUNCTION__,
1143 unlang_ops[instruction->type].name);
1144
1146
1147 /*
1148 * A module (or even a section) may be administratively down
1149 */
1150 if (unlikely(((thread_data = unlang_thread_data(instruction)) != NULL) &&
1151 thread_data->use_forced_result)) {
1152 frame->scratch_result = thread_data->forced_result;
1154
1155 } else {
1156 /*
1157 * catch plays games with the frame so we skip
1158 * to the next catch section at a given depth,
1159 * it's not safe to access frame->instruction
1160 * after this point, and the cached instruction
1161 * should be used instead.
1162 */
1163 ua = frame->process(&frame->scratch_result, request, frame);
1164 }
1165
1167
1168 RDEBUG4("** [%i] %s << %s (%s %s)", stack->depth, __FUNCTION__,
1170 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<INVALID>"),
1171 mod_action_name[scratch->priority]);
1172
1173 /*
1174 * If the frame is cancelled we ignore the
1175 * return code of the process function and
1176 * pop the frame. We'll keep popping
1177 * frames until we hit a non-cancelled frame
1178 * or the top frame.
1179 */
1180 if (is_unwinding(frame)) goto calculate_result;
1181
1182 switch (ua) {
1183 /*
1184 * The operation resulted in additional frames
1185 * being pushed onto the stack, execution should
1186 * now continue at the deepest frame.
1187 */
1189 fr_assert_msg(&stack->frame[stack->depth] > frame,
1190 "Instruction %s returned UNLANG_ACTION_PUSHED_CHILD, "
1191 "but stack depth was not increased",
1192 instruction->name);
1195
1196 /*
1197 * Yield control back to the scheduler, or whatever
1198 * called the interpreter.
1199 */
1201 fr_assert_msg(&stack->frame[stack->depth] == frame,
1202 "Instruction %s returned UNLANG_ACTION_YIELD, but pushed additional "
1203 "frames for evaluation. Instruction should return UNLANG_ACTION_PUSHED_CHILD "
1204 "instead", instruction->name);
1206 yielded_set(frame);
1207 RDEBUG4("** [%i] %s - yielding with current (%s %s)", stack->depth, __FUNCTION__,
1208 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"),
1209 mod_action_name[scratch->priority]);
1211
1212 /*
1213 * This action is intended to be returned by library
1214 * functions. It reduces boilerplate.
1215 */
1216 case UNLANG_ACTION_FAIL:
1217 /*
1218 * Let unlang_calculate figure out if this is the final result
1219 */
1220 frame->scratch_result = UNLANG_RESULT_RCODE(RLM_MODULE_FAIL);
1222
1223 /*
1224 * Instruction finished execution,
1225 * check to see what we need to do next, and update
1226 * the section rcode and priority.
1227 */
1229 calculate_result:
1230 /*
1231 * Merge in the scratch result _before_ printing
1232 * out the rcode for the frame, so get what we'll
1233 * actually return.
1234 */
1235 fa = result_calculate(request, frame, &frame->scratch_result);
1236
1237 instruction_done_debug(request, frame, instruction);
1238
1239 switch (fa) {
1241 goto pop;
1242
1244 if (has_debug_braces(instruction)) {
1245 REXDENT();
1246 RDEBUG2("} # retrying the same section");
1247 }
1248 continue; /* with the current instruction */
1249
1250 default:
1251 break;
1252 }
1253 break;
1254
1255 /*
1256 * Execute the next instruction in this frame
1257 */
1259 if (has_debug_braces(instruction)) {
1260 REXDENT();
1261 RDEBUG2("}");
1262 }
1263 break;
1264 } /* switch over return code from the interpret function */
1265
1266 frame_next(stack, frame);
1267 }
1268
1269pop:
1270 fr_assert(MOD_ACTION_VALID(frame->p_result->priority));
1271
1272 RDEBUG4("** [%i] %s - done current subsection with (%s %s), %s",
1273 stack->depth, __FUNCTION__,
1274 fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"),
1275 mod_action_name[frame->p_result->priority],
1276 frame->p_result == &(frame->section_result) ? "will set higher frame rcode" : "will NOT set higher frame rcode (p_result)");
1277
1279}
1280
1281/** Run the interpreter for a current request
1282 *
1283 * This function runs the interpreter for a request. It deals with popping
1284 * stack frames, and calculating the final result for the frame.
1285 *
1286 * @param[in] request to run. If this is an internal request
1287 * the request may be freed by the interpreter.
1288 * @param[in] running Is the interpreter already running.
1289 * @return The final request rcode.
1290 */
1291CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
1292{
1293 unlang_stack_t *stack = request->stack;
1294 unlang_interpret_t *intp = stack->intp;
1295 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1296
1297 /*
1298 * This is needed to ensure that if a frame is marked
1299 * for unwinding whilst the request is yielded, we
1300 * unwind the cancelled frame correctly, instead of
1301 * continuing.
1302 */
1304
1305#ifndef NDEBUG
1306 if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
1307 DUMP_STACK;
1308#endif
1309
1310 fr_assert(!unlang_request_is_scheduled(request)); /* if we're running it, it can't be scheduled */
1311 fr_assert_msg(intp, "request has no interpreter associated");
1312
1313 RDEBUG4("** [%i] %s - interpret entered", stack->depth, __FUNCTION__);
1314 if (!running) intp->funcs.resume(request, intp->uctx);
1315
1316 for (;;) {
1317 fr_assert(stack->depth > 0);
1319
1320 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
1322 switch (fa) {
1323 next:
1324 RDEBUG4("** [%i] %s - frame action next", stack->depth, __FUNCTION__);
1326
1327 case UNLANG_FRAME_ACTION_NEXT: /* Evaluate the current frame */
1328 frame = &stack->frame[stack->depth];
1329 fa = frame_eval(request, frame);
1330 if (fa != UNLANG_FRAME_ACTION_POP) continue;
1331
1332 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
1335
1336 case UNLANG_FRAME_ACTION_POP: /* Pop this frame and check the one beneath it */
1337 {
1338 bool top_frame = is_top_frame(frame);
1339 bool private_result = is_private_result(frame);
1340
1341 unlang_result_t section_result = frame->section_result; /* record the result of the frame before we pop it*/
1342
1343 DUMP_STACK;
1344
1345 /*
1346 * Triggers can run modules which pop, and then the stack is empty.
1347 */
1348 if (unlikely(stack->depth == 0)) {
1349 break;
1350 }
1351
1352 /*
1353 * Head on back up the stack
1354 */
1355 frame_pop(request, stack);
1356 RDEBUG4("** [%i] %s - frame popped", stack->depth + 1, __FUNCTION__);
1357
1358 /*
1359 * Update the stack frame
1360 */
1361 frame = &stack->frame[stack->depth];
1362 DUMP_STACK;
1363
1364 /*
1365 * Transition back to the C stack
1366 *
1367 * We still need to merge in the previous frame's result,
1368 * but we don't care about the action, as we're returning.
1369 */
1370 if (top_frame) {
1371 if (!private_result) result_calculate(request, frame, &section_result);
1372 break; /* stop */
1373 }
1374
1375 /*
1376 * Don't process the section result for a frame if
1377 * the result is being consumed by a module.
1378 */
1379 if (private_result) {
1381 /*
1382 * Merge lower frame into higher frame.
1383 *
1384 * this _MUST_ be done, even on resume, because the
1385 * section result needs to be updated for the frame
1386 * being resumed, in case it cares about the rcode
1387 * like transaction sections.
1388 */
1389 } else {
1390 fa = result_pop(request, frame, &section_result);
1391 }
1392
1393 /*
1394 * Resume a "foreach" loop, or a "load-balance" section
1395 * or anything else that needs to be checked on the way
1396 * back on up the stack. Here we just resume evaluating
1397 * the frame, we don't advance the instruction.
1398 */
1399 if (!is_unwinding(frame) && is_repeatable(frame)) goto next;
1400
1401 /*
1402 * Close out the section we entered earlier
1403 *
1404 * @todo - this arguably accesses the
1405 * frame after it's been popped, but this
1406 * is usually OK. :(
1407 */
1408 instruction_done_debug(request, frame, frame->instruction);
1409
1411
1412 /*
1413 * If we're continuing after popping a frame
1414 * then we advance the instruction else we
1415 * end up executing the same code over and over...
1416 */
1417 switch (fa) {
1419 DEBUG4("** [%i] %s - continuing after subsection with (%s %s)",
1420 stack->depth, __FUNCTION__,
1423 frame_next(stack, frame);
1424 goto next;
1425
1426 /*
1427 * Else if we're really done with this frame
1428 * print some helpful debug...
1429 */
1430 default:
1431 RDEBUG4("** [%i] %s - done current subsection with (%s %s)",
1432 stack->depth, __FUNCTION__,
1435 continue;
1436 }
1437
1438 }
1439
1441 /* Cannot yield from a nested call to unlang_interpret */
1442 fr_assert(!running);
1443
1444 RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
1445 intp->funcs.yield(request, intp->uctx);
1446 return RLM_MODULE_NOT_SET;
1447
1448 case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
1449 goto next;
1450 }
1451 break;
1452 }
1453
1454 fr_assert(stack->depth >= 0);
1455
1456 /*
1457 * We're at the top frame, return the result from the
1458 * stack, and get rid of the top frame.
1459 */
1460 RDEBUG4("** [%i] %s - interpret exiting, returning (%s)", stack->depth, __FUNCTION__,
1462
1463 DUMP_STACK;
1464
1465 {
1466 rlm_rcode_t rcode;
1467 /*
1468 * Record this now as the done functions may free
1469 * the request.
1470 *
1471 * Note: We use p_result here, as that's where the
1472 * result of evaluating the frame was written.
1473 * We don't use the section_result, as that may have
1474 * been left as its default value which may be 0
1475 * (reject).
1476 */
1477 rcode = frame->p_result->rcode;
1478
1479 /*
1480 * This usually means the request is complete in its
1481 * entirety.
1482 */
1483 if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
1484
1485 return rcode;
1486 }
1487}
1488
1490 .self = {
1492 .name = "empty-group",
1493 .debug_name = "empty-group",
1494 .actions = {
1495 .actions = {
1507 },
1508 .retry = RETRY_INIT,
1509 },
1510 },
1511 .children = {
1512 .head = {
1513 .entry = {
1514 .prev = &empty_group.children.head.entry,
1515 .next = &empty_group.children.head.entry,
1516 }
1517 },
1518 },
1519};
1520
1521/** Push a configuration section onto the request stack for later interpretation.
1522 *
1523 */
1525{
1526 unlang_t *instruction = NULL;
1527
1528 /*
1529 * Interpretable unlang instructions are stored as CONF_DATA
1530 * associated with sections.
1531 */
1532 if (cs) {
1533 instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
1534 if (!instruction) {
1535 REDEBUG("Failed to find pre-compiled unlang for section %s ... { ... }",
1536 cf_section_name1(cs));
1537 return -1;
1538 }
1539 }
1540
1541 return unlang_interpret_push_instruction(p_result, request, instruction, conf);
1542}
1543
1544/** Push an instruction onto the request stack for later interpretation.
1545 *
1546 */
1548{
1549 unlang_stack_t *stack = request->stack;
1550
1551 if (!instruction) {
1552 instruction = unlang_group_to_generic(&empty_group);
1553 }
1554
1555 /*
1556 * Push the default action, and the instruction which has
1557 * no action.
1558 */
1559 if (unlang_interpret_push(p_result, request, instruction, conf, UNLANG_NEXT_SIBLING) < 0) {
1560 return -1;
1561 }
1562
1563 RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
1564
1565 return 0;
1566}
1567
1568/** Allocate a new unlang stack
1569 *
1570 * @param[in] ctx to allocate stack in.
1571 * @return
1572 * - A new stack on success.
1573 * - NULL on OOM.
1574 */
1575void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
1576{
1577 /*
1578 * Should never be evaluated, is just here to reduce
1579 * branches, so we don't need to check for frame->instruction.
1580 */
1581 static unlang_t unlang_instruction = {
1582 .debug_name = "top",
1583 .actions = DEFAULT_MOD_ACTIONS,
1584 };
1585
1587
1588 /*
1589 * If we have talloc_pooled_object allocate the stack as
1590 * a combined chunk/pool, with memory to hold at mutable
1591 * state data for the of the stack frames.
1592 *
1593 * Having a dedicated pool for mutable stack data
1594 * means we don't have memory fragmentations issues
1595 * as we would if request were used as the pool.
1596 *
1597 * This number is pretty arbitrary, but it seems
1598 * like too low level to make into a tuneable.
1599 */
1601 stack->frame[0].p_result = &stack->frame[0].section_result;
1602 stack->frame[0].scratch_result = UNLANG_RESULT_NOT_SET;
1603 stack->frame[0].section_result = UNLANG_RESULT_NOT_SET;
1604 stack->frame[0].instruction = &unlang_instruction; /* The top frame has no instruction, so we use a dummy one */
1605
1606 return stack;
1607}
1608
1609/** Indicate to the caller of the interpreter that this request is complete
1610 *
1611 */
1613{
1614 unlang_stack_t *stack = request->stack;
1615 unlang_interpret_t *intp;
1616
1617 if (!fr_cond_assert(stack != NULL)) return;
1618
1619 intp = stack->intp;
1620
1621 request->master_state = REQUEST_DONE;
1622 switch (request->type) {
1624 intp->funcs.done_external(request, frame_current(request)->section_result.rcode, intp->uctx);
1625 break;
1626
1628 intp->funcs.done_internal(request, frame_current(request)->section_result.rcode, intp->uctx);
1629 break;
1630
1632 intp->funcs.done_detached(request, frame_current(request)->section_result.rcode, intp->uctx); /* Callback will usually free the request */
1633 break;
1634 }
1635}
1636
1637/** Tell the interpreter to detach the request
1638 *
1639 * This function should not be called directly use unlang_interpret_signal(request, FR_SIGNAL_DETACH) instead.
1640 * This will ensure all frames on the request's stack receive the detach signal.
1641 */
1642static inline CC_HINT(always_inline)
1644{
1645 unlang_stack_t *stack = request->stack;
1646 unlang_interpret_t *intp;
1647
1648 if (!fr_cond_assert(stack != NULL)) return;
1649
1650 if (!request_is_detachable(request)) return;
1651
1652 intp = stack->intp;
1653
1654 intp->funcs.detach(request, intp->uctx);
1655}
1656
1658{
1659 unlang_stack_t *stack = request->stack;
1660 unlang_interpret_t *intp;
1661
1662 if (!fr_cond_assert(stack != NULL)) return;
1663
1664 intp = stack->intp;
1665
1666 request->priority = priority;
1667
1668 if (intp->funcs.prioritise) intp->funcs.prioritise(request, intp->uctx);
1669}
1670
1671/** Cancel any pending retry
1672 *
1673 * @param[in] request The current request.
1674 */
1676{
1677 unlang_stack_t *stack = request->stack;
1678 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1679
1680 TALLOC_FREE(frame->retry);
1681}
1682
1683
1684/** Delivers a frame to one or more frames in the stack
1685 *
1686 * This is typically called via an "async" action, i.e. an action outside
1687 * of the normal processing of the request.
1688 *
1689 * For FR_SIGNAL_CANCEL all frames are marked up for cancellation, but the
1690 * cancellation is handled by the interpret.
1691 *
1692 * Other signal types are delivered immediately, inrrespecitve of whether
1693 * the request is currently being processed or not.
1694 *
1695 * Signaling stops at the "limit" frame. This is so that keywords
1696 * such as "timeout" and "limit" can signal frames *lower* than theirs
1697 * to stop, but then continue with their own work.
1698 *
1699 * @note It's better (clearer) to use one of the unwind_* functions
1700 * unless the entire request is being cancelled.
1701 *
1702 * @param[in] request The current request.
1703 * @param[in] action to signal.
1704 * @param[in] limit the frame at which to stop signaling.
1705 */
1706void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
1707{
1708 unlang_stack_frame_t *frame;
1709 unlang_stack_t *stack = request->stack;
1710 int i, depth = stack->depth;
1711
1712 (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1713
1714 fr_assert(stack->depth >= 1);
1715
1716 /*
1717 * Does not complete the unwinding here, just marks
1718 * up the frames for unwinding. The request must
1719 * be marked as runnable to complete the cancellation.
1720 */
1721 if (action == FR_SIGNAL_CANCEL) unwind_to_depth(stack, limit);
1722
1723 /*
1724 * Walk back up the stack, calling signal handlers
1725 * to cancel any pending operations and free/release
1726 * any resources.
1727 *
1728 * There may be multiple resumption points in the
1729 * stack, as modules can push xlats and function
1730 * calls.
1731 *
1732 * Note: Slightly confusingly, a cancellation signal
1733 * can still be delivered to a frame that is not
1734 * cancellable, but the frame won't be automatically
1735 * unwound.
1736 */
1737 for (i = depth; i >= limit; i--) {
1738 frame = &stack->frame[i];
1739 if (frame->signal) {
1740 frame->signal(request, frame, action);
1741
1742 /*
1743 * Once the cancellation function has been
1744 * called, the frame is no longer in a state
1745 * where it can accept further signals.
1746 */
1747 if (action == FR_SIGNAL_CANCEL) frame->signal = NULL;
1748
1749 /*
1750 * If the frame is cancelled, we don't do any retries.
1751 */
1752 TALLOC_FREE(frame->retry);
1753 }
1754 }
1755}
1756
1757/** Send a signal (usually stop) to a request
1758 *
1759 * This is typically called via an "async" action, i.e. an action
1760 * outside of the normal processing of the request.
1761 *
1762 * @note This does NOT immediately stop the request, it just deliveres
1763 * signals, and in the case of a cancel, marks up frames for unwinding
1764 * and adds it to the runnable queue if it's yielded.
1765 *
1766 * @note This function should be safe to call anywhere.
1767 *
1768 * @param[in] request The current request.
1769 * @param[in] action to signal.
1770 */
1772{
1773 unlang_stack_t *stack = request->stack;
1774
1775 switch (action) {
1776 case FR_SIGNAL_DETACH:
1777 /*
1778 * Ensure the request is able to be detached
1779 * else don't signal.
1780 */
1781 if (!fr_cond_assert(request_is_detachable(request))) return;
1782 break;
1783
1784 default:
1785 break;
1786 }
1787
1788 /*
1789 * Requests that haven't been run through the interpreter
1790 * yet should have a stack depth of zero, so we don't
1791 * need to do anything.
1792 */
1793 if (!stack || stack->depth == 0) return;
1794
1795 unlang_stack_signal(request, action, 1);
1796
1797 switch (action) {
1798 case FR_SIGNAL_CANCEL:
1799 {
1800 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1801 /*
1802 * Let anything that cares, know that the
1803 * request was forcefully stopped.
1804 */
1805 request->master_state = REQUEST_STOP_PROCESSING;
1806
1807 /*
1808 * Give cancelled requests the highest priority
1809 * to get them to release resources ASAP.
1810 */
1811 unlang_interpret_request_prioritise(request, UINT32_MAX);
1812
1813 /*
1814 * If the request is yielded, mark it as runnable
1815 *
1816 * If the request was _not_ cancelled, it means
1817 * it's not cancellable, and we need to let the
1818 * request progress normally.
1819 *
1820 * A concrete example of this, is the parent of
1821 * subrequests, which must not continue until
1822 * the subrequest is done.
1823 */
1824 if (stack && is_yielded(frame) && is_unwinding(frame) && !unlang_request_is_scheduled(request)) {
1826 }
1827 }
1828 break;
1829
1830 case FR_SIGNAL_DETACH:
1831 /*
1832 * Cleanup any cross-request pointers, and mark the
1833 * request as detached. When the request completes it
1834 * should by automatically freed.
1835 */
1837 break;
1838
1839 default:
1840 break;
1841 }
1842}
1843
1845{
1846 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1847 request_t *request = talloc_get_type_abort(retry->request, request_t);
1848
1849 RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1850
1851 /*
1852 * Signal all lower frames to exit.
1853 */
1854 unlang_stack_signal(request, FR_SIGNAL_CANCEL, retry->depth + 1);
1855
1856 retry->state = FR_RETRY_MRD;
1858}
1859
1861{
1862 request_t *request = talloc_get_type_abort(ctx, request_t);
1863
1864 RDEBUG("Maximum timeout reached, signalling interpreter to stop the request.");
1865
1866 /*
1867 * Stop the entire request.
1868 */
1870}
1871
1872
1873/** Set a timeout for a request.
1874 *
1875 * The timeout is associated with the current stack frame.
1876 *
1877 */
1879{
1880 unlang_stack_t *stack = request->stack;
1881 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1882 unlang_retry_t *retry;
1883
1884 fr_assert(!frame->retry);
1886
1887 frame->retry = retry = talloc_zero(stack, unlang_retry_t);
1888 if (!frame->retry) return -1;
1889
1890 retry->request = request;
1891 retry->depth = stack->depth;
1892 retry->state = FR_RETRY_CONTINUE;
1893 retry->count = 1;
1894
1895 return fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, timeout,
1896 false, instruction_timeout_handler, request);
1897}
1898
1899
1900/** Return the depth of the request's stack
1901 *
1902 */
1904{
1905 unlang_stack_t *stack = request->stack;
1906
1907 return stack->depth;
1908}
1909
1910/** Get the last instruction result OR the last frame that was popped
1911 *
1912 * @param[in] request The current request.
1913 * @return the current rcode for the frame.
1914 */
1916{
1917 return frame_current(request)->p_result->rcode;
1918}
1919
1920/** Get the last instruction priority OR the last frame that was popped
1921 *
1922 * @param[in] request The current request.
1923 * @return the current rcode for the frame.
1924 */
1929
1930/** Get the last instruction result OR the last frame that was popped
1931 *
1932 * @param[in] request The current request.
1933 * @return the current result for the frame.
1934 */
1936{
1937 return frame_current(request)->p_result;
1938}
1939
1940/** Return whether a request is currently scheduled
1941 *
1942 */
1944{
1945 unlang_stack_t *stack = request->stack;
1946 unlang_interpret_t *intp = stack->intp;
1947
1948 return intp->funcs.scheduled(request, intp->uctx);
1949}
1950
1951/** Return whether a request has been cancelled
1952 */
1954{
1955 return (request->master_state == REQUEST_STOP_PROCESSING);
1956}
1957
1958/** Return whether a request has been marked done
1959 */
1961{
1962 return (request->master_state == REQUEST_DONE);
1963}
1964
1965/** Check if a request as resumable.
1966 *
1967 * @param[in] request The current request.
1968 * @return
1969 * - true if the request is resumable (i.e. has yielded)
1970 * - false if the request is not resumable (i.e. has not yielded)
1971 */
1973{
1974 unlang_stack_t *stack = request->stack;
1975 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1976
1977 return is_yielded(frame);
1978}
1979
1980/** Mark a request as resumable.
1981 *
1982 * It's not called "unlang_interpret", because it doesn't actually
1983 * resume the request, it just schedules it for resumption.
1984 *
1985 * @note that this schedules the request for resumption. It does not immediately
1986 * start running the request.
1987 *
1988 * @param[in] request The current request.
1989 */
1991{
1992 unlang_stack_t *stack = request->stack;
1993 unlang_interpret_t *intp = stack->intp;
1994 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1995
1996 bool scheduled = unlang_request_is_scheduled(request);
1997
1998 /*
1999 * The request hasn't yielded, OR it's already been
2000 * marked as runnable. Don't do anything.
2001 *
2002 * The IO code, or children have no idea where they're
2003 * being called from. They just ask to mark the parent
2004 * resumable when they're done. So we have to check here
2005 * if this request is resumable.
2006 *
2007 * If the parent called the child directly, then the
2008 * parent hasn't yielded, so it isn't resumable. When
2009 * the child is done, the parent will automatically
2010 * continue running. We therefore don't need to insert
2011 * the parent into the backlog.
2012 *
2013 * Multiple child request may also mark a parent request
2014 * runnable, before the parent request starts running.
2015 */
2016 if (!is_yielded(frame) || scheduled) {
2017 RDEBUG3("Not marking request %s as runnable due to%s%s",
2018 request->name,
2019 !is_yielded(frame) ?
2020 " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
2021 return;
2022 }
2023
2024 RDEBUG3("Interpreter - Request marked as runnable");
2025
2026 intp->funcs.mark_runnable(request, intp->uctx);
2027}
2028
2029/** Get a talloc_ctx which is valid only for this frame
2030 *
2031 * @param[in] request The current request.
2032 * @return
2033 * - a TALLOC_CTX which is valid only for this stack frame
2034 */
2036{
2037 unlang_stack_t *stack = request->stack;
2038 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
2039
2040 if (frame->state) return (TALLOC_CTX *)frame->state;
2041
2042 /*
2043 * If the frame doesn't ordinarily have a
2044 * state, assume the caller knows what it's
2045 * doing and allocate one.
2046 */
2047 return (TALLOC_CTX *)(frame->state = talloc_new(stack));
2048}
2049
2051 { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
2053};
2054
2055static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
2056 UNUSED xlat_ctx_t const *xctx,
2057 request_t *request, fr_value_box_list_t *args);
2058
2059/** Signal the request to stop executing
2060 *
2061 * The request can't be running at this point because we're in the event
2062 * loop. This means the request is always in a consistent state when
2063 * the timeout event fires, even if that's state is waiting on I/O.
2064 */
2066{
2067 request_t *request = talloc_get_type_abort(uctx, request_t);
2068
2069 RDEBUG2("Request canceled by dynamic timeout");
2070 /*
2071 * Cleans up the memory allocated to hold
2072 * the pointer, not the event itself.
2073 */
2074 talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
2075
2077}
2078
2079/** Allows a request to dynamically alter its own lifetime
2080 *
2081 * %cancel(<timeout>)
2082 *
2083 * If timeout is 0, then the request is immediately cancelled.
2084 */
2086 UNUSED xlat_ctx_t const *xctx,
2087 request_t *request, fr_value_box_list_t *args)
2088{
2089 fr_value_box_t *timeout;
2091 fr_timer_t **ev_p, **ev_p_og;
2092 fr_value_box_t *vb;
2093 fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
2094
2095 fr_assert(el != NULL);
2096
2097 XLAT_ARGS(args, &timeout);
2098
2099 /*
2100 * No timeout means cancel immediately, so yield allowing
2101 * the interpreter to run the event we added to cancel
2102 * the request.
2103 *
2104 * We call unlang_xlat_yield to keep the interpreter happy
2105 * as it expects to see a resume function set.
2106 */
2107 if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
2109 return XLAT_ACTION_DONE;
2110 }
2111
2112 /*
2113 * First see if we already have a timeout event
2114 * that was previously added by this xlat.
2115 */
2116 ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
2117 if (ev_p) {
2118 fr_assert(*ev_p);
2119
2120 when = fr_timer_when(*ev_p);
2121 } else {
2122 /*
2123 * Must not be parented from the request
2124 * as this is freed by request data.
2125 */
2126 MEM(ev_p = talloc_zero(NULL, fr_timer_t *));
2127 }
2128
2129 if (unlikely(fr_timer_in(ev_p, el->tl, ev_p,
2130 timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
2131 false, unlang_cancel_event, request) < 0)) {
2132 RPERROR("Failed inserting cancellation event");
2133 talloc_free(ev_p);
2134 return XLAT_ACTION_FAIL;
2135 }
2136 if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
2137 UNCONST(fr_timer_t **, ev_p), true, true, false) < 0)) {
2138 RPERROR("Failed associating cancellation event with request");
2139 talloc_free(ev_p);
2140 return XLAT_ACTION_FAIL;
2141 }
2142
2143 if (ev_p_og) {
2144 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
2145
2146 /*
2147 * Return how long before the previous
2148 * cancel event would have fired.
2149 *
2150 * This can be useful for doing stacked
2151 * cancellations in policy.
2152 */
2153 vb->vb_time_delta = fr_time_sub(when, unlang_interpret_event_list(request)->tl->time());
2155 }
2156
2157 /*
2158 * No value if this is the first cleanup event
2159 */
2160 return XLAT_ACTION_DONE;
2161}
2162
2164 { .required = true, .single = true, .type = FR_TYPE_STRING },
2166};
2167
2168/** Get information about the interpreter state
2169 *
2170 * @ingroup xlat_functions
2171 */
2173 UNUSED xlat_ctx_t const *xctx,
2174 request_t *request, fr_value_box_list_t *in)
2175{
2176 unlang_stack_t *stack = request->stack;
2177 int depth = stack->depth;
2178 unlang_stack_frame_t *frame;
2179 unlang_t const *instruction;
2180 fr_value_box_t *arg = fr_value_box_list_head(in);
2181 char const *fmt = arg->vb_strvalue;
2182 fr_value_box_t *vb;
2183
2184 MEM(vb = fr_value_box_alloc_null(ctx));
2185
2186 /*
2187 * Find the correct stack frame.
2188 */
2189 while (*fmt == '.') {
2190 if (depth <= 1) {
2191 if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
2192 error:
2193 talloc_free(vb);
2194 return XLAT_ACTION_FAIL;
2195 }
2196 goto finish;
2197 }
2198
2199 fmt++;
2200 depth--;
2201 }
2202
2203 /*
2204 * Get the current instruction.
2205 */
2206 frame = &stack->frame[depth];
2207 instruction = frame->instruction;
2208
2209 /*
2210 * Nothing there...
2211 */
2212 if (!instruction) goto clear;
2213
2214 /*
2215 * How deep the current stack is.
2216 */
2217 if (strcmp(fmt, "depth") == 0) {
2218 fr_value_box_int32(vb, NULL, depth, false);
2219 goto finish;
2220 }
2221
2222 /*
2223 * The current module
2224 */
2225 if (strcmp(fmt, "module") == 0) {
2226 if (!request->module) goto clear;
2227
2228 if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
2229
2230 goto finish;
2231 }
2232
2233 /*
2234 * Name of the instruction.
2235 */
2236 if (strcmp(fmt, "name") == 0) {
2237 if (!instruction->name) goto clear;
2238
2239 if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
2240 strlen(instruction->name), false) < 0) goto error;
2241 goto finish;
2242 }
2243
2244 /*
2245 * The request processing stage.
2246 */
2247 if (strcmp(fmt, "processing_stage") == 0) {
2248 if (!request->component) goto clear;
2249
2250 if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
2251
2252 goto finish;
2253 }
2254
2255 /*
2256 * The current return code.
2257 */
2258 if (strcmp(fmt, "rcode") == 0) {
2259 if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
2260
2261 goto finish;
2262 }
2263
2264 /*
2265 * The virtual server handling the request
2266 */
2267 if (strcmp(fmt, "server") == 0) {
2268 request_t *our_request;
2269 CONF_SECTION *server = NULL;
2270
2271 /*
2272 * If we're being pedantic subrequests don't have a virtual
2273 * server associated with them unless they go call {}.
2274 *
2275 * But we're not being pendantic, so go back up the request
2276 * list ooking for a call frame.
2277 *
2278 * Unfortunately for detached subrequests we still won't find
2279 * the actual virtual server...
2280 */
2281 for (our_request = request; our_request && server == NULL; our_request = our_request->parent) {
2282 server = unlang_call_current(our_request);
2283 }
2284 if (server == NULL) goto finish;
2285
2286 if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(server), false) < 0) goto error;
2287
2288 goto finish;
2289 }
2290
2291 /*
2292 * Unlang instruction type.
2293 */
2294 if (strcmp(fmt, "type") == 0) {
2295 if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
2296 strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
2297
2298 goto finish;
2299 }
2300
2301 /*
2302 * All of the remaining things need a CONF_ITEM.
2303 */
2304 if (!instruction->ci) {
2305 if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 9, false) < 0) goto error;
2306
2307 goto finish;
2308 }
2309
2310 /*
2311 * Line number of the current section.
2312 */
2313 if (strcmp(fmt, "line") == 0) {
2314 fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
2315
2316 goto finish;
2317 }
2318
2319 /*
2320 * Filename of the current section.
2321 */
2322 if (strcmp(fmt, "filename") == 0) {
2323 if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
2324
2325 goto finish;
2326 }
2327
2328finish:
2329 if (vb->type != FR_TYPE_NULL) {
2331 } else {
2332 clear:
2333 talloc_free(vb);
2334 }
2335
2336 return XLAT_ACTION_DONE;
2337}
2338
2339/** Initialize a unlang compiler / interpret.
2340 *
2341 * @param[in] ctx to bind lifetime of the interpret to.
2342 * Shouldn't be any free order issues here as
2343 * the interpret itself has no state.
2344 * But event loop should be stopped before
2345 * freeing the interpret.
2346 * @param[in] el for any timer or I/O events.
2347 * @param[in] funcs Callbacks to used to communicate request
2348 * state to our owner.
2349 * @param[in] uctx Data to pass to callbacks.
2350 */
2352 fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
2353{
2354 unlang_interpret_t *intp;
2355
2356 fr_assert(funcs->init_internal);
2357
2358 fr_assert(funcs->done_internal);
2359 fr_assert(funcs->done_detached);
2360 fr_assert(funcs->done_external);
2361
2362 fr_assert(funcs->detach);
2363 fr_assert(funcs->yield);
2364 fr_assert(funcs->resume);
2365 fr_assert(funcs->mark_runnable);
2366 fr_assert(funcs->scheduled);
2367
2368 MEM(intp = talloc(ctx, unlang_interpret_t));
2369 *intp = (unlang_interpret_t){
2370 .el = el,
2371 .funcs = *funcs,
2372 .uctx = uctx
2373 };
2374
2375 return intp;
2376}
2377
2378/** Discard the bottom most frame on the request's stack
2379 *
2380 * This is used for cleaning up after errors. i.e. the caller
2381 * uses a push function, and experiences an error and needs to
2382 * remove the frame that was just pushed.
2383 */
2385{
2386 frame_pop(request, request->stack);
2387}
2388
2389/** Set a specific interpreter for a request
2390 *
2391 */
2393{
2394 unlang_stack_t *stack = request->stack;
2395 stack->intp = intp;
2396}
2397
2398/** Get the interpreter set for a request
2399 *
2400 */
2402{
2403 unlang_stack_t *stack = request->stack;
2404
2405 return stack->intp;
2406}
2407
2408/** Get the event list for the current interpreter
2409 *
2410 */
2412{
2413 unlang_stack_t *stack = request->stack;
2414
2415 if (!stack->intp) return NULL;
2416
2417 return stack->intp->el;
2418}
2419
2420/** Set the default interpreter for this thread
2421 *
2422 */
2424{
2425 if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
2426
2427 intp_thread_default = intp;
2428}
2429
2430/** Get the default interpreter for this thread
2431 *
2432 * This allows detached requests to be executed asynchronously
2433 */
2435{
2436 if (!intp_thread_default) return NULL;
2437
2438 return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
2439}
2440
2442{
2443 xlat_t *xlat;
2444 /*
2445 * Should be void, but someone decided not to register multiple xlats
2446 * breaking the convention we use everywhere else in the server...
2447 */
2448 if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2450
2451 if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2453
2454 return 0;
2455}
#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
int const char * file
Definition acutest.h:702
va_list args
Definition acutest.h:770
static int const char * fmt
Definition acutest.h:573
int const char int line
Definition acutest.h:702
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define RCSID(id)
Definition build.h:512
#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:407
#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:217
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1352
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1906
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1338
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:692
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:626
#define cf_lineno(_cf)
Definition cf_util.h:121
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:300
#define cf_item_next(_parent, _curr)
Definition cf_util.h:94
#define cf_filename(_cf)
Definition cf_util.h:124
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:68
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:131
#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:202
#define MEM(x)
Definition debug.h:36
#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:2172
talloc_free(hp)
void unlang_interpret_request_prioritise(request_t *request, uint32_t priority)
Definition interpret.c:1657
static size_t unlang_action_table_len
Definition interpret.c:388
void stack_dump_with_actions(request_t *request)
Definition interpret.c:589
static fr_table_num_ordered_t const unlang_frame_action_table[]
Definition interpret.c:390
static void unlang_interpret_request_detach(request_t *request)
Tell the interpreter to detach the request.
Definition interpret.c:1643
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:1291
bool unlang_request_is_done(request_t const *request)
Return whether a request has been marked done.
Definition interpret.c:1960
static void stack_dump_body(request_t *request, bool with_actions)
Definition interpret.c:569
static unlang_group_t empty_group
Definition interpret.c:1489
unlang_result_t * unlang_interpret_result(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1935
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:413
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:2384
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1878
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1612
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:1071
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:2392
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:2401
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1903
int unlang_thread_instantiate(TALLOC_CTX *ctx)
Create thread-specific data structures for unlang.
Definition interpret.c:63
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1990
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition interpret.c:2163
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:2035
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1943
static char const unlang_spaces[]
Definition interpret.c:58
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition interpret.c:2441
void stack_dump(request_t *request)
Definition interpret.c:584
p_result_location_t
Definition interpret.c:400
@ P_RESULT_LOCATION_FRAME
Definition interpret.c:402
@ P_RESULT_LOCATION_FUNCTION_RCTX
Definition interpret.c:406
@ P_RESULT_LOCATION_UNKNOWN
Definition interpret.c:401
@ P_RESULT_LOCATION_SCRATCH
Definition interpret.c:403
@ P_RESULT_LOCATION_MODULE_RCTX
Definition interpret.c:405
@ P_RESULT_LOCATION_STATE
Definition interpret.c:404
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:2434
fr_dict_t const * old_dict
the previous dictionary for the request
Definition interpret.c:677
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition interpret.c:1575
unlang_t const * unlang_interpret_instruction(request_t *request)
Get the current instruction.
Definition interpret.c:321
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition interpret.c:2423
static fr_table_num_ordered_t const p_result_location_table[]
Definition interpret.c:473
#define DUMP_STACK
Definition interpret.c:593
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:1925
static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1844
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:2351
static void instruction_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1860
uint64_t unlang_number
Definition interpret.c:54
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition interpret.c:1953
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:1547
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:2065
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1771
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition interpret.c:2050
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:1524
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:787
static fr_table_num_ordered_t const unlang_action_table[]
Definition interpret.c:381
static int _local_variables_free(unlang_variable_ref_t *ref)
Definition interpret.c:682
static size_t p_result_location_table_len
Definition interpret.c:480
static void instruction_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:482
bool unlang_interpret_is_resumable(request_t *request)
Check if a request as resumable.
Definition interpret.c:1972
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:616
int unlang_interpret_force_result(unlang_t const *instruction, unlang_result_t *p_result, fr_timer_list_t *tl, fr_time_delta_t expire)
Set (or clear) a forced result.
Definition interpret.c:344
static void instruction_done_debug(request_t *request, unlang_stack_frame_t *frame, unlang_t const *instruction)
Definition interpret.c:1027
fr_rb_tree_t * unlang_instruction_tree
Definition compile.c:64
request_t * request
the request
Definition interpret.c:679
static void forced_result_expiry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:332
void unlang_interpret_request_cancel_retry(request_t *request)
Cancel any pending retry.
Definition interpret.c:1675
static unlang_thread_t * unlang_thread_data(unlang_t const *instruction)
Get the thread-instance data for an instruction.
Definition interpret.c:124
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:997
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:1706
void * unlang_thread_instance(unlang_t const *instruction)
Get the thread-instance data for an instruction.
Definition interpret.c:110
static _Thread_local unlang_thread_t * unlang_thread_array
Definition interpret.c:51
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:2085
static size_t unlang_frame_action_table_len
Definition interpret.c:395
rlm_rcode_t unlang_interpret_rcode(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1915
static void frame_dump(request_t *request, unlang_stack_frame_t *frame, bool with_actions)
Definition interpret.c:511
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:720
static void actions_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:497
static _Thread_local unlang_interpret_t * intp_thread_default
The default interpreter instance for this thread.
Definition interpret.c:44
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2411
fr_dict_t const * to_free_dict
Free entries matching this dictionary.
Definition interpret.c:678
unlang_result_t default_result
The default result for the frame.
Definition interpret.h:151
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:40
unlang_request_prioritise_t prioritise
Function to re-prioritise a request in the runnable queue.
Definition interpret.h:134
unlang_mod_action_t priority
The priority or action for that rcode.
Definition interpret.h:141
#define UNLANG_RESULT_NOT_SET
Definition interpret.h:144
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:157
unlang_request_done_t done_internal
Function called when an internal request completes.
Definition interpret.h:124
#define UNLANG_FRAME_POOL_SIZE
total size of all frame states
Definition interpret.h:43
unlang_request_resume_t resume
Function called when a request is resumed.
Definition interpret.h:129
#define UNLANG_SUB_FRAME
Definition interpret.h:37
unlang_request_done_t done_external
Function called when a external request completes.
Definition interpret.h:123
unlang_request_init_t detach
Function called when a request is detached.
Definition interpret.h:127
unlang_request_runnable_t mark_runnable
Function called when a request needs to be added back to the runnable queue.
Definition interpret.h:130
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:139
unlang_request_yield_t yield
Function called when a request yields.
Definition interpret.h:128
unlang_request_done_t done_detached
Function called when a detached request completes.
Definition interpret.h:125
unlang_request_scheduled_t scheduled
Function to check if a request is already scheduled.
Definition interpret.h:132
#define UNLANG_RESULT_RCODE(_x)
Definition interpret.h:145
unlang_request_init_t init_internal
Function called to initialise an internal request.
Definition interpret.h:121
struct unlang_interpret_s unlang_interpret_t
Interpreter handle.
Definition interpret.h:53
Configuration structure to make it easier to pass configuration options to initialise the frame with.
Definition interpret.h:149
External functions provided by the owner of the interpret.
Definition interpret.h:115
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
#define fr_time()
Definition event.c:60
Stores all information relating to an event list.
Definition event.c:377
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:616
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:56
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
void * fr_rb_iter_init_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Initialise an in-order iterator.
Definition rb.c:824
void * fr_rb_iter_next_inorder(UNUSED fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Return the next node.
Definition rb.c:850
Iterator structure for in-order traversal of an rbtree.
Definition rb.h:319
The main red black tree structure.
Definition rb.h:71
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:311
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
Definition request.h:180
@ REQUEST_TYPE_INTERNAL
A request generated internally.
Definition request.h:181
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
Definition request.h:182
#define request_is_detachable(_x)
Definition request.h:189
@ REQUEST_DONE
Request has completed.
Definition request.h:91
@ REQUEST_STOP_PROCESSING
Request has been signalled to stop.
Definition request.h:90
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.
static char const * name
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
Definition log.h:93
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:804
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:208
static fr_time_delta_t fr_time_delta_add(fr_time_delta_t a, fr_time_delta_t b)
Definition time.h:255
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
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_TRACKING_YIELDED
We're currently tracking time in the yielded state.
static void fr_time_tracking_yield(fr_time_tracking_t *tt, fr_time_t now)
Transition to the yielded state, recording the time we just spent running.
static void fr_time_tracking_end(fr_time_delta_t *predicted, fr_time_tracking_t *tt, fr_time_t now)
End time tracking for this entity.
static void fr_time_tracking_start(fr_time_tracking_t *parent, fr_time_tracking_t *tt, fr_time_t now)
Start time tracking for a tracked entity.
static void fr_time_tracking_resume(fr_time_tracking_t *tt, fr_time_t now)
Track that a request resumed.
fr_time_t fr_timer_when(fr_timer_t *ev)
Internal timestamp representing when the timer should fire.
Definition timer.c:719
int fr_timer_delete(fr_timer_t **ev_p)
Delete a timer event and free its memory.
Definition timer.c:692
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)
CONF_SECTION * cs
#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.
char const * thread_inst_type
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.
#define unlang_frame_perf_init(_x)
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.
#define unlang_list_foreach(_list_head, _iter)
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)
unsigned int number
unique node number
static unlang_stack_frame_t * frame_current(request_t *request)
unlang_list_t children
fr_timer_t * ev
run on expiry
static bool is_private_result(unlang_stack_frame_t const *frame)
char const * name
Unknown...
bool use_forced_result
Do we force a result for this module?
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_POLICY
Policy section.
Definition unlang_priv.h:79
@ 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
#define debug_braces(_type)
unlang_t const * instruction
instruction which we're executing
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.
unlang_result_t forced_result
the result to force
unlang_thread_instantiate_t thread_instantiate
per-thread instantiation function
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,...
size_t thread_inst_size
unlang_list_t * list
so we have fewer run-time dereferences
static bool is_unwinding(unlang_stack_frame_t const *frame)
void * thread_inst
thread-specific instance data
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
#define fr_strerror_const(_msg)
Definition strerror.h:223
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:4619
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:4838
#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
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
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:216