The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
interpret.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 409bfbb8ed0632c557dae94e0bc74c496ef5a72d $
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: 409bfbb8ed0632c557dae94e0bc74c496ef5a72d $")
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/server/rcode.h>
33#include <freeradius-devel/unlang/xlat_func.h>
34#include <freeradius-devel/unlang/mod_action.h>
35
36#include "interpret_priv.h"
37#include "unlang_priv.h"
38#include "module_priv.h"
39
40
41/** The default interpreter instance for this thread
42 */
44
46 { L("calculate-result"), UNLANG_ACTION_CALCULATE_RESULT },
47 { L("next"), UNLANG_ACTION_EXECUTE_NEXT },
48 { L("pushed-child"), UNLANG_ACTION_PUSHED_CHILD },
50 { L("yield"), UNLANG_ACTION_YIELD }
51};
53
60
61#ifndef NDEBUG
62#include <freeradius-devel/unlang/module_priv.h>
63
72
73/** Try and figure out where result_p points to
74 *
75 * If it's somewhere other than these three locations, it's probably wrong.
76 */
77static int find_result_p_location(result_p_location_t *location, void **chunk, request_t *request, void *ptr)
78{
79 unlang_stack_t *stack = request->stack;
81 unsigned int i;
82
83 for (i = 0; i <= (unsigned int)stack->depth; i++) {
84 frame = &stack->frame[i];
85 if (frame->state && (ptr >= (void *)frame->state) &&
86 (ptr < ((void *)((uint8_t *)frame->state + talloc_get_size(frame->state))))) {
87 *location = RESULT_P_LOCATION_STATE;
88 *chunk = frame->state;
89 return i;
90 }
91
92 if (ptr == &frame->section_result) {
93 *location = RESULT_P_LOCATION_FRAME;
94 *chunk = NULL;
95 return i;
96 }
97
98 if (ptr == &frame->scratch_result) {
99 *location = RESULT_P_LOCATION_SCRATCH;
100 *chunk = NULL;
101 return i;
102 }
103
104 if (!frame->instruction) continue;
105
106 switch (frame->instruction->type) {
108 {
109 unlang_frame_state_module_t *mod_state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
110
111 if (!mod_state->rctx) continue;
112
113 if ((ptr >= (void *)mod_state->rctx) &&
114 (ptr < ((void *)((uint8_t *)mod_state->rctx + talloc_get_size(mod_state->rctx))))) {
116 *chunk = mod_state->rctx;
117 return i;
118 }
119
120 /*
121 * We don't know where the child frame is, so we can't
122 * determine where the result_p is.
123 */
124 }
125 continue;
126
127 default:
128 break;
129 }
130 }
131
132 *location = RESULT_P_LOCATION_UNKNOWN;
133 *chunk = NULL;
134 return -1;
135}
136
138 { L("frame"), RESULT_P_LOCATION_FRAME },
139 { L("module_rctx"), RESULT_P_LOCATION_MODULE_RCTX },
140 { L("scratch"), RESULT_P_LOCATION_SCRATCH },
141 { L("state"), RESULT_P_LOCATION_STATE },
142 { L("unknown"), RESULT_P_LOCATION_UNKNOWN }
143};
145
146static void instruction_dump(request_t *request, unlang_t const *instruction)
147{
148 RINDENT();
149 if (!instruction) {
150 RDEBUG2("instruction <none>");
151 REXDENT();
152 return;
153 }
154
155 RDEBUG2("type %s", unlang_ops[instruction->type].name);
156 RDEBUG2("name %s", instruction->name);
157 RDEBUG2("debug_name %s", instruction->debug_name);
158 REXDENT();
159}
160
161static void CC_HINT(nonnull) actions_dump(request_t *request, unlang_t const *instruction)
162{
163 char buffer[20];
164 int i;
165
166 RDEBUG2("actions");
167 RINDENT();
168 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
169 snprintf(buffer, sizeof(buffer), "%d", instruction->actions.actions[i]);
170
171 RDEBUG2("%s: %s",
172 fr_table_str_by_value(mod_rcode_table, i, "<invalid>"),
174 instruction->actions.actions[i]);
175 }
176 REXDENT();
177}
178
179static void frame_dump(request_t *request, unlang_stack_frame_t *frame, bool with_actions)
180{
181 unlang_op_t *op = NULL;
182
183 if (frame->instruction) {
184 op = &unlang_ops[frame->instruction->type];
185 instruction_dump(request, frame->instruction);
186 }
187
188 RINDENT();
189 if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
190 if (frame->next) {
191 RDEBUG2("next %s", frame->next->debug_name);
192 } else {
193 RDEBUG2("next <none>");
194 }
195
196 if (is_private_result(frame)) {
197 int location;
199 void *chunk;
200
201 RDEBUG2("p_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->result_p->rcode, "<invalid>"));
202 RDEBUG2("p_priority %d", frame->result_p->priority);
203
204 location = find_result_p_location(&type, &chunk, request, frame->result_p);
205 RDEBUG2("p_location %s [%i] %p (%s)", fr_table_str_by_value(result_p_location_table, type, "<invalid>"),
206 location, frame->result_p, chunk ? talloc_get_name(chunk) : "<none>"
207 );
208 } else {
209 RDEBUG2("sec_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->section_result.rcode, "<invalid>"));
210 RDEBUG2("sec_priority %d", frame->section_result.priority);
211 }
212 RDEBUG2("scr_rcode %s", fr_table_str_by_value(mod_rcode_table, frame->scratch_result.rcode, "<invalid>"));
213 RDEBUG2("scr_priority %d", frame->scratch_result.priority);
214 RDEBUG2("top_frame %s", is_top_frame(frame) ? "yes" : "no");
215 RDEBUG2("repeat %s", is_repeatable(frame) ? "yes" : "no");
216 RDEBUG2("yielded %s", is_yielded(frame) ? "yes" : "no");
217 RDEBUG2("unwind %s", is_unwinding(frame) ? "yes" : "no");
218
219 if (frame->instruction) {
220 RDEBUG2("control %s%s%s",
221 is_break_point(frame) ? "b" : "-",
222 is_return_point(frame) ? "r" : "-",
223 is_continue_point(frame) ? "c" : "-"
224 );
225 if (with_actions) actions_dump(request, frame->instruction);
226 }
227
228 /*
229 * Call the custom frame dump function
230 */
231 if (op && op->dump) op->dump(request, frame);
232 REXDENT();
233}
234
235static void stack_dump_body(request_t *request, bool with_actions)
236{
237 int i;
238 unlang_stack_t *stack = request->stack;
239
240 RDEBUG2("----- Begin stack debug [depth %i] -----",
241 stack->depth);
242 for (i = stack->depth; i >= 0; i--) {
243 unlang_stack_frame_t *frame = &stack->frame[i];
244 RDEBUG2("[%d] Frame contents", i);
245 frame_dump(request, frame, with_actions);
246 }
247 RDEBUG2("----- End stack debug [depth %i] -------", stack->depth);
248}
249
250void stack_dump(request_t *request)
251{
252 stack_dump_body(request, false);
253}
254
256{
257 stack_dump_body(request, true);
258}
259#define DUMP_STACK if (DEBUG_ENABLED5) stack_dump(request)
260#else
261#define DUMP_STACK
262#endif
263
264/** Push a new frame onto the stack
265 *
266 * @param[in] result_p Where to write the result of evaluating the section.
267 * If NULL, results will be written to frame->section_result and will
268 * be automatically merged with the next highest frame when this one
269 * is popped.
270 * @param[in] request to push the frame onto.
271 * @param[in] instruction One or more unlang_t nodes describing the operations to execute.
272 * @param[in] conf Configuration for the frame. If NULL, the following values areused:
273 * - default_rcode = RLM_MODULE_NOT_SET
274 * - default_priority = MOD_ACTION_NOT_SET
275 * - top_frame = UNLANG_SUB_FRAME
276 * - no_rcode = false
277 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
278 * or to execute subsequent nodes.
279 * @return
280 * - 0 on success.
281 * - -1 on call stack too deep.
282 */
284 unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
285{
286 unlang_stack_t *stack = request->stack;
288
289 static unlang_frame_conf_t default_conf = {
291 .default_priority = MOD_ACTION_NOT_SET,
292 .top_frame = UNLANG_SUB_FRAME
293 };
294
295 if (!conf) conf = &default_conf;
296
297 fr_assert(instruction);
298
299#ifndef NDEBUG
300 if (DEBUG_ENABLED5) RDEBUG3("unlang_interpret_push called with instruction type \"%s\" - args %s %s",
301 instruction ? instruction->debug_name : "<none>",
302 do_next_sibling ? "UNLANG_NEXT_SIBLING" : "UNLANG_NEXT_STOP",
303 conf->top_frame ? "UNLANG_TOP_FRAME" : "UNLANG_SUB_FRAME");
304#endif
305
306 /*
307 * This is not a cancellation point.
308 *
309 * If we cancel here bad things happen inside the interpret.
310 */
311 if (stack->depth >= (UNLANG_STACK_MAX - 1)) {
312 RERROR("Call stack is too deep");
313 return - 1;
314 }
315
316 stack->depth++;
317
318 /*
319 * Initialize the next stack frame.
320 */
321 frame = &stack->frame[stack->depth];
322 memset(frame, 0, sizeof(*frame));
323
324 frame->instruction = instruction;
325
326 if (do_next_sibling) {
327 fr_assert(instruction != NULL);
328 frame->next = instruction->next;
329 }
330 /* else frame->next MUST be NULL */
331
333 if (conf->top_frame) top_frame_set(frame);
334
335 frame->result_p = result_p ? result_p : &frame->section_result;
336 frame->result_p->rcode = conf->default_rcode;
337 frame->result_p->priority = conf->default_priority;
338
339 frame->indent = request->log.indent;
340
341 if (!instruction) return 0;
342
343 frame_state_init(stack, frame);
344
345 return 0;
346}
347
348typedef struct {
349 fr_dict_t const *old_dict; //!< the previous dictionary for the request
350 request_t *request; //!< the request
352
354{
355 fr_pair_t *vp, *prev;
356
357 /*
358 * Local variables are appended to the end of the list. So we remove them by walking backwards
359 * from the end of the list.
360 */
361 vp = fr_pair_list_tail(&ref->request->local_pairs);
362 while (vp) {
363 prev = fr_pair_list_prev(&ref->request->local_pairs, vp);
364 if (vp->da->dict != ref->request->local_dict) {
365 break;
366 }
367
368 (void) fr_pair_delete(&ref->request->local_pairs, vp);
369 vp = prev;
370 }
371
372 ref->request->local_dict = ref->old_dict;
373
374 return 0;
375}
376
377/** Push the children of the current frame onto a new frame onto the stack
378 *
379 * @param[out] p_result set to RLM_MOULDE_FAIL if pushing the children fails
380 * @param[in] request to push the frame onto.
381 * @param[in] default_rcode The default result.
382 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
383 * or to execute subsequent nodes.
384 * @return
385 * - UNLANG_ACTION_PUSHED_CHILD on success.
386 * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
387 * - UNLANG_ACTION_STOP_PROCESSING, fatal error, usually stack overflow.
388 */
390 rlm_rcode_t default_rcode, bool do_next_sibling)
391{
392 unlang_stack_t *stack = request->stack;
393 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
396
398
400
401 /*
402 * The compiler catches most of these, EXCEPT for the
403 * top-level 'recv Access-Request' etc. Which can exist,
404 * and can be empty.
405 */
406 if (!g->children) {
407 RDEBUG2("... ignoring empty subsection ...");
409 }
410
411 if (unlang_interpret_push(p_result, request, g->children,
412 FRAME_CONF(default_rcode, UNLANG_SUB_FRAME), do_next_sibling) < 0) {
414 }
415
417
418 /*
419 * Note that we do NOT create the variables, This way we don't have to worry about any
420 * uninitialized values. If the admin tries to use the variable without initializing it, they
421 * will get a "no such attribute" error.
422 */
423 if (!frame->state) {
424 MEM(ref = talloc(stack, unlang_variable_ref_t));
425 frame->state = ref;
426 } else {
427 MEM(ref = talloc(frame->state, unlang_variable_ref_t));
428 }
429
430 /*
431 * Set the destructor to clean up local variables.
432 */
433 ref->request = request;
434 ref->old_dict = request->local_dict;
435 request->local_dict = g->variables->dict;
436 talloc_set_destructor(ref, _local_variables_free);
437
439}
440
441static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx);
442
443/** Update the current result after each instruction, and after popping each stack frame
444 *
445 * @note Sets stack->scratch to be the the result of the frame being popped.
446 *
447 * @param[in] request The current request.
448 * @return
449 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions.
450 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
451 */
452static inline CC_HINT(always_inline)
454{
455 unlang_t const *instruction = frame->instruction;
456 unlang_stack_t *stack = request->stack;
457 unlang_result_t *frame_result = frame->result_p;
458
459 if (is_unwinding(frame)) {
460 RDEBUG4("** [%i] %s - unwinding frame", stack->depth, __FUNCTION__);
462 }
463
464 /*
465 * Don't calculate a new return code for the frame, just skip
466 * to the next instruction.
467 */
468 if (result->rcode == RLM_MODULE_NOT_SET) {
469 RDEBUG4("** [%i] %s - skipping frame, no result set",
470 stack->depth, __FUNCTION__);
472 }
473
474 RDEBUG4("** [%i] %s - have (%s %d) frame or module returned (%s %d)",
475 stack->depth, __FUNCTION__,
476 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
477 frame_result->priority,
478 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
479 result->priority);
480
481 /*
482 * Update request->rcode if the instruction says we should
483 * We don't care about priorities for this.
484 *
485 * This is the field that's evaluated in unlang conditions
486 * like `if (ok)`.
487 */
488 if (is_rcode_set(frame) && (request->rcode != result->rcode)) {
489 RDEBUG3("Setting request->rcode to '%s'",
490 fr_table_str_by_value(rcode_table, result->rcode, "<INVALID>"));
491 request->rcode = result->rcode;
492 }
493
494 /*
495 * The array holds a default priority for this return
496 * code. Grab it in preference to any unset priority.
497 */
498 if (result->priority == MOD_ACTION_NOT_SET) {
499 result->priority = instruction->actions.actions[result->rcode];
500
501 RDEBUG4("** [%i] %s - using default instruction priority for %s, %d",
502 stack->depth, __FUNCTION__,
503 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
504 result->priority);
505 }
506
507 /*
508 * Deal with special priorities which indicate we need
509 * to do something in addition to modifying the frame's
510 * rcode.
511 */
512 switch (result->priority) {
513 /*
514 * The child's prioriy value indicates we
515 * should return from this frame.
516 */
518 RDEBUG4("** [%i] %s - action says to return with (%s %d)",
519 stack->depth, __FUNCTION__,
520 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
521 result->priority);
522
523 frame_result->priority = 0;
524 frame_result->rcode = result->rcode;
526
527 /*
528 * Reject means we should return, but
529 * with a reject rcode. This allows the
530 * user to change normally positive rcodes
531 * into negative ones.
532 *
533 * They could also just check the rcode
534 * after the module returns...
535 */
537 RDEBUG4("** [%i] %s - action says to return with (%s %d)",
538 stack->depth, __FUNCTION__,
540 result->priority);
541
542 frame_result->priority = 0;
543 frame_result->rcode = RLM_MODULE_REJECT;
545
546 case MOD_ACTION_RETRY:
547 {
548 unlang_retry_t *retry = frame->retry;
549
550 RDEBUG4("** [%i] %s - action says to retry with",
551 stack->depth, __FUNCTION__);
552
553 /*
554 * If this is the first time doing the retry,
555 * then allocate the structure and set the timer.
556 */
557 if (!retry) {
558 MEM(frame->retry = retry = talloc_zero(stack, unlang_retry_t));
559
560 retry->request = request;
561 retry->depth = stack->depth;
562 retry->state = FR_RETRY_CONTINUE;
563 retry->count = 1;
564
565 /*
566 * Set a timer which automatically fires
567 * if there's a timeout. And parent it
568 * from the retry structure, so that the
569 * timer is automatically freed when the
570 * frame is cleaned up.
571 */
572 if (fr_time_delta_ispos(instruction->actions.retry.mrd)) {
573 if (fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, instruction->actions.retry.mrd,
574 false, instruction_retry_handler, request) < 0) {
575 RPEDEBUG("Failed inserting retry event");
576 frame_result->rcode = RLM_MODULE_FAIL;
577 goto finalize;
578 }
579 }
580
581 } else {
582 /*
583 * We've been told to stop doing retries,
584 * probably from a timeout.
585 */
586 if (retry->state != FR_RETRY_CONTINUE) goto timeout;
587
588 /*
589 * Clamp it at the maximum count.
590 */
591 if (instruction->actions.retry.mrc > 0) {
592 retry->count++;
593
594 if (retry->count >= instruction->actions.retry.mrc) {
595 retry->state = FR_RETRY_MRC;
596
597 REDEBUG("Retries hit max_rtx_count (%u) - returning 'timeout'", instruction->actions.retry.mrc);
598
599 timeout:
600 frame_result->rcode = RLM_MODULE_TIMEOUT;
601 goto finalize;
602 }
603 }
604 }
605
606 RINDENT();
607 if (instruction->actions.retry.mrc) {
608 RDEBUG("... retrying (%u/%u)", retry->count, instruction->actions.retry.mrc);
609 } else {
610 RDEBUG("... retrying");
611 }
612 REXDENT();
613
614 talloc_free(frame->state);
616 frame_state_init(stack, frame); /* Don't change result_p */
618 default:
619 break;
620 }
621 }
622
623finalize:
624 /*
625 * We're higher or equal to previous priority, remember this
626 * return code and priority.
627 */
628 if (result->priority >= frame_result->priority) {
629 RDEBUG4("** [%i] %s - overwriting existing result (%s %d) with higher priority (%s %d)",
630 stack->depth, __FUNCTION__,
631 fr_table_str_by_value(mod_rcode_table, frame_result->rcode, "<invalid>"),
632 frame_result->priority,
633 fr_table_str_by_value(mod_rcode_table, result->rcode, "<invalid>"),
634 result->priority);
635 *frame->result_p = *result;
636 }
637
638 /*
639 * Determine if we should continue processing siblings
640 * or pop the frame ending the section.
641 */
643}
644
645/** Function called to merge inter-stack-frame results
646 *
647 * This function is called whenever a frame is popped from the stack.
648 *
649 * 'result' is the result from the frame being popped, and 'frame' is the next highest frame in the stack.
650 *
651 * The logic here is very similar to result_eval(), with two important differences:
652 * - The priority of the lower frame is ignored, and the default priority of the higher frame is used.
653 * Unless the higher frame's priority is MOD_ACTION_NOT_SET, in which case the lower frame's priority is used.
654 */
655static inline CC_HINT(always_inline)
657{
658 unlang_stack_t *stack = request->stack;
659 unlang_result_t our_result = *result;
660
661 /*
662 * When a stack frame is being popped, the priority of the
663 * source (lower) frame is ignored, and the default priority
664 * of the destination (higher) frame is used.
665 *
666 * We could (easily) add support for preserving the priority
667 * from the lower frame, if the priority of the higher frame
668 * was MOD_ACTION_NOT_SET, but there are no concrete use
669 * cases for this yet.
670 */
671 if (result->rcode != RLM_MODULE_NOT_SET) {
672 our_result.priority = frame->instruction->actions.actions[result->rcode];
673 }
674
675 RDEBUG4("** [%i] %s - using instruction priority for higher frame (%s, %d)",
676 stack->depth, __FUNCTION__,
677 fr_table_str_by_value(mod_rcode_table, our_result.rcode, "<invalid>"),
678 our_result.priority);
679
680 return result_calculate(request, frame, &our_result);
681}
682
683static inline CC_HINT(always_inline) void instruction_done_debug(request_t *request, unlang_stack_frame_t *frame, unlang_t const *instruction)
684{
685 if (has_debug_braces(instruction)) {
686 REXDENT();
687
688 /*
689 * If we're at debug level 1, don't emit the closing
690 * brace as the opening brace wasn't emitted.
691 *
692 * Not a typo, we don't want to print the scratch_result
693 * here, aka the ones the section actually returned,
694 * vs the section result, which may have just been left
695 * at defaults.
696 */
698 RDEBUG("# %s %s%s%s", frame->instruction->debug_name,
699 frame->result_p == &frame->section_result ? "(" : "))",
701 frame->result_p == &frame->section_result ? "(" : "))");
702 } else {
703 RDEBUG2("} # %s %s%s%s", frame->instruction->debug_name,
704 frame->result_p == &frame->section_result ? "(" : "((",
706 frame->result_p == &frame->section_result ? ")" : "))");
707 }
708 }
709}
710
711/** Evaluates all the unlang nodes in a section
712 *
713 * This function interprets a list of unlang instructions at a given level using the same
714 * stack frame, and pushes additional frames onto the stack as needed.
715 *
716 * This function can be seen as moving horizontally.
717 *
718 * @param[in] request The current request.
719 * @param[in] frame The current stack frame.
720 * @return
721 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions in the current stack frame
722 * which may not be the same frame as when this function
723 * was called.
724 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
725 */
726static inline CC_HINT(always_inline)
728{
729 unlang_stack_t *stack = request->stack;
730 unlang_result_t *scratch = &frame->scratch_result;
731
732 /*
733 * Loop over all the instructions in this list.
734 */
735 while (frame->instruction) {
736 unlang_t const *instruction = frame->instruction;
739
741
742 fr_assert(instruction->debug_name != NULL); /* if this happens, all bets are off. */
743 fr_assert(unlang_ops[instruction->type].interpret != NULL);
744 fr_assert(frame->process != NULL);
745
746 REQUEST_VERIFY(request);
747
748 /*
749 * We're running this frame, so it can't possibly be yielded.
750 */
751 if (is_yielded(frame)) {
752 RDEBUG("%s - Resuming execution", instruction->debug_name);
753 yielded_clear(frame);
754 }
755
756#ifndef NDEBUG
757 /*
758 * Failure testing!
759 */
760 if (request->ins_max) {
761 request->ins_count++;
762
763 if (request->ins_count >= request->ins_max) {
764 RERROR("Failing request due to maximum instruction count %" PRIu64, request->ins_max);
765
767 }
768 }
769#endif
770
771 /*
772 * We're not re-entering this frame, this is the first
773 * time we're evaluating this instruction, so we should
774 * print debug braces and indent.
775 */
776 if (!is_repeatable(frame)) {
777 if (has_debug_braces(frame)) {
778 RDEBUG2("%s {", instruction->debug_name);
779 RINDENT();
780 }
781 /*
782 * Clear the repeatable flag so this frame
783 * won't get executed again unless it specifically
784 * requests it.
785 *
786 * The flag may still be set again during the
787 * process function to indicate that the frame
788 * should be evaluated again.
789 */
790 } else {
791 repeatable_clear(frame);
792 }
793
794 /*
795 * Execute an operation
796 */
797 RDEBUG4("** [%i] %s >> %s", stack->depth, __FUNCTION__,
798 unlang_ops[instruction->type].name);
799
801
802 /*
803 * catch plays games with the frame so we skip
804 * to the next catch section at a given depth,
805 * it's not safe to access frame->instruction
806 * after this point, and the cached instruction
807 * should be used instead.
808 */
809 ua = frame->process(&frame->scratch_result, request, frame);
810
811 RDEBUG4("** [%i] %s << %s (%s %d)", stack->depth, __FUNCTION__,
813 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<INVALID>"),
814 scratch->priority);
815
818
819 /*
820 * If the frame is cancelled we ignore the
821 * return code of the process function and
822 * pop the frame. We'll keep popping
823 * frames until we hit a non-cancelled frame
824 * or the top frame.
825 */
826 if (is_unwinding(frame)) goto calculate_result;
827
828 switch (ua) {
830 /*
831 * This marks all the cancellable
832 * frames with the unwind flag,
833 * and starts popping them.
834 */
837
838 /*
839 * The operation resulted in additional frames
840 * being pushed onto the stack, execution should
841 * now continue at the deepest frame.
842 */
844 fr_assert_msg(&stack->frame[stack->depth] > frame,
845 "Instruction %s returned UNLANG_ACTION_PUSHED_CHILD, "
846 "but stack depth was not increased",
847 instruction->name);
850
851 /*
852 * Yield control back to the scheduler, or whatever
853 * called the interpreter.
854 */
856 fr_assert_msg(&stack->frame[stack->depth] == frame,
857 "Instruction %s returned UNLANG_ACTION_YIELD, but pushed additional "
858 "frames for evaluation. Instruction should return UNLANG_ACTION_PUSHED_CHILD "
859 "instead", instruction->name);
861 yielded_set(frame);
862 RDEBUG4("** [%i] %s - yielding with current (%s %d)", stack->depth, __FUNCTION__,
863 fr_table_str_by_value(mod_rcode_table, scratch->rcode, "<invalid>"),
864 scratch->priority);
866
867 /*
868 * This action is intended to be returned by library
869 * functions. It reduces boilerplate.
870 */
872 frame->scratch_result.rcode = RLM_MODULE_FAIL; /* Let unlang_calculate figure out if this is the final result */
874
875 /*
876 * Instruction finished execution,
877 * check to see what we need to do next, and update
878 * the section rcode and priority.
879 */
881 calculate_result:
882 /*
883 * Merge in the scratch result _before_ printing
884 * out the rcode for the frame, so get what we'll
885 * actually return.
886 */
887 fa = result_calculate(request, frame, &frame->scratch_result);
888
889 instruction_done_debug(request, frame, instruction);
890
891 switch (fa) {
893 goto pop;
894
896 if (has_debug_braces(instruction)) {
897 REXDENT();
898 RDEBUG2("} # retrying the same section");
899 }
900 continue; /* with the current instruction */
901
902 default:
903 break;
904 }
905 break;
906
907 /*
908 * Execute the next instruction in this frame
909 */
911 if (has_debug_braces(instruction)) {
912 REXDENT();
913 RDEBUG2("}");
914 }
915 break;
916 } /* switch over return code from the interpret function */
917
918 frame_next(stack, frame);
919 }
920
921pop:
922 RDEBUG4("** [%i] %s - done current subsection with (%s %d), %s",
923 stack->depth, __FUNCTION__,
924 fr_table_str_by_value(mod_rcode_table, frame->result_p->rcode, "<invalid>"),
925 frame->result_p->priority,
926 frame->result_p == &(frame->section_result) ? "will set higher frame rcode" : "will NOT set higher frame rcode (result_p)");
927
929}
930
931/** Run the interpreter for a current request
932 *
933 * This function runs the interpreter for a request. It deals with popping
934 * stack frames, and calaculating the final result for the frame.
935 *
936 * @param[in] request to run. If this is an internal request
937 * the request may be freed by the interpreter.
938 * @param[in] running Is the interpreter already running.
939 * @return The final request rcode.
940 */
941CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
942{
943 unlang_stack_t *stack = request->stack;
944 unlang_interpret_t *intp = stack->intp;
945 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
946
947 /*
948 * This is needed to ensure that if a frame is marked
949 * for unwinding whilst the request is yielded, we
950 * unwind the cancelled frame correctly, instead of
951 * continuing.
952 */
954
955#ifndef NDEBUG
956 if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
958#endif
959
960 fr_assert(!unlang_request_is_scheduled(request)); /* if we're running it, it can't be scheduled */
961 fr_assert_msg(intp, "request has no interpreter associated");
962
963 RDEBUG4("** [%i] %s - interpret entered", stack->depth, __FUNCTION__);
964 if (!running) intp->funcs.resume(request, intp->uctx);
965
966 for (;;) {
967 fr_assert(stack->depth > 0);
969
970 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
972 switch (fa) {
973 next:
974 RDEBUG4("** [%i] %s - frame action next", stack->depth, __FUNCTION__);
976
977 case UNLANG_FRAME_ACTION_NEXT: /* Evaluate the current frame */
978 frame = &stack->frame[stack->depth];
979 fa = frame_eval(request, frame);
980 if (fa != UNLANG_FRAME_ACTION_POP) continue;
981
982 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
985
986 case UNLANG_FRAME_ACTION_POP: /* Pop this frame and check the one beneath it */
987 {
988 bool top_frame = is_top_frame(frame);
989 bool private_result = is_private_result(frame);
990
991 unlang_result_t section_result = frame->section_result; /* record the result of the frame before we pop it*/
992
994 /*
995 * Head on back up the stack
996 */
997 frame_pop(request, stack);
998 RDEBUG4("** [%i] %s - frame popped", stack->depth, __FUNCTION__);
999
1000 /*
1001 * Update the stack frame
1002 */
1003 frame = &stack->frame[stack->depth];
1004 DUMP_STACK;
1005
1006 /*
1007 * Transition back to the C stack
1008 *
1009 * We still need to merge in the previous frame's result,
1010 * but we don't care about the action, as we're returning.
1011 */
1012 if (top_frame) {
1013 if (!private_result) result_calculate(request, frame, &section_result);
1014 break; /* stop */
1015 }
1016
1017 /*
1018 * Don't process the section result for a frame if
1019 * the result is being consumed by a module.
1020 */
1021 if (private_result) {
1023 /*
1024 * Merge lower frame into higher frame.
1025 *
1026 * this _MUST_ be done, even on resume, because the
1027 * section result needs to be updated for the frame
1028 * being resumed, in case it cares about the rcode
1029 * like transaction sections.
1030 */
1031 } else {
1032 fa = result_pop(request, frame, &section_result);
1033 }
1034
1035 /*
1036 * Resume a "foreach" loop, or a "load-balance" section
1037 * or anything else that needs to be checked on the way
1038 * back on up the stack. Here we just resume evaluating
1039 * the frame, we don't advance the instruction.
1040 */
1041 if (!is_unwinding(frame) && is_repeatable(frame)) goto next;
1042
1043 /*
1044 * Close out the section we entered earlier
1045 */
1046 instruction_done_debug(request, frame, frame->instruction);
1047
1048 /*
1049 * If we're continuing after popping a frame
1050 * then we advance the instruction else we
1051 * end up executing the same code over and over...
1052 */
1053 switch (fa) {
1055 DEBUG4("** [%i] %s - continuing after subsection with (%s %d)",
1056 stack->depth, __FUNCTION__,
1058 frame->section_result.priority);
1059 frame_next(stack, frame);
1060 goto next;
1061
1062 /*
1063 * Else if we're really done with this frame
1064 * print some helpful debug...
1065 */
1066 default:
1067 RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
1068 stack->depth, __FUNCTION__,
1070 frame->section_result.priority);
1071 continue;
1072 }
1073
1074 }
1075
1077 /* Cannot yield from a nested call to unlang_interpret */
1078 fr_assert(!running);
1079
1080 RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
1081 intp->funcs.yield(request, intp->uctx);
1082 return RLM_MODULE_NOT_SET;
1083
1084 case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
1085 goto next;
1086 }
1087 break;
1088 }
1089
1090 fr_assert(stack->depth >= 0);
1091
1092 /*
1093 * We're at the top frame, return the result from the
1094 * stack, and get rid of the top frame.
1095 */
1096 RDEBUG4("** [%i] %s - interpret exiting, returning (%s)", stack->depth, __FUNCTION__,
1098
1099 DUMP_STACK;
1100
1101 {
1102 rlm_rcode_t rcode;
1103 /*
1104 * Record this now as the done functions may free
1105 * the request.
1106 */
1107 rcode = frame->section_result.rcode;
1108
1109 /*
1110 * This usually means the request is complete in its
1111 * entirety.
1112 */
1113 if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
1114
1115 return rcode;
1116 }
1117}
1118
1120 .self = {
1122 .debug_name = "empty-group",
1123 .actions = {
1124 .actions = {
1134 },
1135 .retry = RETRY_INIT,
1136 },
1137 },
1138};
1139
1140/** Push a configuration section onto the request stack for later interpretation.
1141 *
1142 */
1144{
1145 unlang_t *instruction = NULL;
1146
1147 /*
1148 * Interpretable unlang instructions are stored as CONF_DATA
1149 * associated with sections.
1150 */
1151 if (cs) {
1152 instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
1153 if (!instruction) {
1154 REDEBUG("Failed to find pre-compiled unlang for section %s %s { ... }",
1156 return -1;
1157 }
1158 }
1159
1160 return unlang_interpret_push_instruction(p_result, request, instruction, conf);
1161}
1162
1163/** Push an instruction onto the request stack for later interpretation.
1164 *
1165 */
1167{
1168 unlang_stack_t *stack = request->stack;
1169
1170 if (!instruction) {
1171 instruction = unlang_group_to_generic(&empty_group);
1172 }
1173
1174 /*
1175 * Push the default action, and the instruction which has
1176 * no action.
1177 */
1178 if (unlang_interpret_push(p_result, request, instruction, conf, UNLANG_NEXT_SIBLING) < 0) {
1179 return -1;
1180 }
1181
1182 RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
1183
1184 return 0;
1185}
1186
1187/** Allocate a new unlang stack
1188 *
1189 * @param[in] ctx to allocate stack in.
1190 * @return
1191 * - A new stack on success.
1192 * - NULL on OOM.
1193 */
1194void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
1195{
1196 /*
1197 * Should never be evaluated, is just here to reduce
1198 * branches, so we don't need to check for frame->instruction.
1199 */
1200 static unlang_t unlang_instruction = {
1201 .debug_name = "top",
1202 .actions = {
1203 /*
1204 * By default, functions don't change the section rcode.
1205 * We can't make generalisations about what the intent
1206 * of the function callbacks are, so isntead of having
1207 * implicit, confusing behaviour, we always discard the
1208 * rcode UNLESS the function explicitly sets it.
1209 */
1210 .actions = {
1221 },
1222 .retry = RETRY_INIT
1223 }
1224 };
1225
1227
1228 /*
1229 * If we have talloc_pooled_object allocate the
1230 * stack as a combined chunk/pool, with memory
1231 * to hold at mutable data for at least a quarter
1232 * of the maximum number of stack frames.
1233 *
1234 * Having a dedicated pool for mutable stack data
1235 * means we don't have memory fragmentations issues
1236 * as we would if request were used as the pool.
1237 *
1238 * This number is pretty arbitrary, but it seems
1239 * like too low level to make into a tuneable.
1240 */
1241 MEM(stack = talloc_zero_pooled_object(ctx, unlang_stack_t, UNLANG_STACK_MAX, 128)); /* 128 bytes per state */
1242 stack->frame[0].result_p = &stack->frame[0].section_result;
1243 stack->frame[0].scratch_result.rcode = RLM_MODULE_NOT_SET;
1244 stack->frame[0].scratch_result.priority = MOD_ACTION_NOT_SET;
1245 stack->frame[0].section_result.rcode = RLM_MODULE_NOT_SET;
1246 stack->frame[0].section_result.priority = MOD_ACTION_NOT_SET;
1247 stack->frame[0].instruction = &unlang_instruction; /* The top frame has no instruction, so we use a dummy one */
1248
1249 return stack;
1250}
1251
1252/** Indicate to the caller of the interpreter that this request is complete
1253 *
1254 */
1256{
1257 unlang_stack_t *stack = request->stack;
1258 unlang_interpret_t *intp;
1259
1260 if (!fr_cond_assert(stack != NULL)) return;
1261
1262 intp = stack->intp;
1263
1264 request->master_state = REQUEST_DONE;
1265 switch (request->type) {
1267 intp->funcs.done_external(request, frame_current(request)->section_result.rcode, intp->uctx);
1268 break;
1269
1271 intp->funcs.done_internal(request, frame_current(request)->section_result.rcode, intp->uctx);
1272 break;
1273
1275 intp->funcs.done_detached(request, frame_current(request)->section_result.rcode, intp->uctx); /* Callback will usually free the request */
1276 break;
1277 }
1278}
1279
1280/** Tell the interpreter to detach the request
1281 *
1282 * This function should not be called directly use unlang_interpret_signal(request, FR_SIGNAL_DETACH) instead.
1283 * This will ensure all frames on the request's stack receive the detach signal.
1284 */
1285static inline CC_HINT(always_inline)
1287{
1288 unlang_stack_t *stack = request->stack;
1289 unlang_interpret_t *intp;
1290
1291 if (!fr_cond_assert(stack != NULL)) return;
1292
1293 if (!request_is_detachable(request)) return;
1294
1295 intp = stack->intp;
1296
1297 intp->funcs.detach(request, intp->uctx);
1298}
1299
1301{
1302 unlang_stack_t *stack = request->stack;
1303 unlang_interpret_t *intp;
1304
1305 if (!fr_cond_assert(stack != NULL)) return;
1306
1307 intp = stack->intp;
1308
1309 request->async->priority = priority;
1310
1311 if (intp->funcs.prioritise) intp->funcs.prioritise(request, intp->uctx);
1312}
1313
1314/** Delivers a frame to one or more frames in the stack
1315 *
1316 * This is typically called via an "async" action, i.e. an action outside
1317 * of the normal processing of the request.
1318 *
1319 * For FR_SIGNAL_CANCEL all frames are marked up for cancellation, but the
1320 * cancellation is handled by the interpret.
1321 *
1322 * Other signal types are delivered immediately, inrrespecitve of whether
1323 * the request is currently being processed or not.
1324 *
1325 * Signaling stops at the "limit" frame. This is so that keywords
1326 * such as "timeout" and "limit" can signal frames *lower* than theirs
1327 * to stop, but then continue with their own work.
1328 *
1329 * @note It's better (clearer) to use one of the unwind_* functions
1330 * unless the entire request is being cancelled.
1331 *
1332 * @param[in] request The current request.
1333 * @param[in] action to signal.
1334 * @param[in] limit the frame at which to stop signaling.
1335 */
1336void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
1337{
1338 unlang_stack_frame_t *frame;
1339 unlang_stack_t *stack = request->stack;
1340 int i, depth = stack->depth;
1341
1342 (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1343
1344 fr_assert(stack->depth >= 1);
1345
1346 /*
1347 * Does not complete the unwinding here, just marks
1348 * up the frames for unwinding. The request must
1349 * be marked as runnable to complete the cancellation.
1350 */
1351 if (action == FR_SIGNAL_CANCEL) unwind_to_depth(stack, limit);
1352
1353 /*
1354 * Walk back up the stack, calling signal handlers
1355 * to cancel any pending operations and free/release
1356 * any resources.
1357 *
1358 * There may be multiple resumption points in the
1359 * stack, as modules can push xlats and function
1360 * calls.
1361 *
1362 * Note: Slightly confusingly, a cancellation signal
1363 * can still be delivered to a frame that is not
1364 * cancellable, but the frame won't be automatically
1365 * unwound.
1366 */
1367 for (i = depth; i >= limit; i--) {
1368 frame = &stack->frame[i];
1369 if (frame->signal) {
1370 frame->signal(request, frame, action);
1371
1372 /*
1373 * Once the cancellation function has been
1374 * called, the frame is no longer in a state
1375 * where it can accept further signals.
1376 */
1377 if (action == FR_SIGNAL_CANCEL) frame->signal = NULL;
1378 }
1379 }
1380}
1381
1382/** Send a signal (usually stop) to a request
1383 *
1384 * This is typically called via an "async" action, i.e. an action
1385 * outside of the normal processing of the request.
1386 *
1387 * @note This does NOT immediately stop the request, it just deliveres
1388 * signals, and in the case of a cancel, marks up frames for unwinding
1389 * and adds it to the runnable queue if it's yielded.
1390 *
1391 * @note This function should be safe to call anywhere.
1392 *
1393 * @param[in] request The current request.
1394 * @param[in] action to signal.
1395 */
1397{
1398 unlang_stack_t *stack = request->stack;
1399
1400 switch (action) {
1401 case FR_SIGNAL_DETACH:
1402 /*
1403 * Ensure the request is able to be detached
1404 * else don't signal.
1405 */
1406 if (!fr_cond_assert(request_is_detachable(request))) return;
1407 break;
1408
1409 default:
1410 break;
1411 }
1412
1413 /*
1414 * Requests that haven't been run through the interpreter
1415 * yet should have a stack depth of zero, so we don't
1416 * need to do anything.
1417 */
1418 if (!stack || stack->depth == 0) return;
1419
1420 unlang_stack_signal(request, action, 1);
1421
1422 switch (action) {
1423 case FR_SIGNAL_CANCEL:
1424 {
1425 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1426 /*
1427 * Let anything that cares, know that the
1428 * request was forcefully stopped.
1429 */
1430 request->master_state = REQUEST_STOP_PROCESSING;
1431
1432 /*
1433 * Give cancelled requests the highest priority
1434 * to get them to release resources ASAP.
1435 */
1436 unlang_interpret_request_prioritise(request, UINT32_MAX);
1437
1438 /*
1439 * If the request is yielded, mark it as runnable
1440 *
1441 * If the request was _not_ cancelled, it means
1442 * it's not cancellable, and we need to let the
1443 * request progress normally.
1444 *
1445 * A concrete example of this, is the parent of
1446 * subrequests, which must not continue until
1447 * the subrequest is done.
1448 */
1449 if (stack && is_yielded(frame) && is_unwinding(frame) && !unlang_request_is_scheduled(request)) {
1451 }
1452 }
1453 break;
1454
1455 case FR_SIGNAL_DETACH:
1456 /*
1457 * Cleanup any cross-request pointers, and mark the
1458 * request as detached. When the request completes it
1459 * should by automatically freed.
1460 */
1462 break;
1463
1464 default:
1465 break;
1466 }
1467}
1468
1470{
1471 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1472 request_t *request = talloc_get_type_abort(retry->request, request_t);
1473
1474 RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1475
1476 /*
1477 * Signal all lower frames to exit.
1478 */
1479 unlang_stack_signal(request, FR_SIGNAL_CANCEL, retry->depth);
1480
1481 retry->state = FR_RETRY_MRD;
1483}
1484
1486{
1487 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1488 request_t *request = talloc_get_type_abort(retry->request, request_t);
1489
1490 RDEBUG("Maximum timeout reached, signalling interpreter to stop the request.");
1491
1492 /*
1493 * Stop the entire request.
1494 */
1496}
1497
1498
1499/** Set a timeout for a request.
1500 *
1501 * The timeout is associated with the current stack frame.
1502 *
1503 */
1505{
1506 unlang_stack_t *stack = request->stack;
1507 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1508 unlang_retry_t *retry;
1509
1510 fr_assert(!frame->retry);
1512
1513 frame->retry = retry = talloc_zero(frame, unlang_retry_t);
1514 if (!frame->retry) return -1;
1515
1516 retry->request = request;
1517 retry->depth = stack->depth;
1518 retry->state = FR_RETRY_CONTINUE;
1519 retry->count = 1;
1520
1521 return fr_timer_in(retry, unlang_interpret_event_list(request)->tl, &retry->ev, timeout,
1522 false, instruction_timeout_handler, request);
1523}
1524
1525
1526/** Return the depth of the request's stack
1527 *
1528 */
1530{
1531 unlang_stack_t *stack = request->stack;
1532
1533 return stack->depth;
1534}
1535
1536/** Get the last instruction result OR the last frame that was popped
1537 *
1538 * @param[in] request The current request.
1539 * @return the current rcode for the frame.
1540 */
1542{
1543 return frame_current(request)->result_p->rcode;
1544}
1545
1546/** Get the last instruction priority OR the last frame that was popped
1547 *
1548 * @param[in] request The current request.
1549 * @return the current rcode for the frame.
1550 */
1555
1556/** Get the last instruction result OR the last frame that was popped
1557 *
1558 * @param[in] request The current request.
1559 * @return the current result for the frame.
1560 */
1562{
1563 return frame_current(request)->result_p;
1564}
1565
1566/** Return whether a request is currently scheduled
1567 *
1568 */
1570{
1571 unlang_stack_t *stack = request->stack;
1572 unlang_interpret_t *intp = stack->intp;
1573
1574 return intp->funcs.scheduled(request, intp->uctx);
1575}
1576
1577/** Return whether a request has been cancelled
1578 */
1580{
1581 return (request->master_state == REQUEST_STOP_PROCESSING);
1582}
1583
1584/** Return whether a request has been marked done
1585 */
1587{
1588 return (request->master_state == REQUEST_DONE);
1589}
1590
1591/** Check if a request as resumable.
1592 *
1593 * @param[in] request The current request.
1594 * @return
1595 * - true if the request is resumable (i.e. has yielded)
1596 * - false if the request is not resumable (i.e. has not yielded)
1597 */
1599{
1600 unlang_stack_t *stack = request->stack;
1601 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1602
1603 return is_yielded(frame);
1604}
1605
1606/** Mark a request as resumable.
1607 *
1608 * It's not called "unlang_interpret", because it doesn't actually
1609 * resume the request, it just schedules it for resumption.
1610 *
1611 * @note that this schedules the request for resumption. It does not immediately
1612 * start running the request.
1613 *
1614 * @param[in] request The current request.
1615 */
1617{
1618 unlang_stack_t *stack = request->stack;
1619 unlang_interpret_t *intp = stack->intp;
1620 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1621
1622 bool scheduled = unlang_request_is_scheduled(request);
1623
1624 /*
1625 * The request hasn't yielded, OR it's already been
1626 * marked as runnable. Don't do anything.
1627 *
1628 * The IO code, or children have no idea where they're
1629 * being called from. They just ask to mark the parent
1630 * resumable when they're done. So we have to check here
1631 * if this request is resumable.
1632 *
1633 * If the parent called the child directly, then the
1634 * parent hasn't yielded, so it isn't resumable. When
1635 * the child is done, the parent will automatically
1636 * continue running. We therefore don't need to insert
1637 * the parent into the backlog.
1638 *
1639 * Multiple child request may also mark a parent request
1640 * runnable, before the parent request starts running.
1641 */
1642 if (!is_yielded(frame) || scheduled) {
1643 RDEBUG3("Not marking request %s as runnable due to%s%s",
1644 request->name,
1645 !is_yielded(frame) ?
1646 " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
1647 return;
1648 }
1649
1650 RDEBUG3("Interpreter - Request marked as runnable");
1651
1652 intp->funcs.mark_runnable(request, intp->uctx);
1653}
1654
1655/** Get a talloc_ctx which is valid only for this frame
1656 *
1657 * @param[in] request The current request.
1658 * @return
1659 * - a TALLOC_CTX which is valid only for this stack frame
1660 */
1662{
1663 unlang_stack_t *stack = request->stack;
1664 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1665
1666 if (frame->state) return (TALLOC_CTX *)frame->state;
1667
1668 /*
1669 * If the frame doesn't ordinarily have a
1670 * state, assume the caller knows what it's
1671 * doing and allocate one.
1672 */
1673 return (TALLOC_CTX *)(frame->state = talloc_new(request));
1674}
1675
1677 { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
1679};
1680
1681static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
1682 UNUSED xlat_ctx_t const *xctx,
1683 request_t *request, fr_value_box_list_t *args);
1684
1685/** Signal the request to stop executing
1686 *
1687 * The request can't be running at this point because we're in the event
1688 * loop. This means the request is always in a consistent state when
1689 * the timeout event fires, even if that's state is waiting on I/O.
1690 */
1692{
1693 request_t *request = talloc_get_type_abort(uctx, request_t);
1694
1695 RDEBUG2("Request canceled by dynamic timeout");
1696 /*
1697 * Cleans up the memory allocated to hold
1698 * the pointer, not the event itself.
1699 */
1700 talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
1701
1703}
1704
1705/** Allows a request to dynamically alter its own lifetime
1706 *
1707 * %cancel(<timeout>)
1708 *
1709 * If timeout is 0, then the request is immediately cancelled.
1710 */
1712 UNUSED xlat_ctx_t const *xctx,
1713 request_t *request, fr_value_box_list_t *args)
1714{
1715 fr_value_box_t *timeout;
1717 fr_timer_t **ev_p, **ev_p_og;
1718 fr_value_box_t *vb;
1719 fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
1720
1721 XLAT_ARGS(args, &timeout);
1722
1723 /*
1724 * No timeout means cancel immediately, so yield allowing
1725 * the interpreter to run the event we added to cancel
1726 * the request.
1727 *
1728 * We call unlang_xlat_yield to keep the interpreter happy
1729 * as it expects to see a resume function set.
1730 */
1731 if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
1733 return XLAT_ACTION_DONE;
1734 }
1735
1736 /*
1737 * First see if we already have a timeout event
1738 * that was previously added by this xlat.
1739 */
1740 ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
1741 if (ev_p) {
1742 if (*ev_p) when = fr_timer_when(*ev_p); /* *ev_p should never be NULL, really... */
1743 } else {
1744 /*
1745 * Must not be parented from the request
1746 * as this is freed by request data.
1747 */
1748 MEM(ev_p = talloc_zero(NULL, fr_timer_t *));
1749 }
1750
1751 if (unlikely(fr_timer_in(ev_p, el->tl, ev_p,
1752 timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
1753 false, unlang_cancel_event, request) < 0)) {
1754 RPERROR("Failed inserting cancellation event");
1755 talloc_free(ev_p);
1756 return XLAT_ACTION_FAIL;
1757 }
1758 if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
1759 UNCONST(fr_timer_t **, ev_p), true, true, false) < 0)) {
1760 RPERROR("Failed associating cancellation event with request");
1761 talloc_free(ev_p);
1762 return XLAT_ACTION_FAIL;
1763 }
1764
1765 if (ev_p_og) {
1766 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
1767
1768 /*
1769 * Return how long before the previous
1770 * cancel event would have fired.
1771 *
1772 * This can be useful for doing stacked
1773 * cancellations in policy.
1774 */
1775 vb->vb_time_delta = fr_time_sub(when, unlang_interpret_event_list(request)->tl->time());
1777 }
1778
1779 /*
1780 * No value if this is the first cleanup event
1781 */
1782 return XLAT_ACTION_DONE;
1783}
1784
1786 { .required = true, .single = true, .type = FR_TYPE_STRING },
1788};
1789
1790/** Get information about the interpreter state
1791 *
1792 * @ingroup xlat_functions
1793 */
1795 UNUSED xlat_ctx_t const *xctx,
1796 request_t *request, fr_value_box_list_t *in)
1797{
1798 unlang_stack_t *stack = request->stack;
1799 int depth = stack->depth;
1800 unlang_stack_frame_t *frame;
1801 unlang_t const *instruction;
1802 fr_value_box_t *arg = fr_value_box_list_head(in);
1803 char const *fmt = arg->vb_strvalue;
1804 fr_value_box_t *vb;
1805
1806 MEM(vb = fr_value_box_alloc_null(ctx));
1807
1808 /*
1809 * Find the correct stack frame.
1810 */
1811 while (*fmt == '.') {
1812 if (depth <= 1) {
1813 if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
1814 error:
1815 talloc_free(vb);
1816 return XLAT_ACTION_FAIL;
1817 }
1818 goto finish;
1819 }
1820
1821 fmt++;
1822 depth--;
1823 }
1824
1825 /*
1826 * Get the current instruction.
1827 */
1828 frame = &stack->frame[depth];
1829 instruction = frame->instruction;
1830
1831 /*
1832 * Nothing there...
1833 */
1834 if (!instruction) {
1835 talloc_free(vb);
1836 return XLAT_ACTION_DONE;
1837 }
1838
1839 /*
1840 * How deep the current stack is.
1841 */
1842 if (strcmp(fmt, "depth") == 0) {
1843 fr_value_box_int32(vb, NULL, depth, false);
1844 goto finish;
1845 }
1846
1847 /*
1848 * The current module
1849 */
1850 if (strcmp(fmt, "module") == 0) {
1851 if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
1852
1853 goto finish;
1854 }
1855
1856 /*
1857 * Name of the instruction.
1858 */
1859 if (strcmp(fmt, "name") == 0) {
1860 if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
1861 strlen(instruction->name), false) < 0) goto error;
1862 goto finish;
1863 }
1864
1865 /*
1866 * The request processing stage.
1867 */
1868 if (strcmp(fmt, "processing_stage") == 0) {
1869 if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
1870
1871 goto finish;
1872 }
1873
1874 /*
1875 * The current return code.
1876 */
1877 if (strcmp(fmt, "rcode") == 0) {
1878 if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
1879
1880 goto finish;
1881 }
1882
1883 /*
1884 * The virtual server handling the request
1885 */
1886 if (strcmp(fmt, "server") == 0) {
1887 if (!unlang_call_current(request)) goto finish;
1888
1889 if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(unlang_call_current(request)), false) < 0) goto error;
1890
1891 goto finish;
1892 }
1893
1894 /*
1895 * Unlang instruction type.
1896 */
1897 if (strcmp(fmt, "type") == 0) {
1898 if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
1899 strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
1900
1901 goto finish;
1902 }
1903
1904 /*
1905 * All of the remaining things need a CONF_ITEM.
1906 */
1907 if (!instruction->ci) {
1908 if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 3, false) < 0) goto error;
1909
1910 goto finish;
1911 }
1912
1913 /*
1914 * Line number of the current section.
1915 */
1916 if (strcmp(fmt, "line") == 0) {
1917 fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
1918
1919 goto finish;
1920 }
1921
1922 /*
1923 * Filename of the current section.
1924 */
1925 if (strcmp(fmt, "filename") == 0) {
1926 if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
1927
1928 goto finish;
1929 }
1930
1931finish:
1932 if (vb->type != FR_TYPE_NULL) {
1934 } else {
1935 talloc_free(vb);
1936 }
1937
1938 return XLAT_ACTION_DONE;
1939}
1940
1941/** Initialize a unlang compiler / interpret.
1942 *
1943 * @param[in] ctx to bind lifetime of the interpret to.
1944 * Shouldn't be any free order issues here as
1945 * the interpret itself has no state.
1946 * But event loop should be stopped before
1947 * freeing the interpret.
1948 * @param[in] el for any timer or I/O events.
1949 * @param[in] funcs Callbacks to used to communicate request
1950 * state to our owner.
1951 * @param[in] uctx Data to pass to callbacks.
1952 */
1954 fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
1955{
1956 unlang_interpret_t *intp;
1957
1958 fr_assert(funcs->init_internal);
1959
1960 fr_assert(funcs->done_internal);
1961 fr_assert(funcs->done_detached);
1962 fr_assert(funcs->done_external);
1963
1964 fr_assert(funcs->detach);
1965 fr_assert(funcs->yield);
1966 fr_assert(funcs->resume);
1967 fr_assert(funcs->mark_runnable);
1968 fr_assert(funcs->scheduled);
1969
1970 MEM(intp = talloc(ctx, unlang_interpret_t));
1971 *intp = (unlang_interpret_t){
1972 .el = el,
1973 .funcs = *funcs,
1974 .uctx = uctx
1975 };
1976
1977 return intp;
1978}
1979
1980/** Discard the bottom most frame on the request's stack
1981 *
1982 * This is used for cleaning up after errors. i.e. the caller
1983 * uses a push function, and experiences an error and needs to
1984 * remove the frame that was just pushed.
1985 */
1987{
1988 frame_pop(request, request->stack);
1989}
1990
1991/** Set a specific interpreter for a request
1992 *
1993 */
1995{
1996 unlang_stack_t *stack = request->stack;
1997 stack->intp = intp;
1998}
1999
2000/** Get the interpreter set for a request
2001 *
2002 */
2004{
2005 unlang_stack_t *stack = request->stack;
2006
2007 return stack->intp;
2008}
2009
2010/** Get the event list for the current interpreter
2011 *
2012 */
2014{
2015 unlang_stack_t *stack = request->stack;
2016
2017 if (!stack->intp) return NULL;
2018
2019 return stack->intp->el;
2020}
2021
2022/** Set the default interpreter for this thread
2023 *
2024 */
2026{
2027 if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
2028
2029 intp_thread_default = intp;
2030}
2031
2032/** Get the default interpreter for this thread
2033 *
2034 * This allows detached requests to be executed asynchronously
2035 */
2037{
2038 if (!intp_thread_default) return NULL;
2039
2040 return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
2041}
2042
2044{
2045 xlat_t *xlat;
2046 /*
2047 * Should be void, but someone decided not to register multiple xlats
2048 * breaking the convention we use everywhere else in the server...
2049 */
2050 if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2052
2053 if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
2055
2056 return 0;
2057}
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_STOP_PROCESSING
Break out of processing the current request (unwind).
Definition action.h:42
@ 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
static int const char char buffer[256]
Definition acutest.h:576
va_list args
Definition acutest.h:770
static int const char * fmt
Definition acutest.h:573
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition call.c:225
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1184
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition cf_util.c:1762
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1170
#define cf_lineno(_cf)
Definition cf_util.h:104
#define cf_data_find(_cf, _type, _name)
Definition cf_util.h:244
#define cf_filename(_cf)
Definition cf_util.h:107
fr_table_num_sorted_t const mod_action_table[]
Definition compile.c:93
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:78
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition dcursor.h:437
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#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:210
#define MEM(x)
Definition debug.h:36
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
static fr_slen_t in
Definition dict.h:841
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:1794
void unlang_interpret_request_prioritise(request_t *request, uint32_t priority)
Definition interpret.c:1300
static size_t unlang_action_table_len
Definition interpret.c:52
void stack_dump_with_actions(request_t *request)
Definition interpret.c:255
static fr_table_num_ordered_t const unlang_frame_action_table[]
Definition interpret.c:54
static fr_table_num_ordered_t const result_p_location_table[]
Definition interpret.c:137
static void unlang_interpret_request_detach(request_t *request)
Tell the interpreter to detach the request.
Definition interpret.c:1286
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:941
static int find_result_p_location(result_p_location_t *location, void **chunk, request_t *request, void *ptr)
Try and figure out where result_p points to.
Definition interpret.c:77
bool unlang_request_is_done(request_t const *request)
Return whether a request has been marked done.
Definition interpret.c:1586
static void stack_dump_body(request_t *request, bool with_actions)
Definition interpret.c:235
static unlang_group_t empty_group
Definition interpret.c:1119
unlang_result_t * unlang_interpret_result(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1561
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:1986
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1504
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1255
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:727
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:1994
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:2003
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1529
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1616
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition interpret.c:1785
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1661
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1569
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition interpret.c:2043
void stack_dump(request_t *request)
Definition interpret.c:250
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:2036
fr_dict_t const * old_dict
the previous dictionary for the request
Definition interpret.c:349
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition interpret.c:1194
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition interpret.c:2025
#define DUMP_STACK
Definition interpret.c:259
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:1551
static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1469
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:1953
static void instruction_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1485
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition interpret.c:1579
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:1166
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:1691
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1396
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition interpret.c:1676
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:1143
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:453
static fr_table_num_ordered_t const unlang_action_table[]
Definition interpret.c:45
static int _local_variables_free(unlang_variable_ref_t *ref)
Definition interpret.c:353
static size_t result_p_location_table_len
Definition interpret.c:144
static void instruction_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:146
bool unlang_interpret_is_resumable(request_t *request)
Check if a request as resumable.
Definition interpret.c:1598
static void instruction_done_debug(request_t *request, unlang_stack_frame_t *frame, unlang_t const *instruction)
Definition interpret.c:683
int unlang_interpret_push(unlang_result_t *result_p, 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:283
result_p_location_t
Definition interpret.c:64
@ RESULT_P_LOCATION_SCRATCH
Definition interpret.c:67
@ RESULT_P_LOCATION_MODULE_RCTX
Definition interpret.c:69
@ RESULT_P_LOCATION_STATE
Definition interpret.c:68
@ RESULT_P_LOCATION_FRAME
Definition interpret.c:66
@ RESULT_P_LOCATION_FUNCTION_RCTX
Definition interpret.c:70
@ RESULT_P_LOCATION_UNKNOWN
Definition interpret.c:65
request_t * request
the request
Definition interpret.c:350
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:656
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:1336
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:1711
static size_t unlang_frame_action_table_len
Definition interpret.c:59
rlm_rcode_t unlang_interpret_rcode(request_t *request)
Get the last instruction result OR the last frame that was popped.
Definition interpret.c:1541
static void frame_dump(request_t *request, unlang_stack_frame_t *frame, bool with_actions)
Definition interpret.c:179
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:389
static void actions_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:161
static _Thread_local unlang_interpret_t * intp_thread_default
The default interpreter instance for this thread.
Definition interpret.c:43
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2013
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:39
unlang_request_prioritise_t prioritise
Function to re-priotise a request in the runnable queue.
Definition interpret.h:129
unlang_mod_action_t priority
The priority or action for that rcode.
Definition interpret.h:136
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:153
unlang_request_done_t done_internal
Function called when an internal request completes.
Definition interpret.h:119
unlang_request_resume_t resume
Function called when a request is resumed.
Definition interpret.h:124
#define UNLANG_SUB_FRAME
Definition interpret.h:37
unlang_request_done_t done_external
Function called when a external request completes.
Definition interpret.h:118
unlang_request_init_t detach
Function called when a request is detached.
Definition interpret.h:122
unlang_request_runnable_t mark_runnable
Function called when a request needs to be added back to the runnable queue.
Definition interpret.h:125
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:134
unlang_request_yield_t yield
Function called when a request yields.
Definition interpret.h:123
unlang_request_done_t done_detached
Function called when a detached request completes.
Definition interpret.h:120
rlm_rcode_t default_rcode
The default return code for the frame.
Definition interpret.h:143
unlang_request_scheduled_t scheduled
Function to check if a request is already scheduled.
Definition interpret.h:127
unlang_request_init_t init_internal
Function called to initialise an internal request.
Definition interpret.h:116
struct unlang_interpret_s unlang_interpret_t
Interpreter handle.
Definition interpret.h:48
Configuration structure to make it easier to pass configuration options to initialise the frame with.
Definition interpret.h:141
External functions provided by the owner of the interpret.
Definition interpret.h:110
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:443
#define DEBUG_ENABLED5
True if global debug level 1-5 messages are enabled.
Definition log.h:261
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RERROR(fmt,...)
Definition log.h:298
#define DEBUG4(_fmt,...)
Definition log.h:267
#define RPERROR(fmt,...)
Definition log.h:302
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RDEBUG4(fmt,...)
Definition log.h:344
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
Definition base.c:31
talloc_free(reap)
Stores all information relating to an event list.
Definition event.c:377
static char * stack[MAX_STACK]
Definition radmin.c:159
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VOID
User data.
unsigned int uint32_t
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
unlang_mod_action_t
Definition mod_action.h:39
@ MOD_ACTION_NOT_SET
Definition mod_action.h:40
@ MOD_ACTION_RETURN
Definition mod_action.h:43
@ MOD_ACTION_REJECT
Definition mod_action.h:42
@ MOD_PRIORITY_MAX
Definition mod_action.h:60
@ MOD_ACTION_RETRY
Definition mod_action.h:41
fr_retry_config_t retry
Definition mod_action.h:65
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:64
Declarations for the unlang module interface.
void * rctx
for resume / signal
Definition module_priv.h:63
A module stack entry.
Definition module_priv.h:45
int fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition pair.c:1823
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define RDEBUG_ENABLED()
Definition radclient.h:49
static rs_t * conf
Definition radsniff.c:53
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:40
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:45
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:46
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_TIMEOUT
Module (or section) timed out.
Definition rcode.h:50
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:47
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:49
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:52
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:48
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:51
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
Definition rcode.h:44
#define REQUEST_VERIFY(_x)
Definition request.h:305
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
Definition request.h:178
@ REQUEST_TYPE_INTERNAL
A request generated internally.
Definition request.h:179
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
Definition request.h:180
#define request_is_detachable(_x)
Definition request.h:187
@ REQUEST_DONE
Request has completed.
Definition request.h:89
@ REQUEST_STOP_PROCESSING
Request has been signalled to stop.
Definition request.h:88
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.
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
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
An element in an arbitrarily ordered array of name to num mappings.
Definition table.h:57
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:177
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_t fr_timer_when(fr_timer_t *ev)
Internal timestamp representing when the timer should fire.
Definition timer.c:719
An event timer list.
Definition timer.c:50
A timer event.
Definition timer.c:84
#define fr_timer_in(...)
Definition timer.h:87
static fr_event_list_t * el
uint8_t required
Argument must be present, and non-empty.
Definition xlat.h:146
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:383
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_FAIL
An xlat function failed.
Definition xlat.h:44
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:145
Private interpreter structures and functions.
fr_retry_state_t state
#define unlang_frame_perf_resume(_x)
unlang_result_t section_result
The aggregate result of executing all siblings in this section.
static void frame_pop(request_t *request, unlang_stack_t *stack)
Pop a stack frame, removing any associated dynamically allocated state.
unlang_t * next
Next node (executed on UNLANG_ACTION_EXECUTE_NEXT et al).
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.
unlang_result_t * result_p
Where to write the result of executing the current instruction.
static bool is_repeatable(unlang_stack_frame_t const *frame)
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:98
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.
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.
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.
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)
static unlang_stack_frame_t * frame_current(request_t *request)
static bool is_private_result(unlang_stack_frame_t const *frame)
char const * name
Unknown...
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:49
@ UNLANG_TYPE_MODULE
Module method.
Definition unlang_priv.h:47
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
char const * name
Name of the operation.
unlang_frame_action_t
Allows the frame evaluator to signal the interpreter.
Definition unlang_priv.h:88
@ 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:89
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
Definition unlang_priv.h:93
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
Definition unlang_priv.h:92
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
Definition unlang_priv.h:91
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.
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_t * children
Children beneath this group.
unlang_frame_flag_t flag
Flags that mark up the frame for various things such as being the point where break,...
static bool is_unwinding(unlang_stack_frame_t const *frame)
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
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:4158
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:4379
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:640
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:651
static size_t char ** out
Definition value.h:1020
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363
xlat_t * xlat_func_register(TALLOC_CTX *ctx, char const *name, xlat_func_t func, fr_type_t return_type)
Register an xlat function.
Definition xlat_func.c:216