The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: 948581a3f67321115a3f343113648cff43b2e989 $
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: 948581a3f67321115a3f343113648cff43b2e989 $")
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 char const *name2;
1536 char const *space = " ";
1537
1538 name2 = cf_section_name2(cs);
1539 if (!name2) name2 = space = "";
1540
1541 REDEBUG("Cannot interpret section at %s[%d]", cf_filename(cs), cf_lineno(cs));
1542 REDEBUG("Failed to find pre-compiled unlang for section %s%s%s%s{ ... }",
1543 cf_section_name1(cs), space, name2, space);
1544 return -1;
1545 }
1546 }
1547
1548 return unlang_interpret_push_instruction(p_result, request, instruction, conf);
1549}
1550
1551/** Push an instruction onto the request stack for later interpretation.
1552 *
1553 */
1555{
1556 unlang_stack_t *stack = request->stack;
1557
1558 if (!instruction) {
1559 instruction = unlang_group_to_generic(&empty_group);
1560 }
1561
1562 /*
1563 * Push the default action, and the instruction which has
1564 * no action.
1565 */
1566 if (unlang_interpret_push(p_result, request, instruction, conf, UNLANG_NEXT_SIBLING) < 0) {
1567 return -1;
1568 }
1569
1570 RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
1571
1572 return 0;
1573}
1574
1575/** Allocate a new unlang stack
1576 *
1577 * @param[in] ctx to allocate stack in.
1578 * @return
1579 * - A new stack on success.
1580 * - NULL on OOM.
1581 */
1582void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
1583{
1584 /*
1585 * Should never be evaluated, is just here to reduce
1586 * branches, so we don't need to check for frame->instruction.
1587 */
1588 static unlang_t unlang_instruction = {
1589 .debug_name = "top",
1590 .actions = DEFAULT_MOD_ACTIONS,
1591 };
1592
1594
1595 /*
1596 * If we have talloc_pooled_object allocate the stack as
1597 * a combined chunk/pool, with memory to hold at mutable
1598 * state data for the of the stack frames.
1599 *
1600 * Having a dedicated pool for mutable stack data
1601 * means we don't have memory fragmentations issues
1602 * as we would if request were used as the pool.
1603 *
1604 * This number is pretty arbitrary, but it seems
1605 * like too low level to make into a tuneable.
1606 */
1608 stack->frame[0].p_result = &stack->frame[0].section_result;
1609 stack->frame[0].scratch_result = UNLANG_RESULT_NOT_SET;
1610 stack->frame[0].section_result = UNLANG_RESULT_NOT_SET;
1611 stack->frame[0].instruction = &unlang_instruction; /* The top frame has no instruction, so we use a dummy one */
1612
1613 return stack;
1614}
1615
1616/** Indicate to the caller of the interpreter that this request is complete
1617 *
1618 */
1620{
1621 unlang_stack_t *stack = request->stack;
1622 unlang_interpret_t *intp;
1623
1624 if (!fr_cond_assert(stack != NULL)) return;
1625
1626 intp = stack->intp;
1627
1628 request->master_state = REQUEST_DONE;
1629 switch (request->type) {
1631 intp->funcs.done_external(request, frame_current(request)->section_result.rcode, intp->uctx);
1632 break;
1633
1635 intp->funcs.done_internal(request, frame_current(request)->section_result.rcode, intp->uctx);
1636 break;
1637
1639 intp->funcs.done_detached(request, frame_current(request)->section_result.rcode, intp->uctx); /* Callback will usually free the request */
1640 break;
1641 }
1642}
1643
1644/** Tell the interpreter to detach the request
1645 *
1646 * This function should not be called directly use unlang_interpret_signal(request, FR_SIGNAL_DETACH) instead.
1647 * This will ensure all frames on the request's stack receive the detach signal.
1648 */
1649static inline CC_HINT(always_inline)
1651{
1652 unlang_stack_t *stack = request->stack;
1653 unlang_interpret_t *intp;
1654
1655 if (!fr_cond_assert(stack != NULL)) return;
1656
1657 if (!request_is_detachable(request)) return;
1658
1659 intp = stack->intp;
1660
1661 intp->funcs.detach(request, intp->uctx);
1662}
1663
1665{
1666 unlang_stack_t *stack = request->stack;
1667 unlang_interpret_t *intp;
1668
1669 if (!fr_cond_assert(stack != NULL)) return;
1670
1671 intp = stack->intp;
1672
1673 request->priority = priority;
1674
1675 if (intp->funcs.prioritise) intp->funcs.prioritise(request, intp->uctx);
1676}
1677
1678/** Cancel any pending retry
1679 *
1680 * @param[in] request The current request.
1681 */
1683{
1684 unlang_stack_t *stack = request->stack;
1685 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1686
1687 TALLOC_FREE(frame->retry);
1688}
1689
1690
1691/** Delivers a frame to one or more frames in the stack
1692 *
1693 * This is typically called via an "async" action, i.e. an action outside
1694 * of the normal processing of the request.
1695 *
1696 * For FR_SIGNAL_CANCEL all frames are marked up for cancellation, but the
1697 * cancellation is handled by the interpret.
1698 *
1699 * Other signal types are delivered immediately, inrrespecitve of whether
1700 * the request is currently being processed or not.
1701 *
1702 * Signaling stops at the "limit" frame. This is so that keywords
1703 * such as "timeout" and "limit" can signal frames *lower* than theirs
1704 * to stop, but then continue with their own work.
1705 *
1706 * @note It's better (clearer) to use one of the unwind_* functions
1707 * unless the entire request is being cancelled.
1708 *
1709 * @param[in] request The current request.
1710 * @param[in] action to signal.
1711 * @param[in] limit the frame at which to stop signaling.
1712 */
1713void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
1714{
1715 unlang_stack_frame_t *frame;
1716 unlang_stack_t *stack = request->stack;
1717 int i, depth = stack->depth;
1718
1719 (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1720
1721 fr_assert(stack->depth >= 1);
1722
1723 /*
1724 * Does not complete the unwinding here, just marks
1725 * up the frames for unwinding. The request must
1726 * be marked as runnable to complete the cancellation.
1727 */
1728 if (action == FR_SIGNAL_CANCEL) unwind_to_depth(stack, limit);
1729
1730 /*
1731 * Walk back up the stack, calling signal handlers
1732 * to cancel any pending operations and free/release
1733 * any resources.
1734 *
1735 * There may be multiple resumption points in the
1736 * stack, as modules can push xlats and function
1737 * calls.
1738 *
1739 * Note: Slightly confusingly, a cancellation signal
1740 * can still be delivered to a frame that is not
1741 * cancellable, but the frame won't be automatically
1742 * unwound.
1743 */
1744 for (i = depth; i >= limit; i--) {
1745 frame = &stack->frame[i];
1746 if (frame->signal) {
1747 frame->signal(request, frame, action);
1748
1749 /*
1750 * Once the cancellation function has been
1751 * called, the frame is no longer in a state
1752 * where it can accept further signals.
1753 */
1754 if (action == FR_SIGNAL_CANCEL) frame->signal = NULL;
1755
1756 /*
1757 * If the frame is cancelled, we don't do any retries.
1758 */
1759 TALLOC_FREE(frame->retry);
1760 }
1761 }
1762}
1763
1764/** Send a signal (usually stop) to a request
1765 *
1766 * This is typically called via an "async" action, i.e. an action
1767 * outside of the normal processing of the request.
1768 *
1769 * @note This does NOT immediately stop the request, it just deliveres
1770 * signals, and in the case of a cancel, marks up frames for unwinding
1771 * and adds it to the runnable queue if it's yielded.
1772 *
1773 * @note This function should be safe to call anywhere.
1774 *
1775 * @param[in] request The current request.
1776 * @param[in] action to signal.
1777 */
1779{
1780 unlang_stack_t *stack = request->stack;
1781
1782 switch (action) {
1783 case FR_SIGNAL_DETACH:
1784 /*
1785 * Ensure the request is able to be detached
1786 * else don't signal.
1787 */
1788 if (!fr_cond_assert(request_is_detachable(request))) return;
1789 break;
1790
1791 default:
1792 break;
1793 }
1794
1795 /*
1796 * Requests that haven't been run through the interpreter
1797 * yet should have a stack depth of zero, so we don't
1798 * need to do anything.
1799 */
1800 if (!stack || stack->depth == 0) return;
1801
1802 unlang_stack_signal(request, action, 1);
1803
1804 switch (action) {
1805 case FR_SIGNAL_CANCEL:
1806 {
1807 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1808 /*
1809 * Let anything that cares, know that the
1810 * request was forcefully stopped.
1811 */
1812 request->master_state = REQUEST_STOP_PROCESSING;
1813
1814 /*
1815 * Give cancelled requests the highest priority
1816 * to get them to release resources ASAP.
1817 */
1818 unlang_interpret_request_prioritise(request, UINT32_MAX);
1819
1820 /*
1821 * If the request is yielded, mark it as runnable
1822 *
1823 * If the request was _not_ cancelled, it means
1824 * it's not cancellable, and we need to let the
1825 * request progress normally.
1826 *
1827 * A concrete example of this, is the parent of
1828 * subrequests, which must not continue until
1829 * the subrequest is done.
1830 */
1831 if (stack && is_yielded(frame) && is_unwinding(frame) && !unlang_request_is_scheduled(request)) {
1833 }
1834 }
1835 break;
1836
1837 case FR_SIGNAL_DETACH:
1838 /*
1839 * Cleanup any cross-request pointers, and mark the
1840 * request as detached. When the request completes it
1841 * should by automatically freed.
1842 */
1844 break;
1845
1846 default:
1847 break;
1848 }
1849}
1850
1852{
1853 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1854 request_t *request = talloc_get_type_abort(retry->request, request_t);
1855
1856 RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1857
1858 /*
1859 * Signal all lower frames to exit.
1860 */
1861 unlang_stack_signal(request, FR_SIGNAL_CANCEL, retry->depth + 1);
1862
1863 retry->state = FR_RETRY_MRD;
1865}
1866
1868{
1869 request_t *request = talloc_get_type_abort(ctx, request_t);
1870
1871 RDEBUG("Maximum timeout reached, signalling interpreter to stop the request.");
1872
1873 /*
1874 * Stop the entire request.
1875 */
1877}
1878
1879
1880/** Set a timeout for a request.
1881 *
1882 * The timeout is associated with the current stack frame.
1883 *
1884 */
1886{
1887 unlang_stack_t *stack = request->stack;
1888 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1889 unlang_retry_t *retry;
1890
1891 fr_assert(!frame->retry);
1893
1894 frame->retry = retry = talloc_zero(stack, unlang_retry_t);
1895 if (!frame->retry) return -1;
1896
1897 retry->request = request;
1898 retry->depth = stack->depth;
1899 retry->state = FR_RETRY_CONTINUE;
1900 retry->count = 1;
1901
1902 return fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, timeout,
1903 false, instruction_timeout_handler, request);
1904}
1905
1906
1907/** Return the depth of the request's stack
1908 *
1909 */
1911{
1912 unlang_stack_t *stack = request->stack;
1913
1914 return stack->depth;
1915}
1916
1917/** Get the last instruction result OR the last frame that was popped
1918 *
1919 * @param[in] request The current request.
1920 * @return the current rcode for the frame.
1921 */
1923{
1924 return frame_current(request)->p_result->rcode;
1925}
1926
1927/** Get the last instruction priority OR the last frame that was popped
1928 *
1929 * @param[in] request The current request.
1930 * @return the current rcode for the frame.
1931 */
1936
1937/** Get the last instruction result OR the last frame that was popped
1938 *
1939 * @param[in] request The current request.
1940 * @return the current result for the frame.
1941 */
1943{
1944 return frame_current(request)->p_result;
1945}
1946
1947/** Return whether a request is currently scheduled
1948 *
1949 */
1951{
1952 unlang_stack_t *stack = request->stack;
1953 unlang_interpret_t *intp = stack->intp;
1954
1955 return intp->funcs.scheduled(request, intp->uctx);
1956}
1957
1958/** Return whether a request has been cancelled
1959 */
1961{
1962 return (request->master_state == REQUEST_STOP_PROCESSING);
1963}
1964
1965/** Return whether a request has been marked done
1966 */
1968{
1969 return (request->master_state == REQUEST_DONE);
1970}
1971
1972/** Check if a request as resumable.
1973 *
1974 * @param[in] request The current request.
1975 * @return
1976 * - true if the request is resumable (i.e. has yielded)
1977 * - false if the request is not resumable (i.e. has not yielded)
1978 */
1980{
1981 unlang_stack_t *stack = request->stack;
1982 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1983
1984 return is_yielded(frame);
1985}
1986
1987/** Mark a request as resumable.
1988 *
1989 * It's not called "unlang_interpret", because it doesn't actually
1990 * resume the request, it just schedules it for resumption.
1991 *
1992 * @note that this schedules the request for resumption. It does not immediately
1993 * start running the request.
1994 *
1995 * @param[in] request The current request.
1996 */
1998{
1999 unlang_stack_t *stack = request->stack;
2000 unlang_interpret_t *intp = stack->intp;
2001 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
2002
2003 bool scheduled = unlang_request_is_scheduled(request);
2004
2005 /*
2006 * The request hasn't yielded, OR it's already been
2007 * marked as runnable. Don't do anything.
2008 *
2009 * The IO code, or children have no idea where they're
2010 * being called from. They just ask to mark the parent
2011 * resumable when they're done. So we have to check here
2012 * if this request is resumable.
2013 *
2014 * If the parent called the child directly, then the
2015 * parent hasn't yielded, so it isn't resumable. When
2016 * the child is done, the parent will automatically
2017 * continue running. We therefore don't need to insert
2018 * the parent into the backlog.
2019 *
2020 * Multiple child request may also mark a parent request
2021 * runnable, before the parent request starts running.
2022 */
2023 if (!is_yielded(frame) || scheduled) {
2024 RDEBUG3("Not marking request %s as runnable due to%s%s",
2025 request->name,
2026 !is_yielded(frame) ?
2027 " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
2028 return;
2029 }
2030
2031 RDEBUG3("Interpreter - Request marked as runnable");
2032
2033 intp->funcs.mark_runnable(request, intp->uctx);
2034}
2035
2036/** Get a talloc_ctx which is valid only for this frame
2037 *
2038 * @param[in] request The current request.
2039 * @return
2040 * - a TALLOC_CTX which is valid only for this stack frame
2041 */
2043{
2044 unlang_stack_t *stack = request->stack;
2045 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
2046
2047 if (frame->state) return (TALLOC_CTX *)frame->state;
2048
2049 /*
2050 * If the frame doesn't ordinarily have a
2051 * state, assume the caller knows what it's
2052 * doing and allocate one.
2053 */
2054 return (TALLOC_CTX *)(frame->state = talloc_new(stack));
2055}
2056
2058 { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
2060};
2061
2062static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
2063 UNUSED xlat_ctx_t const *xctx,
2064 request_t *request, fr_value_box_list_t *args);
2065
2066/** Signal the request to stop executing
2067 *
2068 * The request can't be running at this point because we're in the event
2069 * loop. This means the request is always in a consistent state when
2070 * the timeout event fires, even if that's state is waiting on I/O.
2071 */
2073{
2074 request_t *request = talloc_get_type_abort(uctx, request_t);
2075
2076 RDEBUG2("Request canceled by dynamic timeout");
2077 /*
2078 * Cleans up the memory allocated to hold
2079 * the pointer, not the event itself.
2080 */
2081 talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
2082
2084}
2085
2086/** Allows a request to dynamically alter its own lifetime
2087 *
2088 * %cancel(<timeout>)
2089 *
2090 * If timeout is 0, then the request is immediately cancelled.
2091 */
2093 UNUSED xlat_ctx_t const *xctx,
2094 request_t *request, fr_value_box_list_t *args)
2095{
2096 fr_value_box_t *timeout;
2098 fr_timer_t **ev_p, **ev_p_og;
2099 fr_value_box_t *vb;
2100 fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
2101
2102 fr_assert(el != NULL);
2103
2104 XLAT_ARGS(args, &timeout);
2105
2106 /*
2107 * No timeout means cancel immediately, so yield allowing
2108 * the interpreter to run the event we added to cancel
2109 * the request.
2110 *
2111 * We call unlang_xlat_yield to keep the interpreter happy
2112 * as it expects to see a resume function set.
2113 */
2114 if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
2116 return XLAT_ACTION_DONE;
2117 }
2118
2119 /*
2120 * First see if we already have a timeout event
2121 * that was previously added by this xlat.
2122 */
2123 ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
2124 if (ev_p) {
2125 fr_assert(*ev_p);
2126
2127 when = fr_timer_when(*ev_p);
2128 } else {
2129 /*
2130 * Must not be parented from the request
2131 * as this is freed by request data.
2132 */
2133 MEM(ev_p = talloc_zero(NULL, fr_timer_t *));
2134 }
2135
2136 if (unlikely(fr_timer_in(ev_p, el->tl, ev_p,
2137 timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
2138 false, unlang_cancel_event, request) < 0)) {
2139 RPERROR("Failed inserting cancellation event");
2140 talloc_free(ev_p);
2141 return XLAT_ACTION_FAIL;
2142 }
2143 if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
2144 UNCONST(fr_timer_t **, ev_p), true, true, false) < 0)) {
2145 RPERROR("Failed associating cancellation event with request");
2146 talloc_free(ev_p);
2147 return XLAT_ACTION_FAIL;
2148 }
2149
2150 if (ev_p_og) {
2151 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
2152
2153 /*
2154 * Return how long before the previous
2155 * cancel event would have fired.
2156 *
2157 * This can be useful for doing stacked
2158 * cancellations in policy.
2159 */
2160 vb->vb_time_delta = fr_time_sub(when, unlang_interpret_event_list(request)->tl->time());
2162 }
2163
2164 /*
2165 * No value if this is the first cleanup event
2166 */
2167 return XLAT_ACTION_DONE;
2168}
2169
2171 { .required = true, .single = true, .type = FR_TYPE_STRING },
2173};
2174
2175/** Get information about the interpreter state
2176 *
2177 * @ingroup xlat_functions
2178 */
2180 UNUSED xlat_ctx_t const *xctx,
2181 request_t *request, fr_value_box_list_t *in)
2182{
2183 unlang_stack_t *stack = request->stack;
2184 int depth = stack->depth;
2185 unlang_stack_frame_t *frame;
2186 unlang_t const *instruction;
2187 fr_value_box_t *arg = fr_value_box_list_head(in);
2188 char const *fmt = arg->vb_strvalue;
2189 fr_value_box_t *vb;
2190
2191 MEM(vb = fr_value_box_alloc_null(ctx));
2192
2193 /*
2194 * Find the correct stack frame.
2195 */
2196 while (*fmt == '.') {
2197 if (depth <= 1) {
2198 if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
2199 error:
2200 talloc_free(vb);
2201 return XLAT_ACTION_FAIL;
2202 }
2203 goto finish;
2204 }
2205
2206 fmt++;
2207 depth--;
2208 }
2209
2210 /*
2211 * Get the current instruction.
2212 */
2213 frame = &stack->frame[depth];
2214 instruction = frame->instruction;
2215
2216 /*
2217 * Nothing there...
2218 */
2219 if (!instruction) goto clear;
2220
2221 /*
2222 * How deep the current stack is.
2223 */
2224 if (strcmp(fmt, "depth") == 0) {
2225 fr_value_box_int32(vb, NULL, depth, false);
2226 goto finish;
2227 }
2228
2229 /*
2230 * The current module
2231 */
2232 if (strcmp(fmt, "module") == 0) {
2233 if (!request->module) goto clear;
2234
2235 if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
2236
2237 goto finish;
2238 }
2239
2240 /*
2241 * Name of the instruction.
2242 */
2243 if (strcmp(fmt, "name") == 0) {
2244 if (!instruction->name) goto clear;
2245
2246 if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
2247 strlen(instruction->name), false) < 0) goto error;
2248 goto finish;
2249 }
2250
2251 /*
2252 * The request processing stage.
2253 */
2254 if (strcmp(fmt, "processing_stage") == 0) {
2255 if (!request->component) goto clear;
2256
2257 if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
2258
2259 goto finish;
2260 }
2261
2262 /*
2263 * The current return code.
2264 */
2265 if (strcmp(fmt, "rcode") == 0) {
2266 if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
2267
2268 goto finish;
2269 }
2270
2271 /*
2272 * The virtual server handling the request
2273 */
2274 if (strcmp(fmt, "server") == 0) {
2275 request_t *our_request;
2276 CONF_SECTION *server = NULL;
2277
2278 /*
2279 * If we're being pedantic subrequests don't have a virtual
2280 * server associated with them unless they go call {}.
2281 *
2282 * But we're not being pendantic, so go back up the request
2283 * list ooking for a call frame.
2284 *
2285 * Unfortunately for detached subrequests we still won't find
2286 * the actual virtual server...
2287 */
2288 for (our_request = request; our_request && server == NULL; our_request = our_request->parent) {
2289 server = unlang_call_current(our_request);
2290 }
2291 if (server == NULL) goto finish;
2292
2293 if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(server), false) < 0) goto error;
2294
2295 goto finish;
2296 }
2297
2298 /*
2299 * Unlang instruction type.
2300 */
2301 if (strcmp(fmt, "type") == 0) {
2302 if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
2303 strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
2304
2305 goto finish;
2306 }
2307
2308 /*
2309 * All of the remaining things need a CONF_ITEM.
2310 */
2311 if (!instruction->ci) {
2312 if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 9, false) < 0) goto error;
2313
2314 goto finish;
2315 }
2316
2317 /*
2318 * Line number of the current section.
2319 */
2320 if (strcmp(fmt, "line") == 0) {
2321 fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
2322
2323 goto finish;
2324 }
2325
2326 /*
2327 * Filename of the current section.
2328 */
2329 if (strcmp(fmt, "filename") == 0) {
2330 if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
2331
2332 goto finish;
2333 }
2334
2335finish:
2336 if (vb->type != FR_TYPE_NULL) {
2338 } else {
2339 clear:
2340 talloc_free(vb);
2341 }
2342
2343 return XLAT_ACTION_DONE;
2344}
2345
2346/** Initialize a unlang compiler / interpret.
2347 *
2348 * @param[in] ctx to bind lifetime of the interpret to.
2349 * Shouldn't be any free order issues here as
2350 * the interpret itself has no state.
2351 * But event loop should be stopped before
2352 * freeing the interpret.
2353 * @param[in] el for any timer or I/O events.
2354 * @param[in] funcs Callbacks to used to communicate request
2355 * state to our owner.
2356 * @param[in] uctx Data to pass to callbacks.
2357 */
2359 fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
2360{
2361 unlang_interpret_t *intp;
2362
2363 fr_assert(funcs->init_internal);
2364
2365 fr_assert(funcs->done_internal);
2366 fr_assert(funcs->done_detached);
2367 fr_assert(funcs->done_external);
2368
2369 fr_assert(funcs->detach);
2370 fr_assert(funcs->yield);
2371 fr_assert(funcs->resume);
2372 fr_assert(funcs->mark_runnable);
2373 fr_assert(funcs->scheduled);
2374
2375 MEM(intp = talloc(ctx, unlang_interpret_t));
2376 *intp = (unlang_interpret_t){
2377 .el = el,
2378 .funcs = *funcs,
2379 .uctx = uctx
2380 };
2381
2382 return intp;
2383}
2384
2385/** Discard the bottom most frame on the request's stack
2386 *
2387 * This is used for cleaning up after errors. i.e. the caller
2388 * uses a push function, and experiences an error and needs to
2389 * remove the frame that was just pushed.
2390 */
2392{
2393 frame_pop(request, request->stack);
2394}
2395
2396/** Set a specific interpreter for a request
2397 *
2398 */
2400{
2401 unlang_stack_t *stack = request->stack;
2402 stack->intp = intp;
2403}
2404
2405/** Get the interpreter set for a request
2406 *
2407 */
2409{
2410 unlang_stack_t *stack = request->stack;
2411
2412 return stack->intp;
2413}
2414
2415/** Get the event list for the current interpreter
2416 *
2417 */
2419{
2420 unlang_stack_t *stack = request->stack;
2421
2422 if (!stack->intp) return NULL;
2423
2424 return stack->intp->el;
2425}
2426
2427/** Set the default interpreter for this thread
2428 *
2429 */
2431{
2432 if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
2433
2434 intp_thread_default = intp;
2435}
2436
2437/** Get the default interpreter for this thread
2438 *
2439 * This allows detached requests to be executed asynchronously
2440 */
2442{
2443 if (!intp_thread_default) return NULL;
2444
2445 return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
2446}
2447
2449{
2450 xlat_t *xlat;
2451 /*
2452 * Should be void, but someone decided not to register multiple xlats
2453 * breaking the convention we use everywhere else in the server...
2454 */
2455 if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2457
2458 if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2460
2461 return 0;
2462}
#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:1359
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1913
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1345
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:67
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:2179
talloc_free(hp)
void unlang_interpret_request_prioritise(request_t *request, uint32_t priority)
Definition interpret.c:1664
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:1650
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:1967
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:1942
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:2391
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1885
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1619
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:2399
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:2408
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1910
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:1997
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition interpret.c:2170
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:2042
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1950
static char const unlang_spaces[]
Definition interpret.c:58
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition interpret.c:2448
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:2441
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:1582
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:2430
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:1932
static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1851
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:2358
static void instruction_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1867
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:1960
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:1554
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:2072
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1778
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition interpret.c:2057
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:1979
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:63
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:1682
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:1713
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:2092
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:1922
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:2418
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