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