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: 9e6ce1db6aa50fa277b24c4aaa324b92343ed9dd $
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: 9e6ce1db6aa50fa277b24c4aaa324b92343ed9dd $")
26
27#include <freeradius-devel/server/base.h>
28#include <freeradius-devel/server/modpriv.h>
29#include <freeradius-devel/unlang/xlat_func.h>
30
31#include "interpret_priv.h"
32#include "module_priv.h"
33#include "parallel_priv.h"
34
35
36/** The default interpreter instance for this thread
37 */
39
41 { L("unwind"), UNLANG_ACTION_UNWIND },
42 { L("calculate-result"), UNLANG_ACTION_CALCULATE_RESULT },
43 { L("next"), UNLANG_ACTION_EXECUTE_NEXT },
44 { L("pushed-child"), UNLANG_ACTION_PUSHED_CHILD },
46 { L("yield"), UNLANG_ACTION_YIELD }
47};
49
56
57#ifndef NDEBUG
58static void instruction_dump(request_t *request, unlang_t const *instruction)
59{
60 RINDENT();
61 if (!instruction) {
62 RDEBUG2("instruction <none>");
63 REXDENT();
64 return;
65 }
66
67 RDEBUG2("type %s", unlang_ops[instruction->type].name);
68 RDEBUG2("name %s", instruction->name);
69 RDEBUG2("debug_name %s", instruction->debug_name);
70 REXDENT();
71}
72
73static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
74{
75 unlang_op_t *op = NULL;
76
77 if (frame->instruction) op = &unlang_ops[frame->instruction->type];
78
79 instruction_dump(request, frame->instruction);
80
81 RINDENT();
82 if (frame->state) RDEBUG2("state %s (%p)", talloc_get_name(frame->state), frame->state);
83 if (frame->next) {
84 RDEBUG2("next %s", frame->next->debug_name);
85 } else {
86 RDEBUG2("next <none>");
87 }
88 RDEBUG2("result %s", fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
89 RDEBUG2("priority %d", frame->priority);
90 RDEBUG2("top_frame %s", is_top_frame(frame) ? "yes" : "no");
91 RDEBUG2("repeat %s", is_repeatable(frame) ? "yes" : "no");
92 RDEBUG2("break_point %s", is_break_point(frame) ? "yes" : "no");
93 RDEBUG2("return_point %s", is_return_point(frame) ? "yes" : "no");
94 RDEBUG2("resumable %s", is_yielded(frame) ? "yes" : "no");
95
96 /*
97 * Call the custom frame dump function
98 */
99 if (op && op->dump) op->dump(request, frame);
100
101 REXDENT();
102}
103
104static char *stack_unwind_flag_dump(uint8_t unwind)
105{
106 static __thread char buf[256];
107 size_t len;
108
109#define UNWIND_FLAG_DUMP(attrib) \
110 if (unwind & attrib) strcat(buf, #attrib" ")
111
112 snprintf(buf, sizeof(buf), "unwind=0x%x (", unwind);
113
117
118 len = strlen(buf);
119 if (buf[len - 1] == ' ') buf[len - 1] = '\0'; /* Trim trailing space */
120 strcat(buf, ")");
121
122#undef UNWIND_FLAG_DUMP
123
124 return buf;
125}
126
127static void stack_dump(request_t *request)
128{
129 int i;
130 unlang_stack_t *stack = request->stack;
131
132 RDEBUG2("----- Begin stack debug [depth %i, %s] -----", stack->depth, stack_unwind_flag_dump(stack->unwind));
133 for (i = stack->depth; i >= 0; i--) {
134 unlang_stack_frame_t *frame = &stack->frame[i];
135
136 RDEBUG2("[%d] Frame contents", i);
137 frame_dump(request, frame);
138 }
139 RDEBUG2("----- End stack debug [depth %i, %s] -------", stack->depth, stack_unwind_flag_dump(stack->unwind));
140}
141#define DUMP_STACK if (DEBUG_ENABLED5) stack_dump(request)
142#else
143#define DUMP_STACK
144#endif
145
146/** Push a new frame onto the stack
147 *
148 * @param[in] request to push the frame onto.
149 * @param[in] instruction One or more unlang_t nodes describing the operations to execute.
150 * @param[in] default_rcode The default result.
151 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
152 * or to execute subsequent nodes.
153 * @param[in] top_frame Return out of the unlang interpret when popping this frame.
154 * Hands execution back to whatever called the interpret.
155 * @return
156 * - 0 on success.
157 * - -1 on call stack too deep.
158 */
159int unlang_interpret_push(request_t *request, unlang_t const *instruction,
160 rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
161{
162 unlang_stack_t *stack = request->stack;
164
165 fr_assert(instruction || top_frame);
166
167#ifndef NDEBUG
168 if (DEBUG_ENABLED5) RDEBUG3("unlang_interpret_push called with instruction type \"%s\" - args %s %s",
169 instruction ? instruction->debug_name : "<none>",
170 do_next_sibling ? "UNLANG_NEXT_SIBLING" : "UNLANG_NEXT_STOP",
171 top_frame ? "UNLANG_TOP_FRAME" : "UNLANG_SUB_FRAME");
172#endif
173
174 /*
175 * This is not a cancellation point.
176 *
177 * If we cancel here bad things happen inside the interpret.
178 */
179 if (stack->depth >= (UNLANG_STACK_MAX - 1)) {
180 RERROR("Call stack is too deep");
181 return - 1;
182 }
183
184 stack->depth++;
185
186 /*
187 * Initialize the next stack frame.
188 */
189 frame = &stack->frame[stack->depth];
190 memset(frame, 0, sizeof(*frame));
191
192 frame->instruction = instruction;
193
194 if (do_next_sibling) {
195 fr_assert(instruction != NULL);
196 frame->next = instruction->next;
197 }
198 /* else frame->next MUST be NULL */
199
200 frame->uflags = UNWIND_FLAG_NONE;
201 if (top_frame) top_frame_set(frame);
202
203 frame->result = default_rcode;
204 frame->priority = -1;
205 frame->indent = request->log.indent;
206
207 if (!instruction) return 0;
208
209 frame_state_init(stack, frame);
210
211 return 0;
212}
213
214typedef struct {
215 fr_dict_t const *old_dict; //!< the previous dictionary for the request
216 request_t *request; //!< the request
218
220{
221 fr_pair_t *vp, *prev;
222
223 /*
224 * Local variables are appended to the end of the list. So we remove them by walking backwards
225 * from the end of the list.
226 */
227 vp = fr_pair_list_tail(&ref->request->local_pairs);
228 while (vp) {
229 prev = fr_pair_list_prev(&ref->request->local_pairs, vp);
230 if (vp->da->dict != ref->request->local_dict) {
231 break;
232 }
233
234 (void) fr_pair_delete(&ref->request->local_pairs, vp);
235 vp = prev;
236 }
237
238 ref->request->local_dict = ref->old_dict;
239
240 return 0;
241}
242
243/** Push the children of the current frame onto a new frame onto the stack
244 *
245 * @param[out] p_result set to RLM_MOULDE_FAIL if pushing the children fails
246 * @param[in] request to push the frame onto.
247 * @param[in] default_rcode The default result.
248 * @param[in] do_next_sibling Whether to only execute the first node in the #unlang_t program
249 * or to execute subsequent nodes.
250 * @return
251 * - UNLANG_ACTION_PUSHED_CHILD on success.
252 * - UNLANG_ACTION_EXECUTE_NEXT do nothing, but just go to the next sibling instruction
253 * - UNLANG_ACTION_STOP_PROCESSING, fatal error, usually stack overflow.
254 */
256 rlm_rcode_t default_rcode, bool do_next_sibling)
257{
258 unlang_stack_t *stack = request->stack;
259 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
262
264
266
267 /*
268 * The compiler catches most of these, EXCEPT for the
269 * top-level 'recv Access-Request' etc. Which can exist,
270 * and can be empty.
271 */
272 if (!g->children) {
273 RDEBUG2("<ignoring empty subsection>");
275 }
276
277 if (unlang_interpret_push(request, g->children, default_rcode, do_next_sibling, UNLANG_SUB_FRAME) < 0) {
278 *p_result = RLM_MODULE_FAIL;
280 }
281
283
284 /*
285 * Note that we do NOT create the variables, This way we don't have to worry about any
286 * uninitialized values. If the admin tries to use the variable without initializing it, they
287 * will get a "no such attribute" error.
288 */
289 if (!frame->state) {
290 MEM(ref = talloc(stack, unlang_variable_ref_t));
291 frame->state = ref;
292 } else {
293 MEM(ref = talloc(frame->state, unlang_variable_ref_t));
294 }
295
296 /*
297 * Set the destructor to clean up local variables.
298 */
299 ref->request = request;
300 ref->old_dict = request->local_dict;
301 request->local_dict = g->variables->dict;
302 talloc_set_destructor(ref, _local_variables_free);
303
305}
306
307static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx);
308
309/** Update the current result after each instruction, and after popping each stack frame
310 *
311 * @param[in] request The current request.
312 * @param[in] frame The current stack frame.
313 * @param[in,out] result The current section result.
314 * @param[in,out] priority The current section priority.
315 * @return
316 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions.
317 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
318 */
319static inline CC_HINT(always_inline)
321 rlm_rcode_t *result, int *priority)
322{
323 unlang_t const *instruction = frame->instruction;
324 unlang_stack_t *stack = request->stack;
325
326 RDEBUG4("** [%i] %s - have (%s %d) module returned (%s %d)",
327 stack->depth, __FUNCTION__,
328 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
329 frame->priority,
330 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
331 *priority);
332
333 /*
334 * Update request->rcode if the instruction says we should
335 * We don't care about priorities for this.
336 */
337 if (unlang_ops[instruction->type].rcode_set) {
338 RDEBUG3("Setting rcode to '%s'",
339 fr_table_str_by_value(rcode_table, *result, "<INVALID>"));
340 request->rcode = *result;
341 }
342
343 /*
344 * Don't set action or priority if we don't have one.
345 */
346 if (*result == RLM_MODULE_NOT_SET) return UNLANG_FRAME_ACTION_NEXT;
347
348 /*
349 * The child's action says return. Do so.
350 */
351 if (instruction->actions.actions[*result] == MOD_ACTION_RETURN) {
352 if (*priority < 0) *priority = 0;
353
354 RDEBUG4("** [%i] %s - action says to return with (%s %d)",
355 stack->depth, __FUNCTION__,
356 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
357 *priority);
358 frame->result = *result;
359 frame->priority = *priority;
361 }
362
363 /*
364 * If "reject", break out of the loop and return
365 * reject.
366 */
367 if (instruction->actions.actions[*result] == MOD_ACTION_REJECT) {
368 if (*priority < 0) *priority = 0;
369
370 RDEBUG4("** [%i] %s - action says to return with (%s %d)",
371 stack->depth, __FUNCTION__,
373 *priority);
374 frame->result = RLM_MODULE_REJECT;
375 frame->priority = *priority;
377 }
378
379 /*
380 * The instruction says it should be retried from the beginning.
381 */
382 if (instruction->actions.actions[*result] == MOD_ACTION_RETRY) {
383 unlang_retry_t *retry = frame->retry;
384
385 RDEBUG4("** [%i] %s - action says to retry with",
386 stack->depth, __FUNCTION__);
387
388 if (*priority < 0) *priority = 0;
389
390 /*
391 * If this is the first time doing the retry,
392 * then allocate the structure and set the timer.
393 */
394 if (!retry) {
395 frame->retry = retry = talloc_zero(stack, unlang_retry_t);
396 if (!frame->retry) goto fail;
397
398 retry->request = request;
399 retry->depth = stack->depth;
400 retry->state = FR_RETRY_CONTINUE;
401 retry->count = 1;
402
403 /*
404 * Set a timer which automatically fires
405 * if there's a timeout. And parent it
406 * from the retry structure, so that the
407 * timer is automatically freed when the
408 * frame is cleaned up.
409 */
410 if (fr_time_delta_ispos(instruction->actions.retry.mrd)) {
411 retry->timeout = fr_time_add(fr_time(), instruction->actions.retry.mrd);
412
413 if (fr_timer_at(retry, unlang_interpret_event_list(request)->tl, &retry->ev, retry->timeout,
414 false, instruction_retry_handler, request) < 0) {
415 RPEDEBUG("Failed inserting event");
416 goto fail;
417 }
418 }
419
420 } else {
421 /*
422 * We've been told to stop doing retries,
423 * probably from a timeout.
424 */
425 if (retry->state != FR_RETRY_CONTINUE) goto fail;
426
427 /*
428 * Clamp it at the maximum count.
429 */
430 if (instruction->actions.retry.mrc > 0) {
431 retry->count++;
432
433 if (retry->count >= instruction->actions.retry.mrc) {
434 retry->state = FR_RETRY_MRC;
435
436 REDEBUG("Retries hit max_rtx_count (%u) - returning 'fail'", instruction->actions.retry.mrc);
437
438 fail:
439 *result = RLM_MODULE_FAIL;
440 goto finalize;
441 }
442 }
443 }
444
445 RINDENT();
446 if (instruction->actions.retry.mrc) {
447 RDEBUG("... retrying (%u/%u)", retry->count, instruction->actions.retry.mrc);
448 } else {
449 RDEBUG("... retrying");
450 }
451 REXDENT();
452
453 talloc_free(frame->state);
455 frame_state_init(stack, frame);
457 }
458
459finalize:
460 /*
461 * The array holds a default priority for this return
462 * code. Grab it in preference to any unset priority.
463 */
464 if (*priority < 0) {
465 *priority = instruction->actions.actions[*result];
466
467 RDEBUG4("** [%i] %s - setting priority to (%s %d)",
468 stack->depth, __FUNCTION__,
469 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
470 *priority);
471 }
472
473 /*
474 * We're higher than any previous priority, remember this
475 * return code and priority.
476 */
477 if (*priority > frame->priority) {
478 frame->result = *result;
479 frame->priority = *priority;
480
481 RDEBUG4("** [%i] %s - over-riding result from higher priority to (%s %d)",
482 stack->depth, __FUNCTION__,
483 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"),
484 *priority);
485 }
486
487 /*
488 * Not allowed in frame uflags...
489 */
490 fr_assert(!(frame->uflags & UNWIND_FLAG_NO_CLEAR));
491
492 /*
493 * If we are unwinding the stack due to a break / return,
494 * then handle it now.
495 */
496 if (stack->unwind) {
497 /*
498 * Continue unwinding...
499 */
500 if (!(stack->unwind & frame->uflags) || (stack->unwind & UNWIND_FLAG_NO_CLEAR)) {
501 RDEBUG4("** [%i] %s - unwinding current frame with (%s %d) - flags - stack (%i), frame (%i)",
502 stack->depth, __FUNCTION__,
503 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
504 frame->priority, stack->unwind, frame->uflags);
505
507 }
508
509 /*
510 * If we've been told to unwind, and we've hit
511 * the frame we should be unwinding to,
512 * and the "NO_CLEAR" flag hasn't been set, then
513 * clear the unwind field so we stop unwinding.
514 */
515 stack->unwind = UNWIND_FLAG_NONE;
516
517 RDEBUG4("** [%i] %s - unwind stop (%s %d) - flags - stack unwind (%i), frame uflags (%i)",
518 stack->depth, __FUNCTION__,
519 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
520 frame->priority, stack->unwind, frame->uflags);
521 }
522
524}
525
526/** Evaluates all the unlang nodes in a section
527 *
528 * @param[in] request The current request.
529 * @param[in] frame The current stack frame.
530 * @param[in,out] result The current section result.
531 * @param[in,out] priority The current section priority.
532 * @return
533 * - UNLANG_FRAME_ACTION_NEXT evaluate more instructions in the current stack frame
534 * which may not be the same frame as when this function
535 * was called.
536 * - UNLANG_FRAME_ACTION_POP the final result has been calculated for this frame.
537 */
538static inline CC_HINT(always_inline)
540{
541 unlang_stack_t *stack = request->stack;
542
543 /*
544 * Loop over all the instructions in this list.
545 */
546 while (frame->instruction) {
547 unlang_t const *instruction = frame->instruction;
550
552
553 fr_assert(instruction->debug_name != NULL); /* if this happens, all bets are off. */
554 fr_assert(unlang_ops[instruction->type].interpret != NULL);
555
556 REQUEST_VERIFY(request);
557
558 /*
559 * We're running this frame, so it can't possibly be yielded.
560 */
561 if (is_yielded(frame)) {
562 RDEBUG("%s - Resuming execution", instruction->debug_name);
563 yielded_clear(frame);
564 }
565
566#ifndef NDEBUG
567 /*
568 * Failure testing!
569 */
570 if (request->ins_max && (request->master_state != REQUEST_STOP_PROCESSING)) {
571 request->ins_count++;
572
573 if (request->ins_count >= request->ins_max) {
574 RERROR("Failing request due to maximum instruction count %" PRIu64, request->ins_max);
575
577 request->master_state = REQUEST_STOP_PROCESSING;
578 }
579 }
580#endif
581
582 /*
583 * unlang_interpret_signal() takes care of
584 * marking the requests as STOP on a CANCEL
585 * signal.
586 */
587 if (request->master_state == REQUEST_STOP_PROCESSING) {
588 do_stop:
589 frame->result = RLM_MODULE_FAIL;
590 frame->priority = MOD_PRIORITY_MAX;
591
592 RDEBUG4("** [%i] %s - STOP current subsection with (%s %d)",
593 stack->depth, __FUNCTION__,
594 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
595 frame->priority);
596
599 }
600
601 if (!is_repeatable(frame) && (unlang_ops[instruction->type].debug_braces)) {
602 RDEBUG2("%s {", instruction->debug_name);
603 RINDENT();
604 }
605
606 /*
607 * Execute an operation
608 */
609 RDEBUG4("** [%i] %s >> %s", stack->depth, __FUNCTION__,
610 unlang_ops[instruction->type].name);
611
612 fr_assert(frame->process != NULL);
613
614 /*
615 * Clear the repeatable flag so this frame
616 * won't get executed again unless it specifically
617 * requests it.
618 *
619 * The flag may still be set again during the
620 * process function to indicate that the frame
621 * should be evaluated again.
622 */
623 repeatable_clear(frame);
625 ua = frame->process(result, request, frame);
626
627 /*
628 * If this frame is breaking or returning
629 * frame then clear that unwind flag,
630 * it's been consumed by this call.
631 *
632 * We leave the unwind flags for the eval
633 * call so that the process function knows
634 * that the stack is being unwound.
635 */
636 if (is_break_point(frame)) {
639 }
640 if (is_return_point(frame)) {
643 }
644
645 RDEBUG4("** [%i] %s << %s (%d)", stack->depth, __FUNCTION__,
646 fr_table_str_by_value(unlang_action_table, ua, "<INVALID>"), *priority);
647
648 fr_assert(*priority >= -1);
649 fr_assert(*priority <= MOD_PRIORITY_MAX);
650
651 switch (ua) {
652 /*
653 * The request is now defunct, and we should not
654 * continue processing it.
655 */
657 goto do_stop;
658
659 /*
660 * The operation resulted in additional frames
661 * being pushed onto the stack, execution should
662 * now continue at the deepest frame.
663 */
665 fr_assert_msg(&stack->frame[stack->depth] > frame,
666 "Instruction %s returned UNLANG_ACTION_PUSHED_CHILD, "
667 "but stack depth was not increased",
668 instruction->name);
670 *result = frame->result;
672
673 /*
674 * We're in a looping construct and need to stop
675 * execution of the current section.
676 */
678 if (*priority < 0) *priority = 0;
679 frame->result = *result;
680 frame->priority = *priority;
681 frame->next = NULL;
682 fr_assert(stack->unwind != UNWIND_FLAG_NONE);
684
685 /*
686 * Yield control back to the scheduler, or whatever
687 * called the interpreter.
688 */
690 fr_assert_msg(&stack->frame[stack->depth] == frame,
691 "Instruction %s returned UNLANG_ACTION_YIELD, but pushed additional "
692 "frames for evaluation. Instruction should return UNLANG_ACTION_PUSHED_CHILD "
693 "instead", instruction->name);
695 yielded_set(frame);
696 RDEBUG4("** [%i] %s - yielding with current (%s %d)", stack->depth, __FUNCTION__,
697 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
698 frame->priority);
701
702 /*
703 * This action is intended to be returned by library
704 * functions. It reduces boilerplate.
705 */
707 *result = RLM_MODULE_FAIL;
709
710 /*
711 * Instruction finished execution,
712 * check to see what we need to do next, and update
713 * the section rcode and priority.
714 */
716 if (unlang_ops[instruction->type].debug_braces) {
717 REXDENT();
718
719 /*
720 * If we're at debug level 1, don't emit the closing
721 * brace as the opening brace wasn't emitted.
722 */
724 RDEBUG("# %s (%s)", instruction->debug_name,
725 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
726 } else {
727 RDEBUG2("} # %s (%s)", instruction->debug_name,
728 fr_table_str_by_value(mod_rcode_table, *result, "<invalid>"));
729 }
730 }
731
732 /*
733 * RLM_MODULE_NOT_SET means the instruction
734 * doesn't want to modify the result.
735 */
736 if (*result != RLM_MODULE_NOT_SET) *priority = instruction->actions.actions[*result];
737
738 fa = result_calculate(request, frame, result, priority);
739 switch (fa) {
742
744 if (unlang_ops[instruction->type].debug_braces) {
745 REXDENT();
746 RDEBUG2("} # retrying the same section");
747 }
748 continue; /* with the current frame */
749
750 default:
751 break;
752 }
753 break;
754
755 /*
756 * Execute the next instruction in this frame
757 */
759 if (unlang_ops[instruction->type].debug_braces) {
760 REXDENT();
761 RDEBUG2("}");
762 }
763 break;
764 } /* switch over return code from the interpret function */
765
766 frame_next(stack, frame);
767 }
768
769 RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
770 stack->depth, __FUNCTION__,
771 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
772 frame->priority);
773
775}
776
777/** Run the interpreter for a current request
778 *
779 * @param[in] request to run. If this is an internal request
780 * the request may be freed by the interpreter.
781 * @param[in] running Is the interpreter already running.
782 * @return The final request rcode.
783 */
784CC_HINT(hot) rlm_rcode_t unlang_interpret(request_t *request, bool running)
785{
787 rlm_rcode_t rcode;
788
789 /*
790 * We don't have a return code yet.
791 */
792 unlang_stack_t *stack = request->stack;
793 unlang_interpret_t *intp = stack->intp;
794 unlang_stack_frame_t *frame = &stack->frame[stack->depth]; /* Quiet static analysis */
795
796 stack->priority = -1; /* Reset */
797
798#ifndef NDEBUG
799 if (DEBUG_ENABLED5) DEBUG("###### unlang_interpret is starting");
801#endif
802
803 fr_assert(!unlang_request_is_scheduled(request)); /* if we're running it, it can't be scheduled */
804 fr_assert_msg(intp, "request has no interpreter associated");
805
806 RDEBUG4("** [%i] %s - interpret entered", stack->depth, __FUNCTION__);
807 if (!running) intp->funcs.resume(request, intp->uctx);
808
809 for (;;) {
810 fr_assert(request->master_state != REQUEST_STOP_PROCESSING);
811
812 RDEBUG4("** [%i] %s - frame action %s", stack->depth, __FUNCTION__,
814 switch (fa) {
815 case UNLANG_FRAME_ACTION_NEXT: /* Evaluate the current frame */
816 fr_assert(stack->depth > 0);
818
819 frame = &stack->frame[stack->depth];
820 fa = frame_eval(request, frame, &stack->result, &stack->priority);
821
822 if (fa != UNLANG_FRAME_ACTION_POP) continue;
823
824 /*
825 * We're supposed to stop processing. Don't pop anything, just stop.
826 */
827 if (request->master_state == REQUEST_STOP_PROCESSING) return RLM_MODULE_FAIL;
828
829 /*
830 * We were executing a frame, frame_eval()
831 * indicated we should pop it, but we're now at
832 * a top_frame, so we need to break out of the loop
833 * and calculate the final result for this substack.
834 *
835 * Note that we only stop on a top frame.
836 * If there's a return point such as in a
837 * policy, then the "return" causes a
838 * "pop" until the return point. BUT we
839 * then continue execution with the next
840 * instruction. And we don't return all
841 * of the way up the stack.
842 */
843 if (is_top_frame(frame)) break;
844
845 continue;
846
847 case UNLANG_FRAME_ACTION_POP: /* Pop this frame and check the one beneath it */
848 /*
849 * The result / priority is returned from the sub-section,
850 * and made into our current result / priority, as
851 * if we had performed a module call.
852 */
853 stack->result = frame->result;
854 stack->priority = frame->priority;
855
856 /*
857 * Head on back up the stack
858 */
859 frame_pop(request, stack);
860 frame = &stack->frame[stack->depth];
862
863 /*
864 * Resume a "foreach" loop, or a "load-balance" section
865 * or anything else that needs to be checked on the way
866 * back on up the stack.
867 */
868 if (is_repeatable(frame)) {
870 continue;
871 }
872
873 /*
874 * Close out the section we entered earlier
875 */
877 REXDENT();
878
879 /*
880 * If we're at debug level 1, don't emit the closing
881 * brace as the opening brace wasn't emitted.
882 */
884 RDEBUG("# %s (%s)", frame->instruction->debug_name,
885 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
886 } else {
887 RDEBUG2("} # %s (%s)", frame->instruction->debug_name,
888 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"));
889 }
890 }
891
892 /*
893 * If we're done, merge the last stack->result / priority in.
894 */
895 if (is_top_frame(frame)) break; /* stop */
896
897 fa = result_calculate(request, frame, &stack->result, &stack->priority);
898
899 /*
900 * If we're continuing after popping a frame
901 * then we advance the instruction else we
902 * end up executing the same code over and over...
903 */
904 if (fa == UNLANG_FRAME_ACTION_NEXT) {
905 RDEBUG4("** [%i] %s - continuing after subsection with (%s %d)",
906 stack->depth, __FUNCTION__,
907 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
908 stack->priority);
909 frame_next(stack, frame);
910
911 /*
912 * Else if we're really done with this frame
913 * print some helpful debug...
914 */
915 } else {
916 RDEBUG4("** [%i] %s - done current subsection with (%s %d)",
917 stack->depth, __FUNCTION__,
918 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"),
919 frame->priority);
920 }
921 continue;
922
924 /* Cannot yield from a nested call to unlang_interpret */
925 fr_assert(!running);
926
927 RDEBUG4("** [%i] %s - interpret yielding", stack->depth, __FUNCTION__);
928 intp->funcs.yield(request, intp->uctx);
929 return stack->result;
930
931 case UNLANG_FRAME_ACTION_RETRY: /* retry the current frame */
933 continue;
934 }
935 break;
936 }
937
938 /*
939 * Nothing in this section, use the top frame stack->result.
940 */
941 if ((stack->priority < 0) || (stack->result == RLM_MODULE_NOT_SET)) {
942 RDEBUG4("** [%i] %s - empty section, using stack result (%s %d)", stack->depth, __FUNCTION__,
943 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"), stack->priority);
944 stack->result = frame->result;
945 stack->priority = frame->priority;
946 }
947
948 if (stack->priority > frame->priority) {
949 frame->result = stack->result;
950 frame->priority = stack->priority;
951
952 RDEBUG4("** [%i] %s - over-riding stack->result from higher priority to (%s %d)",
953 stack->depth, __FUNCTION__,
954 fr_table_str_by_value(mod_rcode_table, stack->result, "<invalid>"),
955 stack->priority);
956 }
957
958 /*
959 * We're at the top frame, return the result from the
960 * stack, and get rid of the top frame.
961 */
962 RDEBUG4("** [%i] %s - interpret exiting, returning %s", stack->depth, __FUNCTION__,
963 fr_table_str_by_value(mod_rcode_table, frame->result, "<invalid>"));
964
965 stack->result = frame->result;
966
967 stack->depth--;
969
970 /*
971 * Record this now as the done functions may free
972 * the request.
973 */
974 rcode = stack->result;
975
976 /*
977 * This usually means the request is complete in its
978 * entirety.
979 */
980 if ((stack->depth == 0) && !running) unlang_interpret_request_done(request);
981
982 return rcode;
983}
984
986 .self = {
988 .debug_name = "empty-group",
989 .actions = {
990 .actions = {
1000 },
1001 .retry = RETRY_INIT,
1002 },
1003 },
1004};
1005
1006/** Push a configuration section onto the request stack for later interpretation.
1007 *
1008 */
1009int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs, rlm_rcode_t default_rcode, bool top_frame)
1010{
1011 unlang_t *instruction = NULL;
1012
1013 /*
1014 * Interpretable unlang instructions are stored as CONF_DATA
1015 * associated with sections.
1016 */
1017 if (cs) {
1018 instruction = (unlang_t *)cf_data_value(cf_data_find(cs, unlang_group_t, NULL));
1019 if (!instruction) {
1020 REDEBUG("Failed to find pre-compiled unlang for section %s %s { ... }",
1022 return -1;
1023 }
1024 }
1025
1026 return unlang_interpret_push_instruction(request, instruction, default_rcode, top_frame);
1027}
1028
1029/** Push an instruction onto the request stack for later interpretation.
1030 *
1031 */
1032int unlang_interpret_push_instruction(request_t *request, void *instruction, rlm_rcode_t default_rcode, bool top_frame)
1033{
1034 unlang_stack_t *stack = request->stack;
1035
1036 if (!instruction) {
1037 instruction = unlang_group_to_generic(&empty_group);
1038 }
1039
1040 /*
1041 * Push the default action, and the instruction which has
1042 * no action.
1043 */
1044 if (unlang_interpret_push(request,
1045 instruction, default_rcode, UNLANG_NEXT_SIBLING, top_frame) < 0) {
1046 return -1;
1047 }
1048
1049 RDEBUG4("** [%i] %s - substack begins", stack->depth, __FUNCTION__);
1050
1051 DUMP_STACK;
1052
1053 return 0;
1054}
1055
1056/** Allocate a new unlang stack
1057 *
1058 * @param[in] ctx to allocate stack in.
1059 * @return
1060 * - A new stack on success.
1061 * - NULL on OOM.
1062 */
1063void *unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
1064{
1066
1067 /*
1068 * If we have talloc_pooled_object allocate the
1069 * stack as a combined chunk/pool, with memory
1070 * to hold at mutable data for at least a quarter
1071 * of the maximum number of stack frames.
1072 *
1073 * Having a dedicated pool for mutable stack data
1074 * means we don't have memory fragmentations issues
1075 * as we would if request were used as the pool.
1076 *
1077 * This number is pretty arbitrary, but it seems
1078 * like too low level to make into a tuneable.
1079 */
1080 MEM(stack = talloc_zero_pooled_object(ctx, unlang_stack_t, UNLANG_STACK_MAX, 128)); /* 128 bytes per state */
1081 stack->result = RLM_MODULE_NOT_SET;
1082
1083 return stack;
1084}
1085
1086/** Indicate to the caller of the interpreter that this request is complete
1087 *
1088 */
1090{
1091 unlang_stack_t *stack = request->stack;
1092 unlang_interpret_t *intp;
1093
1094 if (!fr_cond_assert(stack != NULL)) return;
1095
1096 intp = stack->intp;
1097
1098 request->master_state = REQUEST_DONE;
1099 switch (request->type) {
1101 intp->funcs.done_external(request, stack->result, intp->uctx);
1102 break;
1103
1105 intp->funcs.done_internal(request, stack->result, intp->uctx);
1106 break;
1107
1109 intp->funcs.done_detached(request, stack->result, intp->uctx); /* Callback will usually free the request */
1110 break;
1111 }
1112}
1113
1114static inline CC_HINT(always_inline)
1116{
1117 unlang_stack_t *stack = request->stack;
1118 unlang_interpret_t *intp;
1119
1120 if (!fr_cond_assert(stack != NULL)) return;
1121
1122 intp = stack->intp;
1123 intp->funcs.stop(request, intp->uctx);
1124 request->log.indent.unlang = 0; /* nothing unwinds the indentation stack */
1125 request->master_state = REQUEST_STOP_PROCESSING;
1126}
1127
1128static inline CC_HINT(always_inline)
1130{
1131 unlang_stack_t *stack = request->stack;
1132 unlang_interpret_t *intp;
1133
1134 if (!fr_cond_assert(stack != NULL)) return;
1135
1136 if (!request_is_detachable(request)) return;
1137
1138 intp = stack->intp;
1139
1140 intp->funcs.detach(request, intp->uctx);
1141}
1142
1143/** Send a signal (usually stop) to a request
1144 *
1145 * This is typically called via an "async" action, i.e. an action
1146 * outside of the normal processing of the request.
1147 *
1148 * If there is no #unlang_module_signal_t callback defined, the action is ignored.
1149 *
1150 * The signaling stops at the "limit" frame. This is so that keywords
1151 * such as "timeout" and "limit" can signal frames *lower* than theirs
1152 * to stop, but then continue with their own work.
1153 *
1154 * @param[in] request The current request.
1155 * @param[in] action to signal.
1156 * @param[in] limit the frame at which to stop signaling.
1157 */
1158void unlang_frame_signal(request_t *request, fr_signal_t action, int limit)
1159{
1160 unlang_stack_frame_t *frame;
1161 unlang_stack_t *stack = request->stack;
1162 int i, depth = stack->depth;
1163
1164 (void)talloc_get_type_abort(request, request_t); /* Check the request hasn't already been freed */
1165
1166 fr_assert(stack->depth > 0);
1167
1168 /*
1169 * Destructive signal where we clean each of the
1170 * stack frames up in turn.
1171 *
1172 * We do this to avoid possible free ordering
1173 * issues where memory allocated by modules higher
1174 * in the stack is used by modules lower in the
1175 * stack.
1176 */
1177 if (action == FR_SIGNAL_CANCEL) {
1178 for (i = depth; i > limit; i--) {
1179 frame = &stack->frame[i];
1180 if (frame->signal) frame->signal(request, frame, action);
1181 frame_cleanup(frame);
1182 }
1183 stack->depth = i;
1184 return;
1185 }
1186
1187 /*
1188 * Walk back up the stack, calling signal handlers
1189 * to cancel any pending operations and free/release
1190 * any resources.
1191 *
1192 * There may be multiple resumption points in the
1193 * stack, as modules can push xlats and function
1194 * calls.
1195 */
1196 for (i = depth; i > limit; i--) {
1197 frame = &stack->frame[i];
1198 if (frame->signal) frame->signal(request, frame, action);
1199 }
1200}
1201
1202/** Send a signal (usually stop) to a request
1203 *
1204 * This is typically called via an "async" action, i.e. an action
1205 * outside of the normal processing of the request.
1206 *
1207 * If there is no #unlang_module_signal_t callback defined, the action is ignored.
1208 *
1209 * @param[in] request The current request.
1210 * @param[in] action to signal.
1211 */
1213{
1214 unlang_stack_t *stack = request->stack;
1215
1216 switch (action) {
1217 case FR_SIGNAL_DETACH:
1218 /*
1219 * Ensure the request is able to be detached
1220 * else don't signal.
1221 */
1222 if (!fr_cond_assert(request_is_detachable(request))) return;
1223 break;
1224
1225 default:
1226 break;
1227 }
1228
1229 /*
1230 * Requests that haven't been run through the interpreter
1231 * yet should have a stack depth of zero, so we don't
1232 * need to do anything.
1233 */
1234 if (stack && (stack->depth > 0)) unlang_frame_signal(request, action, 0);
1235
1236 switch (action) {
1237 case FR_SIGNAL_CANCEL:
1238 /*
1239 * Detach the request from the parent to cleanup
1240 * any cross-request pointers. This is a noop
1241 * if the request is not detachable.
1242 */
1244
1245 /*
1246 * Get the request into a consistent state,
1247 * removing it from any runnable lists.
1248 */
1250
1251 /*
1252 * As the request is detached, we call the done_detached
1253 * callback which should free the request.
1254 */
1256 break;
1257
1258 case FR_SIGNAL_DETACH:
1259 /*
1260 * Cleanup any cross-request pointers, and mark the
1261 * request as detached. When the request completes it
1262 * should by automatically freed.
1263 */
1265 break;
1266
1267 default:
1268 break;
1269 }
1270}
1271
1273{
1274 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1275 request_t *request = talloc_get_type_abort(retry->request, request_t);
1276
1277 RDEBUG("retry timeout reached, signalling interpreter to cancel.");
1278
1279 /*
1280 * Signal all lower frames to exit.
1281 */
1282 unlang_frame_signal(request, FR_SIGNAL_CANCEL, retry->depth);
1283
1284 retry->state = FR_RETRY_MRD;
1286}
1287
1289{
1290 unlang_retry_t *retry = talloc_get_type_abort(ctx, unlang_retry_t);
1291 request_t *request = talloc_get_type_abort(retry->request, request_t);
1292
1293 RDEBUG("Maximum timeout reached, signalling interpreter to stop the request.");
1294
1295 /*
1296 * Stop the entire request.
1297 */
1299}
1300
1301
1302/** Set a timeout for a request.
1303 *
1304 * The timeout is associated with the current stack frame.
1305 *
1306 */
1308{
1309 unlang_stack_t *stack = request->stack;
1310 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1311 unlang_retry_t *retry;
1312
1313 fr_assert(!frame->retry);
1315
1316 frame->retry = retry = talloc_zero(frame, unlang_retry_t);
1317 if (!frame->retry) return -1;
1318
1319 retry->request = request;
1320 retry->depth = stack->depth;
1321 retry->state = FR_RETRY_CONTINUE;
1322 retry->count = 1;
1323
1324 retry->timeout = fr_time_add(fr_time(), timeout);
1325
1326 return fr_timer_at(retry, unlang_interpret_event_list(request)->tl, &retry->ev, retry->timeout,
1327 false, instruction_timeout_handler, request);
1328}
1329
1330
1331/** Return the depth of the request's stack
1332 *
1333 */
1335{
1336 unlang_stack_t *stack = request->stack;
1337
1338 return stack->depth;
1339}
1340
1341/** Get the current rcode for the frame
1342 *
1343 * This can be useful for getting the result of unlang_function_t pushed
1344 * onto the stack for evaluation.
1345 *
1346 * @param[in] request The current request.
1347 * @return the current rcode for the frame.
1348 */
1350{
1351 unlang_stack_t *stack = request->stack;
1352
1353 return stack->result;
1354}
1355
1356/** Overwrite the current stack rcode
1357 *
1358 * @param[in] request The current request.
1359 * @param[in] rcode to set.
1360 */
1362{
1363 unlang_stack_t *stack = request->stack;
1364
1365 stack->result = rcode;
1366}
1367
1368/** Return whether a request is currently scheduled
1369 *
1370 */
1372{
1373 unlang_stack_t *stack = request->stack;
1374 unlang_interpret_t *intp = stack->intp;
1375
1376 return intp->funcs.scheduled(request, intp->uctx);
1377}
1378
1379/** Return whether a request has been cancelled
1380 */
1382{
1383 return (request->master_state == REQUEST_STOP_PROCESSING);
1384}
1385
1386/** Return whether a request has been marked done
1387 */
1389{
1390 return (request->master_state == REQUEST_DONE);
1391}
1392
1393/** Check if a request as resumable.
1394 *
1395 * @param[in] request The current request.
1396 * @return
1397 * - true if the request is resumable (i.e. has yielded)
1398 * - false if the request is not resumable (i.e. has not yielded)
1399 */
1401{
1402 unlang_stack_t *stack = request->stack;
1403 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1404
1405 return is_yielded(frame);
1406}
1407
1408/** Mark a request as resumable.
1409 *
1410 * It's not called "unlang_interpret", because it doesn't actually
1411 * resume the request, it just schedules it for resumption.
1412 *
1413 * @note that this schedules the request for resumption. It does not immediately
1414 * start running the request.
1415 *
1416 * @param[in] request The current request.
1417 */
1419{
1420 unlang_stack_t *stack = request->stack;
1421 unlang_interpret_t *intp = stack->intp;
1422 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1423
1424 bool scheduled = unlang_request_is_scheduled(request);
1425
1426 /*
1427 * The request hasn't yielded, OR it's already been
1428 * marked as runnable. Don't do anything.
1429 *
1430 * The IO code, or children have no idea where they're
1431 * being called from. They just ask to mark the parent
1432 * resumable when they're done. So we have to check here
1433 * if this request is resumable.
1434 *
1435 * If the parent called the child directly, then the
1436 * parent hasn't yielded, so it isn't resumable. When
1437 * the child is done, the parent will automatically
1438 * continue running. We therefore don't need to insert
1439 * the parent into the backlog.
1440 *
1441 * Multiple child request may also mark a parent request
1442 * runnable, before the parent request starts running.
1443 */
1444 if (!is_yielded(frame) || scheduled) {
1445 RDEBUG3("Not marking runnable due to%s%s",
1446 !is_yielded(frame) ?
1447 " it not being yielded " : "", scheduled ? " it already being scheduled" : "");
1448 return;
1449 }
1450
1451 RDEBUG3("Interpreter - Request marked as runnable");
1452
1453 intp->funcs.mark_runnable(request, intp->uctx);
1454}
1455
1456/** Get a talloc_ctx which is valid only for this frame
1457 *
1458 * @param[in] request The current request.
1459 * @return
1460 * - a TALLOC_CTX which is valid only for this stack frame
1461 */
1463{
1464 unlang_stack_t *stack = request->stack;
1465 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
1466
1467 if (frame->state) return (TALLOC_CTX *)frame->state;
1468
1469 /*
1470 * If the frame doesn't ordinarily have a
1471 * state, assume the caller knows what it's
1472 * doing and allocate one.
1473 */
1474 return (TALLOC_CTX *)(frame->state = talloc_new(request));
1475}
1476
1478 { .required = false, .single = true, .type = FR_TYPE_TIME_DELTA },
1480};
1481
1482static xlat_action_t unlang_cancel_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out,
1483 UNUSED xlat_ctx_t const *xctx,
1484 request_t *request, fr_value_box_list_t *args);
1485
1486/** Signal the request to stop executing
1487 *
1488 * The request can't be running at this point because we're in the event
1489 * loop. This means the request is always in a consistent state when
1490 * the timeout event fires, even if that's state is waiting on I/O.
1491 */
1493{
1494 request_t *request = talloc_get_type_abort(uctx, request_t);
1495
1496 RDEBUG2("Request canceled by dynamic timeout");
1497 /*
1498 * Cleans up the memory allocated to hold
1499 * the pointer, not the event itself.
1500 */
1501 talloc_free(request_data_get(request, (void *)unlang_cancel_xlat, 0));
1502
1504}
1505
1507 UNUSED xlat_ctx_t const *xctx,
1508 UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
1509{
1510 fr_assert_msg(0, "Should never be run");
1511 return XLAT_ACTION_FAIL;
1512}
1513
1514/** Allows a request to dynamically alter its own lifetime
1515 *
1516 * %cancel(<timeout>)
1517 *
1518 * If timeout is 0, then the request is immediately cancelled.
1519 */
1521 UNUSED xlat_ctx_t const *xctx,
1522 request_t *request, fr_value_box_list_t *args)
1523{
1524 fr_value_box_t *timeout;
1526 fr_timer_t **ev_p, **ev_p_og;
1527 fr_value_box_t *vb;
1528 fr_time_t when = fr_time_from_sec(0); /* Invalid clang complaints if we don't set this */
1529
1530 XLAT_ARGS(args, &timeout);
1531
1532 /*
1533 * First see if we already have a timeout event
1534 * that was previously added by this xlat.
1535 */
1536 ev_p = ev_p_og = request_data_get(request, (void *)unlang_cancel_xlat, 0);
1537 if (ev_p) {
1538 if (*ev_p) when = fr_timer_when(*ev_p); /* *ev_p should never be NULL, really... */
1539 } else {
1540 /*
1541 * Must not be parented from the request
1542 * as this is freed by request data.
1543 */
1544 MEM(ev_p = talloc_zero(NULL, fr_timer_t *));
1545 }
1546
1547 if (unlikely(fr_timer_in(ev_p, el->tl, ev_p,
1548 timeout ? timeout->vb_time_delta : fr_time_delta_from_sec(0),
1549 false, unlang_cancel_event, request) < 0)) {
1550 RPERROR("Failed inserting cancellation event");
1551 talloc_free(ev_p);
1552 return XLAT_ACTION_FAIL;
1553 }
1554 if (unlikely(request_data_add(request, (void *)unlang_cancel_xlat, 0,
1555 UNCONST(fr_timer_t **, ev_p), true, true, false) < 0)) {
1556 RPERROR("Failed associating cancellation event with request");
1557 talloc_free(ev_p);
1558 return XLAT_ACTION_FAIL;
1559 }
1560
1561 /*
1562 * No timeout means cancel immediately, so yield allowing
1563 * the interpreter to run the event we added to cancel
1564 * the request.
1565 *
1566 * We call unlang_xlat_yield to keep the interpreter happy
1567 * as it expects to see a resume function set.
1568 */
1569 if (!timeout || fr_time_delta_eq(timeout->vb_time_delta, fr_time_delta_from_sec(0))) {
1570 return unlang_xlat_yield(request, unlang_cancel_never_run, NULL, 0, NULL);
1571 }
1572
1573 if (ev_p_og) {
1574 MEM(vb = fr_value_box_alloc(ctx, FR_TYPE_TIME_DELTA, NULL));
1575
1576 /*
1577 * Return how long before the previous
1578 * cancel event would have fired.
1579 *
1580 * This can be useful for doing stacked
1581 * cancellations in policy.
1582 */
1583 vb->vb_time_delta = fr_time_sub(when, fr_time());
1585 }
1586
1587 /*
1588 * No value if this is the first cleanup event
1589 */
1590 return XLAT_ACTION_DONE;
1591}
1592
1594 { .required = true, .single = true, .type = FR_TYPE_STRING },
1596};
1597
1598/** Get information about the interpreter state
1599 *
1600 * @ingroup xlat_functions
1601 */
1603 UNUSED xlat_ctx_t const *xctx,
1604 request_t *request, fr_value_box_list_t *in)
1605{
1606 unlang_stack_t *stack = request->stack;
1607 int depth = stack->depth;
1608 unlang_stack_frame_t *frame;
1609 unlang_t const *instruction;
1610 fr_value_box_t *arg = fr_value_box_list_head(in);
1611 char const *fmt = arg->vb_strvalue;
1612 fr_value_box_t *vb;
1613
1614 MEM(vb = fr_value_box_alloc_null(ctx));
1615
1616 /*
1617 * Find the correct stack frame.
1618 */
1619 while (*fmt == '.') {
1620 if (depth <= 1) {
1621 if (fr_value_box_bstrndup(vb, vb, NULL, "<underflow>", 11, false) < 0) {
1622 error:
1623 talloc_free(vb);
1624 return XLAT_ACTION_FAIL;
1625 }
1626 goto finish;
1627 }
1628
1629 fmt++;
1630 depth--;
1631 }
1632
1633 /*
1634 * Get the current instruction.
1635 */
1636 frame = &stack->frame[depth];
1637 instruction = frame->instruction;
1638
1639 /*
1640 * Nothing there...
1641 */
1642 if (!instruction) {
1643 talloc_free(vb);
1644 return XLAT_ACTION_DONE;
1645 }
1646
1647 /*
1648 * How deep the current stack is.
1649 */
1650 if (strcmp(fmt, "depth") == 0) {
1651 fr_value_box_int32(vb, NULL, depth, false);
1652 goto finish;
1653 }
1654
1655 /*
1656 * The current module
1657 */
1658 if (strcmp(fmt, "module") == 0) {
1659 if (fr_value_box_strdup(vb, vb, NULL, request->module, false) < 0) goto error;
1660
1661 goto finish;
1662 }
1663
1664 /*
1665 * Name of the instruction.
1666 */
1667 if (strcmp(fmt, "name") == 0) {
1668 if (fr_value_box_bstrndup(vb, vb, NULL, instruction->name,
1669 strlen(instruction->name), false) < 0) goto error;
1670 goto finish;
1671 }
1672
1673 /*
1674 * The request processing stage.
1675 */
1676 if (strcmp(fmt, "processing_stage") == 0) {
1677 if (fr_value_box_strdup(vb, vb, NULL, request->component, false) < 0) goto error;
1678
1679 goto finish;
1680 }
1681
1682 /*
1683 * The current return code.
1684 */
1685 if (strcmp(fmt, "rcode") == 0) {
1686 if (fr_value_box_strdup(vb, vb, NULL, fr_table_str_by_value(rcode_table, request->rcode, "<INVALID>"), false) < 0) goto error;
1687
1688 goto finish;
1689 }
1690
1691 /*
1692 * The virtual server handling the request
1693 */
1694 if (strcmp(fmt, "server") == 0) {
1695 if (!unlang_call_current(request)) goto finish;
1696
1697 if (fr_value_box_strdup(vb, vb, NULL, cf_section_name2(unlang_call_current(request)), false) < 0) goto error;
1698
1699 goto finish;
1700 }
1701
1702 /*
1703 * Unlang instruction type.
1704 */
1705 if (strcmp(fmt, "type") == 0) {
1706 if (fr_value_box_bstrndup(vb, vb, NULL, unlang_ops[instruction->type].name,
1707 strlen(unlang_ops[instruction->type].name), false) < 0) goto error;
1708
1709 goto finish;
1710 }
1711
1712 /*
1713 * All of the remaining things need a CONF_ITEM.
1714 */
1715 if (!instruction->ci) {
1716 if (fr_value_box_bstrndup(vb, vb, NULL, "<INVALID>", 3, false) < 0) goto error;
1717
1718 goto finish;
1719 }
1720
1721 /*
1722 * Line number of the current section.
1723 */
1724 if (strcmp(fmt, "line") == 0) {
1725 fr_value_box_int32(vb, NULL, cf_lineno(instruction->ci), false);
1726
1727 goto finish;
1728 }
1729
1730 /*
1731 * Filename of the current section.
1732 */
1733 if (strcmp(fmt, "filename") == 0) {
1734 if (fr_value_box_strdup(vb, vb, NULL, cf_filename(instruction->ci), false) < 0) goto error;
1735
1736 goto finish;
1737 }
1738
1739finish:
1740 if (vb->type != FR_TYPE_NULL) {
1742 } else {
1743 talloc_free(vb);
1744 }
1745
1746 return XLAT_ACTION_DONE;
1747}
1748
1749/** Initialize a unlang compiler / interpret.
1750 *
1751 * @param[in] ctx to bind lifetime of the interpret to.
1752 * Shouldn't be any free order issues here as
1753 * the interpret itself has no state.
1754 * But event loop should be stopped before
1755 * freeing the interpret.
1756 * @param[in] el for any timer or I/O events.
1757 * @param[in] funcs Callbacks to used to communicate request
1758 * state to our owner.
1759 * @param[in] uctx Data to pass to callbacks.
1760 */
1762 fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
1763{
1764 unlang_interpret_t *intp;
1765
1766 fr_assert(funcs->init_internal);
1767
1768 fr_assert(funcs->done_internal);
1769 fr_assert(funcs->done_detached);
1770 fr_assert(funcs->done_external);
1771
1772 fr_assert(funcs->detach);
1773 fr_assert(funcs->stop);
1774 fr_assert(funcs->yield);
1775 fr_assert(funcs->resume);
1776 fr_assert(funcs->mark_runnable);
1777 fr_assert(funcs->scheduled);
1778
1779 MEM(intp = talloc(ctx, unlang_interpret_t));
1780 *intp = (unlang_interpret_t){
1781 .el = el,
1782 .funcs = *funcs,
1783 .uctx = uctx
1784 };
1785
1786 return intp;
1787}
1788
1789/** Discard the bottom most frame on the request's stack
1790 *
1791 * This is used for cleaning up after errors. i.e. the caller
1792 * uses a push function, and experiences an error and needs to
1793 * remove the frame that was just pushed.
1794 */
1796{
1797 frame_pop(request, request->stack);
1798}
1799
1800/** Set a specific interpreter for a request
1801 *
1802 */
1804{
1805 unlang_stack_t *stack = request->stack;
1806 stack->intp = intp;
1807}
1808
1809/** Get the interpreter set for a request
1810 *
1811 */
1813{
1814 unlang_stack_t *stack = request->stack;
1815
1816 return stack->intp;
1817}
1818
1819/** Get the event list for the current interpreter
1820 *
1821 */
1823{
1824 unlang_stack_t *stack = request->stack;
1825
1826 if (!stack->intp) return NULL;
1827
1828 return stack->intp->el;
1829}
1830
1831/** Set the default interpreter for this thread
1832 *
1833 */
1835{
1836 if (intp) (void)talloc_get_type_abort(intp, unlang_interpret_t);
1837
1838 intp_thread_default = intp;
1839}
1840
1841/** Get the default interpreter for this thread
1842 *
1843 * This allows detached requests to be executed asynchronously
1844 */
1846{
1847 if (!intp_thread_default) return NULL;
1848
1849 return talloc_get_type_abort(intp_thread_default, unlang_interpret_t);
1850}
1851
1853{
1854 xlat_t *xlat;
1855 /*
1856 * Should be void, but someone decided not to register multiple xlats
1857 * breaking the convention we use everywhere else in the server...
1858 */
1859 if (unlikely((xlat = xlat_func_register(ctx, "interpreter", unlang_interpret_xlat, FR_TYPE_VOID)) == NULL)) return -1;
1861
1862 if (unlikely((xlat = xlat_func_register(ctx, "cancel", unlang_cancel_xlat, FR_TYPE_VOID)) == NULL)) return -1;
1864
1865 return 0;
1866}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_UNWIND
Break out of the current group.
Definition action.h:41
@ 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:43
@ 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:42
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_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: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: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:833
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:1602
static size_t unlang_action_table_len
Definition interpret.c:48
static fr_table_num_ordered_t const unlang_frame_action_table[]
Definition interpret.c:50
static void unlang_interpret_request_detach(request_t *request)
Definition interpret.c:1129
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:784
bool unlang_request_is_done(request_t const *request)
Return whether a request has been marked done.
Definition interpret.c:1388
static unlang_frame_action_t frame_eval(request_t *request, unlang_stack_frame_t *frame, rlm_rcode_t *result, int *priority)
Evaluates all the unlang nodes in a section.
Definition interpret.c:539
static unlang_group_t empty_group
Definition interpret.c:985
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:1795
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1307
static unlang_frame_action_t result_calculate(request_t *request, unlang_stack_frame_t *frame, rlm_rcode_t *result, int *priority)
Update the current result after each instruction, and after popping each stack frame.
Definition interpret.c:320
int unlang_interpret_push_instruction(request_t *request, void *instruction, rlm_rcode_t default_rcode, bool top_frame)
Push an instruction onto the request stack for later interpretation.
Definition interpret.c:1032
void unlang_interpret_request_done(request_t *request)
Indicate to the caller of the interpreter that this request is complete.
Definition interpret.c:1089
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:1803
unlang_interpret_t * unlang_interpret_get(request_t *request)
Get the interpreter set for a request.
Definition interpret.c:1812
rlm_rcode_t unlang_interpret_stack_result(request_t *request)
Get the current rcode for the frame.
Definition interpret.c:1349
int unlang_interpret_stack_depth(request_t *request)
Return the depth of the request's stack.
Definition interpret.c:1334
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1418
static xlat_arg_parser_t const unlang_interpret_xlat_args[]
Definition interpret.c:1593
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1462
bool unlang_request_is_scheduled(request_t const *request)
Return whether a request is currently scheduled.
Definition interpret.c:1371
void unlang_frame_signal(request_t *request, fr_signal_t action, int limit)
Send a signal (usually stop) to a request.
Definition interpret.c:1158
int unlang_interpret_init_global(TALLOC_CTX *ctx)
Definition interpret.c:1852
unlang_interpret_t * unlang_interpret_get_thread_default(void)
Get the default interpreter for this thread.
Definition interpret.c:1845
fr_dict_t const * old_dict
the previous dictionary for the request
Definition interpret.c:215
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition interpret.c:1063
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition interpret.c:1834
#define DUMP_STACK
Definition interpret.c:141
int unlang_interpret_push(request_t *request, unlang_t const *instruction, rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
Push a new frame onto the stack.
Definition interpret.c:159
static void instruction_retry_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1272
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:1761
static void instruction_timeout_handler(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *ctx)
Definition interpret.c:1288
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition interpret.c:1381
static void unlang_interpret_request_stop(request_t *request)
Definition interpret.c:1115
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:1492
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition interpret.c:1212
static xlat_arg_parser_t const unlang_cancel_xlat_args[]
Definition interpret.c:1477
static fr_table_num_ordered_t const unlang_action_table[]
Definition interpret.c:40
static void stack_dump(request_t *request)
Definition interpret.c:127
static int _local_variables_free(unlang_variable_ref_t *ref)
Definition interpret.c:219
static void instruction_dump(request_t *request, unlang_t const *instruction)
Definition interpret.c:58
bool unlang_interpret_is_resumable(request_t *request)
Check if a request as resumable.
Definition interpret.c:1400
unlang_action_t unlang_interpret_push_children(rlm_rcode_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:255
int unlang_interpret_push_section(request_t *request, CONF_SECTION *cs, rlm_rcode_t default_rcode, bool top_frame)
Push a configuration section onto the request stack for later interpretation.
Definition interpret.c:1009
void unlang_interpret_stack_result_set(request_t *request, rlm_rcode_t rcode)
Overwrite the current stack rcode.
Definition interpret.c:1361
#define UNWIND_FLAG_DUMP(attrib)
request_t * request
the request
Definition interpret.c:216
static void frame_dump(request_t *request, unlang_stack_frame_t *frame)
Definition interpret.c:73
static xlat_action_t unlang_cancel_never_run(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *in)
Definition interpret.c:1506
static char * stack_unwind_flag_dump(uint8_t unwind)
Definition interpret.c:104
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:1520
static size_t unlang_frame_action_table_len
Definition interpret.c:55
static _Thread_local unlang_interpret_t * intp_thread_default
The default interpreter instance for this thread.
Definition interpret.c:38
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:1822
unlang_request_stop_t stop
function called when a request is signalled to stop.
Definition interpret.h:116
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:38
unlang_request_done_t done_internal
Function called when an internal request completes.
Definition interpret.h:112
unlang_request_resume_t resume
Function called when a request is resumed.
Definition interpret.h:118
#define UNLANG_SUB_FRAME
Definition interpret.h:36
unlang_request_done_t done_external
Function called when a external request completes.
Definition interpret.h:111
unlang_request_init_t detach
Function called when a request is detached.
Definition interpret.h:115
unlang_request_runnable_t mark_runnable
Function called when a request needs to be added back to the runnable queue.
Definition interpret.h:119
unlang_request_yield_t yield
Function called when a request yields.
Definition interpret.h:117
unlang_request_done_t done_detached
Function called when a detached request completes.
Definition interpret.h:113
unlang_request_scheduled_t scheduled
Function to check if a request is already scheduled.
Definition interpret.h:121
unlang_request_init_t init_internal
Function called to initialise an internal request.
Definition interpret.h:109
struct unlang_interpret_s unlang_interpret_t
Interpreter handle.
Definition interpret.h:47
External functions provided by the owner of the interpret.
Definition interpret.h:103
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 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:158
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_VOID
User data.
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
@ MOD_ACTION_RETURN
Definition mod_action.h:40
@ MOD_ACTION_REJECT
Definition mod_action.h:41
@ MOD_PRIORITY_MAX
Definition mod_action.h:58
@ MOD_ACTION_RETRY
Definition mod_action.h:42
fr_retry_config_t retry
Definition mod_action.h:63
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:62
Declarations for the unlang module interface.
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:1828
Declarations for the unlang "parallel" keyword.
#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
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_FAIL
Module failed, don't reply.
Definition rcode.h:42
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:41
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:51
#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_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
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
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
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:666
An event timer list.
Definition timer.c:49
A timer event.
Definition timer.c:75
#define fr_timer_in(...)
Definition timer.h:86
#define fr_timer_at(...)
Definition timer.h:80
static fr_event_list_t * el
xlat_action_t unlang_xlat_yield(request_t *request, xlat_func_t resume, xlat_func_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition xlat.c:569
bool required
Argument must be present, and non-empty.
Definition xlat.h:145
#define XLAT_ARGS(_list,...)
Populate local variables with value boxes from the input list.
Definition xlat.h:379
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:166
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:144
#define UNWIND_FLAG_RETURN_POINT
'return' stops here.
fr_retry_state_t state
#define unlang_frame_perf_resume(_x)
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.
static bool is_repeatable(unlang_stack_frame_t const *frame)
#define UNWIND_FLAG_TOP_FRAME
are we the top frame of the stack? If true, causes the interpreter to stop interpreting and return,...
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:93
static void repeatable_clear(unlang_stack_frame_t *frame)
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)
bool rcode_set
Set request->rcode to the result of this operation.
int priority
Result priority.
unlang_dump_t dump
Dump additional information about the frame state.
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
static unlang_action_t unwind_all(unlang_stack_t *stack)
rindent_t indent
Indent level of the request when the frame was created.
#define UNWIND_FLAG_NO_CLEAR
Keep unwinding, don't clear the unwind flag.
#define UNWIND_FLAG_BREAK_POINT
'break' stops here.
fr_timer_t * ev
unlang_process_t interpret
Function to interpret the keyword.
#define UNWIND_FLAG_NONE
No flags.
uint8_t uflags
Unwind markers.
int depth
of this retry structure
static void frame_cleanup(unlang_stack_frame_t *frame)
Cleanup any lingering frame state.
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 void stack_unwind_break_clear(unlang_stack_t *stack)
char const * name
Unknown...
static bool is_break_point(unlang_stack_frame_t const *frame)
@ UNLANG_TYPE_GROUP
Grouping section.
Definition unlang_priv.h:48
unlang_t const * instruction
The unlang node we're evaluating.
bool debug_braces
Whether the operation needs to print braces in debug mode.
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
rlm_rcode_t result
The result from executing the instruction.
char const * name
Name of the operation.
unlang_frame_action_t
Allows the frame evaluator to signal the interpreter.
Definition unlang_priv.h:83
@ 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:84
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
Definition unlang_priv.h:88
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
Definition unlang_priv.h:87
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
Definition unlang_priv.h:86
static void yielded_set(unlang_stack_frame_t *frame)
static void yielded_clear(unlang_stack_frame_t *frame)
#define unlang_frame_perf_yield(_x)
fr_time_t timeout
#define unlang_frame_perf_cleanup(_x)
unlang_t const * next
The next unlang node we will evaluate.
static void stack_unwind_return_clear(unlang_stack_t *stack)
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.
static void stack_unwind_top_frame_clear(unlang_stack_t *stack)
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:4161
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:4382
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:632
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:643
static size_t char ** out
Definition value.h:1012
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:362
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