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