The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
interpret.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: e9a2e4b743028943788bd11d0faf893917e87b81 $
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: e9a2e4b743028943788bd11d0faf893917e87b81 $")
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
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 request_t *request; //!< the request
680
682{
683 fr_pair_t *vp, *prev;
684
685 /*
686 * Local variables are appended to the end of the list. So we remove them by walking backwards
687 * from the end of the list.
688 */
689 vp = fr_pair_list_tail(&ref->request->local_pairs);
690 while (vp) {
691 fr_assert(vp->da->flags.local);
692
693 prev = fr_pair_list_prev(&ref->request->local_pairs, vp);
694 if (vp->da->dict != ref->request->local_dict) {
695 break;
696 }
697
698 (void) fr_pair_delete(&ref->request->local_pairs, vp);
699 vp = prev;
700 }
701
702 ref->request->local_dict = ref->old_dict;
703
704 return 0;
705}
706
707/** Push the children of the current frame onto a new frame onto the stack
708 *
709 * @param[out] p_result set to RLM_MODULE_FAIL if pushing the children fails
710 * @param[in] request to push the frame onto.
711 * @param[in] default_rcode The default result.
712 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
713 * or to execute subsequent nodes.
714 * @return
715 * - UNLANG_ACTION_PUSHED_CHILD on success.
716 * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
717 * - UNLANG_ACTION_FAIL, fatal error, usually stack overflow.
718 */
720 rlm_rcode_t default_rcode, bool do_next_sibling)
721{
722 unlang_stack_t *stack = request->stack;
723 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
726
728
730
731 /*
732 * The compiler catches most of these, EXCEPT for the
733 * top-level 'recv Access-Request' etc. Which can exist,
734 * and can be empty.
735 */
736 if (unlang_list_empty(&g->children)) {
737 RDEBUG2("... ignoring empty subsection ...");
739 }
740
741 if (unlang_interpret_push(p_result, request, unlang_list_head(&g->children),
742 FRAME_CONF(default_rcode, UNLANG_SUB_FRAME), do_next_sibling) < 0) {
744 }
745
747
748 /*
749 * Note that we do NOT create the variables, This way we don't have to worry about any
750 * uninitialized values. If the admin tries to use the variable without initializing it, they
751 * will get a "no such attribute" error.
752 */
753 if (!frame->state) {
754 MEM(ref = talloc(stack, unlang_variable_ref_t));
755 frame->state = ref;
756 } else {
757 MEM(ref = talloc(frame->state, unlang_variable_ref_t));
758 }
759
760 /*
761 * Set the destructor to clean up local variables.
762 */
763 ref->request = request;
764 ref->old_dict = request->local_dict;
765 request->local_dict = g->variables->dict;
766 talloc_set_destructor(ref, _local_variables_free);
767
769}
770
771static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx);
772
773/** Update the current result after each instruction, and after popping each stack frame
774 *
775 * @note Sets stack->scratch to be the the result of the frame being popped.
776 *
777 * @param[in] request The current request.
778 * @param[in] frame The current stack frame.
779 * @param[in] result from the previous action.
780 * @return
781 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions.
782 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
783 */
784static inline CC_HINT(always_inline)
786{
787 unlang_t const *instruction = frame->instruction;
788 unlang_stack_t *stack = request->stack;
789 unlang_result_t *frame_result = frame->p_result;
790
791 if (is_unwinding(frame)) {
792 RDEBUG4("** [%i] %s - unwinding frame", stack->depth, __FUNCTION__);
794 }
795
796 /*
797 * Don't calculate a new return code for the frame, just skip
798 * to the next instruction.
799 */
800 if (result->rcode == RLM_MODULE_NOT_SET) {
801 RDEBUG4("** [%i] %s - skipping frame, no result set",
802 stack->depth, __FUNCTION__);
804 }
805
806 fr_assert(MOD_ACTION_VALID(frame_result->priority));
807 fr_assert(MOD_ACTION_VALID(result->priority));
808
809 RDEBUG4("** [%i] %s - have (%s %s) frame or module returned (%s %s)",
810 stack->depth, __FUNCTION__,
811 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
812 mod_action_name[frame_result->priority],
813 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
814 mod_action_name[result->priority]);
815
816 /*
817 * Update request->rcode if the instruction says we should
818 * We don't care about priorities for this.
819 *
820 * This is the field that's evaluated in unlang conditions
821 * like `if (ok)`.
822 */
823 if (is_rcode_set(frame) && (request->rcode != result->rcode)) {
824 RDEBUG3("Setting request->rcode to '%s'",
825 fr_table_str_by_value(rcode_table, result->rcode, "<INVALID>"));
826 request->rcode = result->rcode;
827 }
828
829 /*
830 * The array holds a default priority for this return
831 * code. Grab it in preference to any unset priority.
832 */
833 if (result->priority == MOD_ACTION_NOT_SET) {
834 result->priority = instruction->actions.actions[result->rcode];
835
836 fr_assert(MOD_ACTION_VALID(result->priority));
837
838 RDEBUG4("** [%i] %s - using default instruction priority for %s, %s",
839 stack->depth, __FUNCTION__,
840 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
841 mod_action_name[result->priority]);
842 }
843
844 /*
845 * Deal with special priorities which indicate we need
846 * to do something in addition to modifying the frame's
847 * rcode.
848 */
849 switch (result->priority) {
850 /*
851 * The child's prioriy value indicates we
852 * should return from this frame.
853 */
855 RDEBUG4("** [%i] %s - action says to return with (%s %s)",
856 stack->depth, __FUNCTION__,
857 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
858 mod_action_name[result->priority]);
859
860 *frame_result = UNLANG_RESULT_RCODE(result->rcode);
862
863 /*
864 * Reject means we should return, but
865 * with a reject rcode. This allows the
866 * user to change normally positive rcodes
867 * into negative ones.
868 *
869 * They could also just check the rcode
870 * after the module returns...
871 */
873 RDEBUG4("** [%i] %s - action says to return with (%s %s)",
874 stack->depth, __FUNCTION__,
876 mod_action_name[result->priority]);
877
878 *frame_result = UNLANG_RESULT_RCODE(RLM_MODULE_REJECT);
880
881 case MOD_ACTION_RETRY:
882 {
883 unlang_retry_t *retry = frame->retry;
884
885 RDEBUG4("** [%i] %s - action says to retry with",
886 stack->depth, __FUNCTION__);
887
888 /*
889 * If this is the first time doing the retry,
890 * then allocate the structure and set the timer.
891 */
892 if (!retry) {
893 MEM(frame->retry = retry = talloc_zero(stack, unlang_retry_t));
894
895 retry->request = request;
896 retry->depth = stack->depth;
897 retry->state = FR_RETRY_CONTINUE;
898 retry->count = 1;
899
900 /*
901 * Set a timer which automatically fires
902 * if there's a timeout. And parent it
903 * from the retry structure, so that the
904 * timer is automatically freed when the
905 * frame is cleaned up.
906 */
907 if (fr_time_delta_ispos(instruction->actions.retry.mrd)) {
908 if (fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, instruction->actions.retry.mrd,
909 false, instruction_retry_handler, retry) < 0) {
910 RPEDEBUG("Failed inserting retry event");
911 *frame_result = UNLANG_RESULT_RCODE(RLM_MODULE_FAIL);
912 goto finalize;
913 }
914 }
915
916 } else {
917 /*
918 * We've been told to stop doing retries,
919 * probably from a timeout.
920 */
921 if (retry->state != FR_RETRY_CONTINUE) goto timeout;
922
923 /*
924 * Clamp it at the maximum count.
925 */
926 if (instruction->actions.retry.mrc > 0) {
927 retry->count++;
928
929 if (retry->count >= instruction->actions.retry.mrc) {
930 retry->state = FR_RETRY_MRC;
931
932 REDEBUG("Retries hit max_rtx_count (%u) - returning 'timeout'", instruction->actions.retry.mrc);
933
934 timeout:
936 goto finalize;
937 }
938 }
939 }
940
941 RINDENT();
942 if (instruction->actions.retry.mrc) {
943 RDEBUG("... retrying (%u/%u)", retry->count, instruction->actions.retry.mrc);
944 } else {
945 RDEBUG("... retrying");
946 }
947 REXDENT();
948
949 TALLOC_FREE(frame->state);
951 frame_state_init(stack, frame); /* Don't change p_result */
953 }
954
955 default:
956 break;
957 }
958
959finalize:
960 /*
961 * We're higher or equal to previous priority, remember this
962 * return code and priority.
963 */
964 if (result->priority >= frame_result->priority) {
965 fr_assert(MOD_ACTION_VALID(result->priority));
966 fr_assert(MOD_ACTION_VALID(frame_result->priority));
967
968 RDEBUG4("** [%i] %s - overwriting existing result (%s %s) with higher priority (%s %s)",
969 stack->depth, __FUNCTION__,
970 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
971 mod_action_name[frame_result->priority],
972 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
973 mod_action_name[result->priority]);
974 *frame->p_result = *result;
975 }
976
977 /*
978 * Determine if we should continue processing siblings
979 * or pop the frame ending the section.
980 */
982}
983
984/** Function called to merge inter-stack-frame results
985 *
986 * This function is called whenever a frame is popped from the stack.
987 *
988 * 'result' is the result from the frame being popped, and 'frame' is the next highest frame in the stack.
989 *
990 * The logic here is very similar to result_eval(), with two important differences:
991 * - The priority of the lower frame is ignored, and the default priority of the higher frame is used.
992 * Unless the higher frame's priority is MOD_ACTION_NOT_SET, in which case the lower frame's priority is used.
993 */
994static inline CC_HINT(always_inline)
996{
997 unlang_stack_t *stack = request->stack;
998 unlang_result_t our_result = *result;
999
1000 fr_assert(MOD_ACTION_VALID(result->priority));
1001
1002 /*
1003 * When a stack frame is being popped, the priority of the
1004 * source (lower) frame is ignored, and the default priority
1005 * of the destination (higher) frame is used.
1006 *
1007 * We could (easily) add support for preserving the priority
1008 * from the lower frame, if the priority of the higher frame
1009 * was MOD_ACTION_NOT_SET, but there are no concrete use
1010 * cases for this yet.
1011 */
1012 if (result->rcode != RLM_MODULE_NOT_SET) {
1013 fr_assert(MOD_ACTION_VALID(frame->instruction->actions.actions[result->rcode]));
1014 our_result.priority = frame->instruction->actions.actions[result->rcode];
1015 }
1016
1017 RDEBUG4("** [%i] %s - using instruction priority for higher frame (%s, %s)",
1018 stack->depth, __FUNCTION__,
1019 fr_table_str_by_value(mod_rcode_table, our_result.rcode, "<invalid>"),
1020 mod_action_name[our_result.priority]);
1021
1022 return result_calculate(request, frame, &our_result);
1023}
1024
1025static inline CC_HINT(always_inline) void instruction_done_debug(request_t *request, unlang_stack_frame_t *frame, unlang_t const *instruction)
1026{
1027 if (has_debug_braces(instruction)) {
1028 REXDENT();
1029
1030 /*
1031 * If we're at debug level 1, don't emit the closing
1032 * brace as the opening brace wasn't emitted.
1033 *
1034 * Not a typo, we don't want to print the scratch_result
1035 * here, aka the ones the section actually returned,
1036 * vs the section result, which may have just been left
1037 * at defaults.
1038 */
1040 RDEBUG("# %s %s%s%s", frame->instruction->debug_name,
1041 frame->p_result == &frame->section_result ? "(" : "((",
1042 fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"),
1043 frame->p_result == &frame->section_result ? ")" : "))");
1044 } else {
1045 RDEBUG2("} # %s %s%s%s", frame->instruction->debug_name,
1046 frame->p_result == &frame->section_result ? "(" : "((",
1047 fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"),
1048 frame->p_result == &frame->section_result ? ")" : "))");
1049 }
1050 }
1051}
1052
1053/** Evaluates all the unlang nodes in a section
1054 *
1055 * This function interprets a list of unlang instructions at a given level using the same
1056 * stack frame, and pushes additional frames onto the stack as needed.
1057 *
1058 * This function can be seen as moving horizontally.
1059 *
1060 * @param[in] request The current request.
1061 * @param[in] frame The current stack frame.
1062 * @return
1063 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions in the current stack frame
1064 * which may not be the same frame as when this function
1065 * was called.
1066 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
1067 */
1068static inline CC_HINT(always_inline)
1070{
1071 unlang_stack_t *stack = request->stack;
1072 unlang_result_t *scratch = &frame->scratch_result;
1073
1074 /*
1075 * Loop over all the instructions in this list.
1076 */
1077 while (frame->instruction) {
1078 unlang_t const *instruction = frame->instruction;
1079 unlang_action_t ua;
1081 unlang_thread_t *thread_data;
1082
1083 DUMP_STACK;
1084
1085 fr_assert(instruction->debug_name != NULL); /* if this happens, all bets are off. */
1086 fr_assert(unlang_ops[instruction->type].interpret != NULL);
1087 fr_assert(frame->process != NULL);
1088
1089 REQUEST_VERIFY(request);
1090
1091 /*
1092 * We're running this frame, so it can't possibly be yielded.
1093 */
1094 if (is_yielded(frame)) {
1095 RDEBUG("%s - Resuming execution", instruction->debug_name);
1096 yielded_clear(frame);
1097 }
1098
1099#ifndef NDEBUG
1100 /*
1101 * Failure testing!
1102 */
1103 if (request->ins_max) {
1104 request->ins_count++;
1105
1106 if (request->ins_count >= request->ins_max) {
1107 RERROR("Failing request due to maximum instruction count %" PRIu64, request->ins_max);
1108
1110 }
1111 }
1112#endif
1113
1114 /*
1115 * We're not re-entering this frame, this is the first
1116 * time we're evaluating this instruction, so we should
1117 * print debug braces and indent.
1118 */
1119 if (!is_repeatable(frame)) {
1120 if (has_debug_braces(frame)) {
1121 RDEBUG2("%s {", instruction->debug_name);
1122 RINDENT();
1123 }
1124 /*
1125 * Clear the repeatable flag so this frame
1126 * won't get executed again unless it specifically
1127 * requests it.
1128 *
1129 * The flag may still be set again during the
1130 * process function to indicate that the frame
1131 * should be evaluated again.
1132 */
1133 } else {
1134 repeatable_clear(frame);
1135 }
1136
1137 /*
1138 * Execute an operation
1139 */
1140 RDEBUG4("** [%i] %s >> %s", stack->depth, __FUNCTION__,
1141 unlang_ops[instruction->type].name);
1142
1144
1145 /*
1146 * A module (or even a section) may be administratively down
1147 */
1148 if (unlikely(((thread_data = unlang_thread_data(instruction)) != NULL) &&
1149 thread_data->use_forced_result)) {
1150 frame->scratch_result = thread_data->forced_result;
1152
1153 } else {
1154 /*
1155 * catch plays games with the frame so we skip
1156 * to the next catch section at a given depth,
1157 * it's not safe to access frame->instruction
1158 * after this point, and the cached instruction
1159 * should be used instead.
1160 */
1161 ua = frame->process(&frame->scratch_result, request, frame);
1162 }
1163
1165
1166 RDEBUG4("** [%i] %s << %s (%s %s)", stack->depth, __FUNCTION__,
1168 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<INVALID>"),
1169 mod_action_name[scratch->priority]);
1170
1171 /*
1172 * If the frame is cancelled we ignore the
1173 * return code of the process function and
1174 * pop the frame. We'll keep popping
1175 * frames until we hit a non-cancelled frame
1176 * or the top frame.
1177 */
1178 if (is_unwinding(frame)) goto calculate_result;
1179
1180 switch (ua) {
1181 /*
1182 * The operation resulted in additional frames
1183 * being pushed onto the stack, execution should
1184 * now continue at the deepest frame.
1185 */
1187 fr_assert_msg(&stack->frame[stack->depth] > frame,
1188 "Instruction %s returned UNLANG_ACTION_PUSHED_CHILD, "
1189 "but stack depth was not increased",
1190 instruction->name);
1193
1194 /*
1195 * Yield control back to the scheduler, or whatever
1196 * called the interpreter.
1197 */
1199 fr_assert_msg(&stack->frame[stack->depth] == frame,
1200 "Instruction %s returned UNLANG_ACTION_YIELD, but pushed additional "
1201 "frames for evaluation. Instruction should return UNLANG_ACTION_PUSHED_CHILD "
1202 "instead", instruction->name);
1204 yielded_set(frame);
1205 RDEBUG4("** [%i] %s - yielding with current (%s %s)", stack->depth, __FUNCTION__,
1206 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"),
1207 mod_action_name[scratch->priority]);
1209
1210 /*
1211 * This action is intended to be returned by library
1212 * functions. It reduces boilerplate.
1213 */
1214 case UNLANG_ACTION_FAIL:
1215 /*
1216 * Let unlang_calculate figure out if this is the final result
1217 */
1218 frame->scratch_result = UNLANG_RESULT_RCODE(RLM_MODULE_FAIL);
1220
1221 /*
1222 * Instruction finished execution,
1223 * check to see what we need to do next, and update
1224 * the section rcode and priority.
1225 */
1227 calculate_result:
1228 /*
1229 * Merge in the scratch result _before_ printing
1230 * out the rcode for the frame, so get what we'll
1231 * actually return.
1232 */
1233 fa = result_calculate(request, frame, &frame->scratch_result);
1234
1235 instruction_done_debug(request, frame, instruction);
1236
1237 switch (fa) {
1239 goto pop;
1240
1242 if (has_debug_braces(instruction)) {
1243 REXDENT();
1244 RDEBUG2("} # retrying the same section");
1245 }
1246 continue; /* with the current instruction */
1247
1248 default:
1249 break;
1250 }
1251 break;
1252
1253 /*
1254 * Execute the next instruction in this frame
1255 */
1257 if (has_debug_braces(instruction)) {
1258 REXDENT();
1259 RDEBUG2("}");
1260 }
1261 break;
1262 } /* switch over return code from the interpret function */
1263
1264 frame_next(stack, frame);
1265 }
1266
1267pop:
1268 fr_assert(MOD_ACTION_VALID(frame->p_result->priority));
1269
1270 RDEBUG4("** [%i] %s - done current subsection with (%s %s), %s",
1271 stack->depth, __FUNCTION__,
1272 fr_table_str_by_value(mod_rcode_table, frame->p_result->rcode, "<invalid>"),
1273 mod_action_name[frame->p_result->priority],
1274 frame->p_result == &(frame->section_result) ? "will set higher frame rcode" : "will NOT set higher frame rcode (p_result)");
1275
1277}
1278
1279/** Run the interpreter for a current request
1280 *
1281 * This function runs the interpreter for a request. It deals with popping
1282 * stack frames, and calculating the final result for the frame.
1283 *
1284 * @param[in] request to run. If this is an internal request
1285 * the request may be freed by the interpreter.
1286 * @param[in] running Is the interpreter already running.
1287 * @return The final request rcode.
1288 */
1289CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
1290{
1291 unlang_stack_t *stack = request->stack;
1292 unlang_interpret_t *intp = stack->intp;
1293 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1294
1295 /*
1296 * This is needed to ensure that if a frame is marked
1297 * for unwinding whilst the request is yielded, we
1298 * unwind the cancelled frame correctly, instead of
1299 * continuing.
1300 */
1302
1303#ifndef NDEBUG
1304 if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
1305 DUMP_STACK;
1306#endif
1307
1308 fr_assert(!unlang_request_is_scheduled(request)); /* if we're running it, it can't be scheduled */
1309 fr_assert_msg(intp, "request has no interpreter associated");
1310
1311 RDEBUG4("** [%i] %s - interpret entered", stack->depth, __FUNCTION__);
1312 if (!running) intp->funcs.resume(request, intp->uctx);
1313
1314 for (;;) {
1315 fr_assert(stack->depth > 0);
1317
1318 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
1320 switch (fa) {
1321 next:
1322 RDEBUG4("** [%i] %s - frame action next", stack->depth, __FUNCTION__);
1324
1325 case UNLANG_FRAME_ACTION_NEXT: /* Evaluate the current frame */
1326 frame = &stack->frame[stack->depth];
1327 fa = frame_eval(request, frame);
1328 if (fa != UNLANG_FRAME_ACTION_POP) continue;
1329
1330 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
1333
1334 case UNLANG_FRAME_ACTION_POP: /* Pop this frame and check the one beneath it */
1335 {
1336 bool top_frame = is_top_frame(frame);
1337 bool private_result = is_private_result(frame);
1338
1339 unlang_result_t section_result = frame->section_result; /* record the result of the frame before we pop it*/
1340
1341 DUMP_STACK;
1342
1343 /*
1344 * Triggers can run modules which pop, and then the stack is empty.
1345 */
1346 if (unlikely(stack->depth == 0)) {
1347 break;
1348 }
1349
1350 /*
1351 * Head on back up the stack
1352 */
1353 frame_pop(request, stack);
1354 RDEBUG4("** [%i] %s - frame popped", stack->depth + 1, __FUNCTION__);
1355
1356 /*
1357 * Update the stack frame
1358 */
1359 frame = &stack->frame[stack->depth];
1360 DUMP_STACK;
1361
1362 /*
1363 * Transition back to the C stack
1364 *
1365 * We still need to merge in the previous frame's result,
1366 * but we don't care about the action, as we're returning.
1367 */
1368 if (top_frame) {
1369 if (!private_result) result_calculate(request, frame, &section_result);
1370 break; /* stop */
1371 }
1372
1373 /*
1374 * Don't process the section result for a frame if
1375 * the result is being consumed by a module.
1376 */
1377 if (private_result) {
1379 /*
1380 * Merge lower frame into higher frame.
1381 *
1382 * this _MUST_ be done, even on resume, because the
1383 * section result needs to be updated for the frame
1384 * being resumed, in case it cares about the rcode
1385 * like transaction sections.
1386 */
1387 } else {
1388 fa = result_pop(request, frame, &section_result);
1389 }
1390
1391 /*
1392 * Resume a "foreach" loop, or a "load-balance" section
1393 * or anything else that needs to be checked on the way
1394 * back on up the stack. Here we just resume evaluating
1395 * the frame, we don't advance the instruction.
1396 */
1397 if (!is_unwinding(frame) && is_repeatable(frame)) goto next;
1398
1399 /*
1400 * Close out the section we entered earlier
1401 *
1402 * @todo - this arguably accesses the
1403 * frame after it's been popped, but this
1404 * is usually OK. :(
1405 */
1406 instruction_done_debug(request, frame, frame->instruction);
1407
1409
1410 /*
1411 * If we're continuing after popping a frame
1412 * then we advance the instruction else we
1413 * end up executing the same code over and over...
1414 */
1415 switch (fa) {
1417 DEBUG4("** [%i] %s - continuing after subsection with (%s %s)",
1418 stack->depth, __FUNCTION__,
1421 frame_next(stack, frame);
1422 goto next;
1423
1424 /*
1425 * Else if we're really done with this frame
1426 * print some helpful debug...
1427 */
1428 default:
1429 RDEBUG4("** [%i] %s - done current subsection with (%s %s)",
1430 stack->depth, __FUNCTION__,
1433 continue;
1434 }
1435
1436 }
1437
1439 /* Cannot yield from a nested call to unlang_interpret */
1440 fr_assert(!running);
1441
1442 RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
1443 intp->funcs.yield(request, intp->uctx);
1444 return RLM_MODULE_NOT_SET;
1445
1446 case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
1447 goto next;
1448 }
1449 break;
1450 }
1451
1452 fr_assert(stack->depth >= 0);
1453
1454 /*
1455 * We're at the top frame, return the result from the
1456 * stack, and get rid of the top frame.
1457 */
1458 RDEBUG4("** [%i] %s - interpret exiting, returning (%s)", stack->depth, __FUNCTION__,
1460
1461 DUMP_STACK;
1462
1463 {
1464 rlm_rcode_t rcode;
1465 /*
1466 * Record this now as the done functions may free
1467 * the request.
1468 *
1469 * Note: We use p_result here, as that's where the
1470 * result of evaluating the frame was written.
1471 * We don't use the section_result, as that may have
1472 * been left as its default value which may be 0
1473 * (reject).
1474 */
1475 rcode = frame->p_result->rcode;
1476
1477 /*
1478 * This usually means the request is complete in its
1479 * entirety.
1480 */
1481 if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
1482
1483 return rcode;
1484 }
1485}
1486
1488 .self = {
1490 .name = "empty-group",
1491 .debug_name = "empty-group",
1492 .actions = {
1493 .actions = {
1505 },
1506 .retry = RETRY_INIT,
1507 },
1508 },
1509 .children = {
1510 .head = {
1511 .entry = {
1512 .prev = &empty_group.children.head.entry,
1513 .next = &empty_group.children.head.entry,
1514 }
1515 },
1516 },
1517};
1518
1519/** Push a configuration section onto the request stack for later interpretation.
1520 *
1521 */
1523{
1524 unlang_t *instruction = NULL;
1525
1526 /*
1527 * Interpretable unlang instructions are stored as CONF_DATA
1528 * associated with sections.
1529 */
1530 if (cs) {
1531 instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
1532 if (!instruction) {
1533 REDEBUG("Failed to find pre-compiled unlang for section %s ... { ... }",
1534 cf_section_name1(cs));
1535 return -1;
1536 }
1537 }
1538
1539 return unlang_interpret_push_instruction(p_result, request, instruction, conf);
1540}
1541
1542/** Push an instruction onto the request stack for later interpretation.
1543 *
1544 */
1546{
1547 unlang_stack_t *stack = request->stack;
1548
1549 if (!instruction) {
1550 instruction = unlang_group_to_generic(&empty_group);
1551 }
1552
1553 /*
1554 * Push the default action, and the instruction which has
1555 * no action.
1556 */
1557 if (unlang_interpret_push(p_result, request, instruction, conf, UNLANG_NEXT_SIBLING) < 0) {
1558 return -1;
1559 }
1560
1561 RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
1562
1563 return 0;
1564}
1565
1566/** Allocate a new unlang stack
1567 *
1568 * @param[in] ctx to allocate stack in.
1569 * @return
1570 * - A new stack on success.
1571 * - NULL on OOM.
1572 */
1573void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
1574{
1575 /*
1576 * Should never be evaluated, is just here to reduce
1577 * branches, so we don't need to check for frame->instruction.
1578 */
1579 static unlang_t unlang_instruction = {
1580 .debug_name = "top",
1581 .actions = DEFAULT_MOD_ACTIONS,
1582 };
1583
1585
1586 /*
1587 * If we have talloc_pooled_object allocate the stack as
1588 * a combined chunk/pool, with memory to hold at mutable
1589 * state data for the of the stack frames.
1590 *
1591 * Having a dedicated pool for mutable stack data
1592 * means we don't have memory fragmentations issues
1593 * as we would if request were used as the pool.
1594 *
1595 * This number is pretty arbitrary, but it seems
1596 * like too low level to make into a tuneable.
1597 */
1599 stack->frame[0].p_result = &stack->frame[0].section_result;
1600 stack->frame[0].scratch_result = UNLANG_RESULT_NOT_SET;
1601 stack->frame[0].section_result = UNLANG_RESULT_NOT_SET;
1602 stack->frame[0].instruction = &unlang_instruction; /* The top frame has no instruction, so we use a dummy one */
1603
1604 return stack;
1605}
1606
1607/** Indicate to the caller of the interpreter that this request is complete
1608 *
1609 */
1611{
1612 unlang_stack_t *stack = request->stack;
1613 unlang_interpret_t *intp;
1614
1615 if (!fr_cond_assert(stack != NULL)) return;
1616
1617 intp = stack->intp;
1618
1619 request->master_state = REQUEST_DONE;
1620 switch (request->type) {
1622 intp->funcs.done_external(request, frame_current(request)->section_result.rcode, intp->uctx);
1623 break;
1624
1626 intp->funcs.done_internal(request, frame_current(request)->section_result.rcode, intp->uctx);
1627 break;
1628
1630 intp->funcs.done_detached(request, frame_current(request)->section_result.rcode, intp->uctx); /* Callback will usually free the request */
1631 break;
1632 }
1633}
1634
1635/** Tell the interpreter to detach the request
1636 *
1637 * This function should not be called directly use unlang_interpret_signal(request, FR_SIGNAL_DETACH) instead.
1638 * This will ensure all frames on the request's stack receive the detach signal.
1639 */
1640static inline CC_HINT(always_inline)
1642{
1643 unlang_stack_t *stack = request->stack;
1644 unlang_interpret_t *intp;
1645
1646 if (!fr_cond_assert(stack != NULL)) return;
1647
1648 if (!request_is_detachable(request)) return;
1649
1650 intp = stack->intp;
1651
1652 intp->funcs.detach(request, intp->uctx);
1653}
1654
1656{
1657 unlang_stack_t *stack = request->stack;
1658 unlang_interpret_t *intp;
1659
1660 if (!fr_cond_assert(stack != NULL)) return;
1661
1662 intp = stack->intp;
1663
1664 request->priority = priority;
1665
1666 if (intp->funcs.prioritise) intp->funcs.prioritise(request, intp->uctx);
1667}
1668
1669/** Cancel any pending retry
1670 *
1671 * @param[in] request The current request.
1672 */
1674{
1675 unlang_stack_t *stack = request->stack;
1676 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1677
1678 TALLOC_FREE(frame->retry);
1679}
1680
1681
1682/** Delivers a frame to one or more frames in the stack
1683 *
1684 * This is typically called via an "async" action, i.e. an action outside
1685 * of the normal processing of the request.
1686 *
1687 * For FR_SIGNAL_CANCEL all frames are marked up for cancellation, but the
1688 * cancellation is handled by the interpret.
1689 *
1690 * Other signal types are delivered immediately, inrrespecitve of whether
1691 * the request is currently being processed or not.
1692 *
1693 * Signaling stops at the "limit" frame. This is so that keywords
1694 * such as "timeout" and "limit" can signal frames *lower* than theirs
1695 * to stop, but then continue with their own work.
1696 *
1697 * @note It's better (clearer) to use one of the unwind_* functions
1698 * unless the entire request is being cancelled.
1699 *
1700 * @param[in] request The current request.
1701 * @param[in] action to signal.
1702 * @param[in] limit the frame at which to stop signaling.
1703 */
1704void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
1705{
1706 unlang_stack_frame_t *frame;
1707 unlang_stack_t *stack = request->stack;
1708 int i, depth = stack->depth;
1709
1710 (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1711
1712 fr_assert(stack->depth >= 1);
1713
1714 /*
1715 * Does not complete the unwinding here, just marks
1716 * up the frames for unwinding. The request must
1717 * be marked as runnable to complete the cancellation.
1718 */
1719 if (action == FR_SIGNAL_CANCEL) unwind_to_depth(stack, limit);
1720
1721 /*
1722 * Walk back up the stack, calling signal handlers
1723 * to cancel any pending operations and free/release
1724 * any resources.
1725 *
1726 * There may be multiple resumption points in the
1727 * stack, as modules can push xlats and function
1728 * calls.
1729 *
1730 * Note: Slightly confusingly, a cancellation signal
1731 * can still be delivered to a frame that is not
1732 * cancellable, but the frame won't be automatically
1733 * unwound.
1734 */
1735 for (i = depth; i >= limit; i--) {
1736 frame = &stack->frame[i];
1737 if (frame->signal) {
1738 frame->signal(request, frame, action);
1739
1740 /*
1741 * Once the cancellation function has been
1742 * called, the frame is no longer in a state
1743 * where it can accept further signals.
1744 */
1745 if (action == FR_SIGNAL_CANCEL) frame->signal = NULL;
1746
1747 /*
1748 * If the frame is cancelled, we don't do any retries.
1749 */
1750 TALLOC_FREE(frame->retry);
1751 }
1752 }
1753}
1754
1755/** Send a signal (usually stop) to a request
1756 *
1757 * This is typically called via an "async" action, i.e. an action
1758 * outside of the normal processing of the request.
1759 *
1760 * @note This does NOT immediately stop the request, it just deliveres
1761 * signals, and in the case of a cancel, marks up frames for unwinding
1762 * and adds it to the runnable queue if it's yielded.
1763 *
1764 * @note This function should be safe to call anywhere.
1765 *
1766 * @param[in] request The current request.
1767 * @param[in] action to signal.
1768 */
1770{
1771 unlang_stack_t *stack = request->stack;
1772
1773 switch (action) {
1774 case FR_SIGNAL_DETACH:
1775 /*
1776 * Ensure the request is able to be detached
1777 * else don't signal.
1778 */
1779 if (!fr_cond_assert(request_is_detachable(request))) return;
1780 break;
1781
1782 default:
1783 break;
1784 }
1785
1786 /*
1787 * Requests that haven't been run through the interpreter
1788 * yet should have a stack depth of zero, so we don't
1789 * need to do anything.
1790 */
1791 if (!stack || stack->depth == 0) return;
1792
1793 unlang_stack_signal(request, action, 1);
1794
1795 switch (action) {
1796 case FR_SIGNAL_CANCEL:
1797 {
1798 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1799 /*
1800 * Let anything that cares, know that the
1801 * request was forcefully stopped.
1802 */
1803 request->master_state = REQUEST_STOP_PROCESSING;
1804
1805 /*
1806 * Give cancelled requests the highest priority
1807 * to get them to release resources ASAP.
1808 */
1809 unlang_interpret_request_prioritise(request, UINT32_MAX);
1810
1811 /*
1812 * If the request is yielded, mark it as runnable
1813 *
1814 * If the request was _not_ cancelled, it means
1815 * it's not cancellable, and we need to let the
1816 * request progress normally.
1817 *
1818 * A concrete example of this, is the parent of
1819 * subrequests, which must not continue until
1820 * the subrequest is done.
1821 */
1822 if (stack && is_yielded(frame) && is_unwinding(frame) && !unlang_request_is_scheduled(request)) {
1824 }
1825 }
1826 break;
1827
1828 case FR_SIGNAL_DETACH:
1829 /*
1830 * Cleanup any cross-request pointers, and mark the
1831 * request as detached. When the request completes it
1832 * should by automatically freed.
1833 */
1835 break;
1836
1837 default:
1838 break;
1839 }
1840}
1841
1843{
1844 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1845 request_t *request = talloc_get_type_abort(retry->request, request_t);
1846
1847 RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1848
1849 /*
1850 * Signal all lower frames to exit.
1851 */
1852 unlang_stack_signal(request, FR_SIGNAL_CANCEL, retry->depth + 1);
1853
1854 retry->state = FR_RETRY_MRD;
1856}
1857
1859{
1860 request_t *request = talloc_get_type_abort(ctx, request_t);
1861
1862 RDEBUG("Maximum timeout reached, signalling interpreter to stop the request.");
1863
1864 /*
1865 * Stop the entire request.
1866 */
1868}
1869
1870
1871/** Set a timeout for a request.
1872 *
1873 * The timeout is associated with the current stack frame.
1874 *
1875 */
1877{
1878 unlang_stack_t *stack = request->stack;
1879 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1880 unlang_retry_t *retry;
1881
1882 fr_assert(!frame->retry);
1884
1885 frame->retry = retry = talloc_zero(stack, unlang_retry_t);
1886 if (!frame->retry) return -1;
1887
1888 retry->request = request;
1889 retry->depth = stack->depth;
1890 retry->state = FR_RETRY_CONTINUE;
1891 retry->count = 1;
1892
1893 return fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, timeout,
1894 false, instruction_timeout_handler, request);
1895}
1896
1897
1898/** Return the depth of the request's stack
1899 *
1900 */
1902{
1903 unlang_stack_t *stack = request->stack;
1904
1905 return stack->depth;
1906}
1907
1908/** Get the last instruction result OR the last frame that was popped
1909 *
1910 * @param[in] request The current request.
1911 * @return the current rcode for the frame.
1912 */
1914{
1915 return frame_current(request)->p_result->rcode;
1916}
1917
1918/** Get the last instruction priority OR the last frame that was popped
1919 *
1920 * @param[in] request The current request.
1921 * @return the current rcode for the frame.
1922 */
1927
1928/** Get the last instruction result OR the last frame that was popped
1929 *
1930 * @param[in] request The current request.
1931 * @return the current result for the frame.
1932 */
1934{
1935 return frame_current(request)->p_result;
1936}
1937
1938/** Return whether a request is currently scheduled
1939 *
1940 */
1942{
1943 unlang_stack_t *stack = request->stack;
1944 unlang_interpret_t *intp = stack->intp;
1945
1946 return intp->funcs.scheduled(request, intp->uctx);
1947}
1948
1949/** Return whether a request has been cancelled
1950 */
1952{
1953 return (request->master_state == REQUEST_STOP_PROCESSING);
1954}
1955
1956/** Return whether a request has been marked done
1957 */
1959{
1960 return (request->master_state == REQUEST_DONE);
1961}
1962
1963/** Check if a request as resumable.
1964 *
1965 * @param[in] request The current request.
1966 * @return
1967 * - true if the request is resumable (i.e. has yielded)
1968 * - false if the request is not resumable (i.e. has not yielded)
1969 */
1971{
1972 unlang_stack_t *stack = request->stack;
1973 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1974
1975 return is_yielded(frame);
1976}
1977
1978/** Mark a request as resumable.
1979 *
1980 * It's not called "unlang_interpret", because it doesn't actually
1981 * resume the request, it just schedules it for resumption.
1982 *
1983 * @note that this schedules the request for resumption. It does not immediately
1984 * start running the request.
1985 *
1986 * @param[in] request The current request.
1987 */
1989{
1990 unlang_stack_t *stack = request->stack;
1991 unlang_interpret_t *intp = stack->intp;
1992 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1993
1994 bool scheduled = unlang_request_is_scheduled(request);
1995
1996 /*
1997 * The request hasn't yielded, OR it's already been
1998 * marked as runnable. Don't do anything.
1999 *
2000 * The IO code, or children have no idea where they're
2001 * being called from. They just ask to mark the parent
2002 * resumable when they're done. So we have to check here
2003 * if this request is resumable.
2004 *
2005 * If the parent called the child directly, then the
2006 * parent hasn't yielded, so it isn't resumable. When
2007 * the child is done, the parent will automatically
2008 * continue running. We therefore don't need to insert
2009 * the parent into the backlog.
2010 *
2011 * Multiple child request may also mark a parent request
2012 * runnable, before the parent request starts running.
2013 */
2014 if (!is_yielded(frame) || scheduled) {
2015 RDEBUG3("Not marking request %s as runnable due to%s%s",
2016 request->name,
2017 !is_yielded(frame) ?
2018 " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
2019 return;
2020 }
2021
2022 RDEBUG3("Interpreter - Request marked as runnable");
2023
2024 intp->funcs.mark_runnable(request, intp->uctx);
2025}
2026
2027/** Get a talloc_ctx which is valid only for this frame
2028 *
2029 * @param[in] request The current request.
2030 * @return
2031 * - a TALLOC_CTX which is valid only for this stack frame
2032 */
2034{
2035 unlang_stack_t *stack = request->stack;
2036 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
2037
2038 if (frame->state) return (TALLOC_CTX *)frame->state;
2039
2040 /*
2041 * If the frame doesn't ordinarily have a
2042 * state, assume the caller knows what it's
2043 * doing and allocate one.
2044 */
2045 return (TALLOC_CTX *)(frame->state = talloc_new(stack));
2046}
2047
2049 { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
2051};
2052
2053static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
2054 UNUSED xlat_ctx_t const *xctx,
2055 request_t *request, fr_value_box_list_t *args);
2056
2057/** Signal the request to stop executing
2058 *
2059 * The request can't be running at this point because we're in the event
2060 * loop. This means the request is always in a consistent state when
2061 * the timeout event fires, even if that's state is waiting on I/O.
2062 */
2064{
2065 request_t *request = talloc_get_type_abort(uctx, request_t);
2066
2067 RDEBUG2("Request canceled by dynamic timeout");
2068 /*
2069 * Cleans up the memory allocated to hold
2070 * the pointer, not the event itself.
2071 */
2072 talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
2073
2075}
2076
2077/** Allows a request to dynamically alter its own lifetime
2078 *
2079 * %cancel(<timeout>)
2080 *
2081 * If timeout is 0, then the request is immediately cancelled.
2082 */
2084 UNUSED xlat_ctx_t const *xctx,
2085 request_t *request, fr_value_box_list_t *args)
2086{
2087 fr_value_box_t *timeout;
2089 fr_timer_t **ev_p, **ev_p_og;
2090 fr_value_box_t *vb;
2091 fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
2092
2093 fr_assert(el != NULL);
2094
2095 XLAT_ARGS(args, &timeout);
2096
2097 /*
2098 * No timeout means cancel immediately, so yield allowing
2099 * the interpreter to run the event we added to cancel
2100 * the request.
2101 *
2102 * We call unlang_xlat_yield to keep the interpreter happy
2103 * as it expects to see a resume function set.
2104 */
2105 if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
2107 return XLAT_ACTION_DONE;
2108 }
2109
2110 /*
2111 * First see if we already have a timeout event
2112 * that was previously added by this xlat.
2113 */
2114 ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
2115 if (ev_p) {
2116 fr_assert(*ev_p);
2117
2118 when = fr_timer_when(*ev_p);
2119 } else {
2120 /*
2121 * Must not be parented from the request
2122 * as this is freed by request data.
2123 */
2124 MEM(ev_p = talloc_zero(NULL, fr_timer_t *));
2125 }
2126
2127 if (unlikely(fr_timer_in(ev_p, el->tl, ev_p,
2128 timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
2129 false, unlang_cancel_event, request) < 0)) {
2130 RPERROR("Failed inserting cancellation event");
2131 talloc_free(ev_p);
2132 return XLAT_ACTION_FAIL;
2133 }
2134 if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
2135 UNCONST(fr_timer_t **, ev_p), true, true, false) < 0)) {
2136 RPERROR("Failed associating cancellation event with request");
2137 talloc_free(ev_p);
2138 return XLAT_ACTION_FAIL;
2139 }
2140
2141 if (ev_p_og) {
2142 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
2143
2144 /*
2145 * Return how long before the previous
2146 * cancel event would have fired.
2147 *
2148 * This can be useful for doing stacked
2149 * cancellations in policy.
2150 */
2151 vb->vb_time_delta = fr_time_sub(when, unlang_interpret_event_list(request)->tl->time());
2153 }
2154
2155 /*
2156 * No value if this is the first cleanup event
2157 */
2158 return XLAT_ACTION_DONE;
2159}
2160
2162 { .required = true, .single = true, .type = FR_TYPE_STRING },
2164};
2165
2166/** Get information about the interpreter state
2167 *
2168 * @ingroup xlat_functions
2169 */
2171 UNUSED xlat_ctx_t const *xctx,
2172 request_t *request, fr_value_box_list_t *in)
2173{
2174 unlang_stack_t *stack = request->stack;
2175 int depth = stack->depth;
2176 unlang_stack_frame_t *frame;
2177 unlang_t const *instruction;
2178 fr_value_box_t *arg = fr_value_box_list_head(in);
2179 char const *fmt = arg->vb_strvalue;
2180 fr_value_box_t *vb;
2181
2182 MEM(vb = fr_value_box_alloc_null(ctx));
2183
2184 /*
2185 * Find the correct stack frame.
2186 */
2187 while (*fmt == '.') {
2188 if (depth <= 1) {
2189 if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
2190 error:
2191 talloc_free(vb);
2192 return XLAT_ACTION_FAIL;
2193 }
2194 goto finish;
2195 }
2196
2197 fmt++;
2198 depth--;
2199 }
2200
2201 /*
2202 * Get the current instruction.
2203 */
2204 frame = &stack->frame[depth];
2205 instruction = frame->instruction;
2206
2207 /*
2208 * Nothing there...
2209 */
2210 if (!instruction) goto clear;
2211
2212 /*
2213 * How deep the current stack is.
2214 */
2215 if (strcmp(fmt, "depth") == 0) {
2216 fr_value_box_int32(vb, NULL, depth, false);
2217 goto finish;
2218 }
2219
2220 /*
2221 * The current module
2222 */
2223 if (strcmp(fmt, "module") == 0) {
2224 if (!request->module) goto clear;
2225
2226 if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
2227
2228 goto finish;
2229 }
2230
2231 /*
2232 * Name of the instruction.
2233 */
2234 if (strcmp(fmt, "name") == 0) {
2235 if (!instruction->name) goto clear;
2236
2237 if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
2238 strlen(instruction->name), false) < 0) goto error;
2239 goto finish;
2240 }
2241
2242 /*
2243 * The request processing stage.
2244 */
2245 if (strcmp(fmt, "processing_stage") == 0) {
2246 if (!request->component) goto clear;
2247
2248 if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
2249
2250 goto finish;
2251 }
2252
2253 /*
2254 * The current return code.
2255 */
2256 if (strcmp(fmt, "rcode") == 0) {
2257 if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
2258
2259 goto finish;
2260 }
2261
2262 /*
2263 * The virtual server handling the request
2264 */
2265 if (strcmp(fmt, "server") == 0) {
2266 request_t *our_request;
2267 CONF_SECTION *server = NULL;
2268
2269 /*
2270 * If we're being pedantic subrequests don't have a virtual
2271 * server associated with them unless they go call {}.
2272 *
2273 * But we're not being pendantic, so go back up the request
2274 * list ooking for a call frame.
2275 *
2276 * Unfortunately for detached subrequests we still won't find
2277 * the actual virtual server...
2278 */
2279 for (our_request = request; our_request && server == NULL; our_request = our_request->parent) {
2280 server = unlang_call_current(our_request);
2281 }
2282 if (server == NULL) goto finish;
2283
2284 if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(server), false) < 0) goto error;
2285
2286 goto finish;
2287 }
2288
2289 /*
2290 * Unlang instruction type.
2291 */
2292 if (strcmp(fmt, "type") == 0) {
2293 if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
2294 strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
2295
2296 goto finish;
2297 }
2298
2299 /*
2300 * All of the remaining things need a CONF_ITEM.
2301 */
2302 if (!instruction->ci) {
2303 if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 9, false) < 0) goto error;
2304
2305 goto finish;
2306 }
2307
2308 /*
2309 * Line number of the current section.
2310 */
2311 if (strcmp(fmt, "line") == 0) {
2312 fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
2313
2314 goto finish;
2315 }
2316
2317 /*
2318 * Filename of the current section.
2319 */
2320 if (strcmp(fmt, "filename") == 0) {
2321 if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
2322
2323 goto finish;
2324 }
2325
2326finish:
2327 if (vb->type != FR_TYPE_NULL) {
2329 } else {
2330 clear:
2331 talloc_free(vb);
2332 }
2333
2334 return XLAT_ACTION_DONE;
2335}
2336
2337/** Initialize a unlang compiler / interpret.
2338 *
2339 * @param[in] ctx to bind lifetime of the interpret to.
2340 * Shouldn't be any free order issues here as
2341 * the interpret itself has no state.
2342 * But event loop should be stopped before
2343 * freeing the interpret.
2344 * @param[in] el for any timer or I/O events.
2345 * @param[in] funcs Callbacks to used to communicate request
2346 * state to our owner.
2347 * @param[in] uctx Data to pass to callbacks.
2348 */
2350 fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
2351{
2352 unlang_interpret_t *intp;
2353
2354 fr_assert(funcs->init_internal);
2355
2356 fr_assert(funcs->done_internal);
2357 fr_assert(funcs->done_detached);
2358 fr_assert(funcs->done_external);
2359
2360 fr_assert(funcs->detach);
2361 fr_assert(funcs->yield);
2362 fr_assert(funcs->resume);
2363 fr_assert(funcs->mark_runnable);
2364 fr_assert(funcs->scheduled);
2365
2366 MEM(intp = talloc(ctx, unlang_interpret_t));
2367 *intp = (unlang_interpret_t){
2368 .el = el,
2369 .funcs = *funcs,
2370 .uctx = uctx
2371 };
2372
2373 return intp;
2374}
2375
2376/** Discard the bottom most frame on the request's stack
2377 *
2378 * This is used for cleaning up after errors. i.e. the caller
2379 * uses a push function, and experiences an error and needs to
2380 * remove the frame that was just pushed.
2381 */
2383{
2384 frame_pop(request, request->stack);
2385}
2386
2387/** Set a specific interpreter for a request
2388 *
2389 */
2391{
2392 unlang_stack_t *stack = request->stack;
2393 stack->intp = intp;
2394}
2395
2396/** Get the interpreter set for a request
2397 *
2398 */
2400{
2401 unlang_stack_t *stack = request->stack;
2402
2403 return stack->intp;
2404}
2405
2406/** Get the event list for the current interpreter
2407 *
2408 */
2410{
2411 unlang_stack_t *stack = request->stack;
2412
2413 if (!stack->intp) return NULL;
2414
2415 return stack->intp->el;
2416}
2417
2418/** Set the default interpreter for this thread
2419 *
2420 */
2422{
2423 if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
2424
2425 intp_thread_default = intp;
2426}
2427
2428/** Get the default interpreter for this thread
2429 *
2430 * This allows detached requests to be executed asynchronously
2431 */
2433{
2434 if (!intp_thread_default) return NULL;
2435
2436 return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
2437}
2438
2440{
2441 xlat_t *xlat;
2442 /*
2443 * Should be void, but someone decided not to register multiple xlats
2444 * breaking the convention we use everywhere else in the server...
2445 */
2446 if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2448
2449 if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2451
2452 return 0;
2453}
#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:214
Common header for all CONF_* types.
Definition cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1187
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1750
char const * cf_section_name1(CONF_SECTION const *cs)
Return the first identifier of a CONF_SECTION.
Definition cf_util.c:1173
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:685
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition cf_util.c:619
#define cf_lineno(_cf)
Definition cf_util.h:101
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:242
#define cf_item_next(_parent, _curr)
Definition cf_util.h:89
#define cf_filename(_cf)
Definition cf_util.h:104
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:68
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition dcursor.h:435
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:141
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:212
#define MEM(x)
Definition debug.h:46
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static fr_slen_t in
Definition dict.h:882
static xlat_action_t unlang_interpret_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Get information about the interpreter state.
Definition interpret.c:2170
talloc_free(hp)
void unlang_interpret_request_prioritise(request_t *request, uint32_t priority)
Definition interpret.c:1655
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:1641
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:1289
bool unlang_request_is_done(request_t const *request)
Return whether a request has been marked done.
Definition interpret.c:1958
static void stack_dump_body(request_t *request, bool with_actions)
Definition interpret.c:569
static unlang_group_t empty_group
Definition interpret.c:1487
unlang_result_t * unlang_interpret_result(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1933
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:2382
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1876
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1610
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:1069
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:2390
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:2399
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1901
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:1988
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition interpret.c:2161
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:2033
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1941
static char const unlang_spaces[]
Definition interpret.c:58
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition interpret.c:2439
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:2432
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:1573
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:2421
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:1923
static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1842
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:2349
static void instruction_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1858
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:1951
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:1545
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:2063
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1769
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition interpret.c:2048
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:1522
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:785
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:681
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:1970
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:1025
fr_rb_tree_t * unlang_instruction_tree
Definition compile.c:64
request_t * request
the request
Definition interpret.c:678
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:1673
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:995
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:1704
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:2083
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:1913
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:719
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:2409
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:577
@ 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:772
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:201
static fr_time_delta_t fr_time_delta_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:363
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition xlat_func.c:216