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