The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
unlang_priv.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 */
17
18/**
19 * $Id: 3812bc4deb5ceb592db9e7b524afb1f130479f62 $
20 *
21 * @file unlang/unlang_priv.h
22 * @brief Private interpreter structures and functions
23 *
24 * @author Alan DeKok (aland@freeradius.org)
25 *
26 * @copyright 2016-2019 The FreeRADIUS server project
27 */
28#include <freeradius-devel/server/cf_util.h> /* Need CONF_* definitions */
29#include <freeradius-devel/server/map_proc.h>
30#include <freeradius-devel/server/modpriv.h>
31#include <freeradius-devel/server/time_tracking.h>
32#include <freeradius-devel/util/debug.h>
33#include <freeradius-devel/unlang/base.h>
34#include <freeradius-devel/io/listen.h>
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40/** Types of unlang_t nodes
41 *
42 * Here are our basic types: unlang_t, unlang_group_t, and unlang_module_t. For an
43 * explanation of what they are all about, see doc/unlang/configurable_failover.adoc
44 */
45typedef enum {
46 UNLANG_TYPE_NULL = 0, //!< unlang type not set.
47 UNLANG_TYPE_MODULE = 1, //!< Module method.
48 UNLANG_TYPE_FUNCTION, //!< Internal call to a function or submodule.
49 UNLANG_TYPE_GROUP, //!< Grouping section.
50 UNLANG_TYPE_REDUNDANT, //!< exactly like group, but with different default return codes
51 UNLANG_TYPE_LOAD_BALANCE, //!< Load balance section.
52 UNLANG_TYPE_REDUNDANT_LOAD_BALANCE, //!< Redundant load balance section.
53 UNLANG_TYPE_PARALLEL, //!< execute statements in parallel
54 UNLANG_TYPE_IF, //!< Condition.
55 UNLANG_TYPE_ELSE, //!< !Condition.
56 UNLANG_TYPE_ELSIF, //!< !Condition && Condition.
57 UNLANG_TYPE_UPDATE, //!< Update block.
58 UNLANG_TYPE_SWITCH, //!< Switch section.
59 UNLANG_TYPE_CASE, //!< Case section (within a #UNLANG_TYPE_SWITCH).
60 UNLANG_TYPE_FOREACH, //!< Foreach section.
61 UNLANG_TYPE_BREAK, //!< Break statement (within a #UNLANG_TYPE_FOREACH or #UNLANG_TYPE_CASE).
62 UNLANG_TYPE_CONTINUE, //!< Break statement (within a #UNLANG_TYPE_FOREACH).
63 UNLANG_TYPE_RETURN, //!< Return statement.
64 UNLANG_TYPE_MAP, //!< Mapping section (like #UNLANG_TYPE_UPDATE, but uses
65 //!< values from a #map_proc_t call).
66 UNLANG_TYPE_SUBREQUEST, //!< create a child subrequest
67 UNLANG_TYPE_CHILD_REQUEST, //!< a frame at the top of a child's request stack used to signal the
68 ///< parent when the child is complete.
69 UNLANG_TYPE_DETACH, //!< detach a child
70 UNLANG_TYPE_CALL, //!< call another virtual server
71 UNLANG_TYPE_CALLER, //!< conditionally check parent dictionary type
72 UNLANG_TYPE_TIMEOUT, //!< time-based timeouts.
73 UNLANG_TYPE_LIMIT, //!< limit number of requests in a section
74 UNLANG_TYPE_TRANSACTION, //!< transactions for editing lists
75 UNLANG_TYPE_TRY, //!< try / catch blocks
76 UNLANG_TYPE_CATCH, //!< catch a previous try
77 UNLANG_TYPE_FINALLY, //!< run at the end of a virtual server.
78 UNLANG_TYPE_POLICY, //!< Policy section.
79 UNLANG_TYPE_XLAT, //!< Represents one level of an xlat expansion.
80 UNLANG_TYPE_TMPL, //!< asynchronously expand a tmpl_t
81 UNLANG_TYPE_EDIT, //!< edit VPs in place. After 20 years!
84
85/** Allows the frame evaluator to signal the interpreter
86 *
87 */
88typedef enum {
89 UNLANG_FRAME_ACTION_POP = 1, //!< Pop the current frame, and check the next one further
90 ///< up in the stack for what to do next.
91 UNLANG_FRAME_ACTION_RETRY, //!< retry the current frame
92 UNLANG_FRAME_ACTION_NEXT, //!< Process the next instruction at this level.
93 UNLANG_FRAME_ACTION_YIELD //!< Temporarily return control back to the caller on the C
94 ///< stack.
96
97#define UNLANG_NEXT_STOP (false)
98#define UNLANG_NEXT_SIBLING (true)
99
100#define UNLANG_DETACHABLE (true)
101#define UNLANG_NORMAL_CHILD (false)
102
103DIAG_OFF(attributes)
104typedef enum CC_HINT(flag_enum) {
105 UNLANG_FRAME_FLAG_NONE = 0x00, //!< No flags.
106 UNLANG_FRAME_FLAG_REPEAT = 0x01, //!< Repeat the frame on the way up the stack.
107 UNLANG_FRAME_FLAG_TOP_FRAME = 0x02, //!< are we the top frame of the stack?
108 ///< If true, causes the interpreter to stop
109 ///< interpreting and return, control then passes
110 ///< to whatever called the interpreter.
111 UNLANG_FRAME_FLAG_YIELDED = 0x04, //!< frame has yielded
112 UNLANG_FRAME_FLAG_UNWIND = 0x08, //!< This frame should be unwound without evaluation.
114DIAG_ON(attributes)
115
116typedef struct unlang_s unlang_t;
118
119/** A node in a graph of #unlang_op_t (s) that we execute
120 *
121 * The interpreter acts like a turing machine, with #unlang_t nodes forming the tape
122 * and the #unlang_action_t the instructions.
123 *
124 * This is the parent 'class' for multiple #unlang_t node specialisations.
125 * The #unlang_t struct is listed first in the specialisation so that we can cast between
126 * parent/child classes without knowledge of the layout of the structures.
127 *
128 * The specialisations of the nodes describe additional details of the operation to be performed.
129 */
130struct unlang_s {
131 unlang_t *parent; //!< Previous node.
132 unlang_t *next; //!< Next node (executed on #UNLANG_ACTION_EXECUTE_NEXT et al).
133 char const *name; //!< Unknown...
134 char const *debug_name; //!< Printed in log messages when the node is executed.
135 unlang_type_t type; //!< The specialisation of this node.
136 bool closed; //!< whether or not this section is closed to new statements
137 CONF_ITEM *ci; //!< used to generate this item
138 unsigned int number; //!< unique node number
139 unlang_mod_actions_t actions; //!< Priorities, etc. for the various return codes.
140};
141
142/** Describes how to allocate an #unlang_group_t with additional memory keyword specific data
143 *
144 */
145typedef struct {
146 unlang_type_t type; //!< Keyword.
147 size_t len; //!< Total length of the unlang_group_t + specialisation struct.
148 unsigned pool_headers; //!< How much additional space to allocate for chunk headers.
149 size_t pool_len; //!< How much additional space to allocate for extensions.
150 char const *type_name; //!< Talloc type name.
152
153typedef struct {
154 fr_dict_t *dict; //!< our dictionary
155 fr_dict_attr_t const *root; //!< the root of our dictionary
156 int max_attr; //!< 1..N local attributes have been defined
158
159/** Generic representation of a grouping
160 *
161 * Can represent IF statements, maps, update sections etc...
162 */
163typedef struct {
165 unlang_t *children; //!< Children beneath this group. The body of an if
166 //!< section for example.
167 unlang_t **tail; //!< pointer to the tail which gets updated
170
171 unlang_variable_t *variables; //!< rarely used, so we don't usually need it
173
174/** A naked xlat
175 *
176 * @note These are vestigial and may be removed in future.
177 */
178typedef struct {
180 tmpl_t const *tmpl;
182
183/** Function to call when interpreting a frame
184 *
185 * @param[in,out] p_result Pointer to the current rcode, may be modified by the function.
186 * @param[in] request The current request.
187 * @param[in] frame being executed.
188 *
189 * @return an action for the interpreter to perform.
190 */
192 unlang_stack_frame_t *frame);
193
194/** Function to call if the request was signalled
195 *
196 * This is the instruction specific cancellation function.
197 * This function will usually either call a more specialised cancellation function
198 * set when something like a module yielded, or just cleanup the state of the original
199 * #unlang_process_t.
200 *
201 * @param[in] request The current request.
202 * @param[in] frame being signalled.
203 * @param[in] action We're being signalled with.
204 */
205typedef void (*unlang_signal_t)(request_t *request,
206 unlang_stack_frame_t *frame, fr_signal_t action);
207
208/** Custom callback for dumping information about frame state
209 *
210 * @param[in] request The current request.
211 * @param[in] frame to provide additional information for.
212 */
213typedef void (*unlang_dump_t)(request_t *request, unlang_stack_frame_t *frame);
214
215typedef int (*unlang_thread_instantiate_t)(unlang_t const *instruction, void *thread_inst);
216
217DIAG_OFF(attributes)
218typedef enum CC_HINT(flag_enum) {
219 UNLANG_OP_FLAG_NONE = 0x00, //!< No flags.
220 UNLANG_OP_FLAG_DEBUG_BRACES = 0x01, //!< Print debug braces.
221 UNLANG_OP_FLAG_RCODE_SET = 0x02, //!< Set request->rcode to the result of this operation.
222 UNLANG_OP_FLAG_NO_CANCEL = 0x04, //!< Must not be cancelled.
223 ///< @Note Slightly confusingly, a cancellation signal
224 ///< can still be delivered to a frame that is not
225 ///< cancellable, but the frame won't be automatically
226 ///< unwound. This lets the frame know that cancellation
227 ///< is desired, but can be ignored.
228 UNLANG_OP_FLAG_BREAK_POINT = 0x08, //!< Break point.
229 UNLANG_OP_FLAG_RETURN_POINT = 0x10, //!< Return point.
230 UNLANG_OP_FLAG_CONTINUE_POINT = 0x20 //!< Continue point.
232DIAG_ON(attributes)
233
234/** An unlang operation
235 *
236 * These are like the opcodes in other interpreters. Each operation, when executed
237 * will return an #unlang_action_t, which determines what the interpreter does next.
238 */
239typedef struct {
240 char const *name; //!< Name of the operation.
241
242 unlang_process_t interpret; //!< Function to interpret the keyword
243
244 unlang_signal_t signal; //!< Function to signal stop / dup / whatever
245
246 unlang_dump_t dump; //!< Dump additional information about the frame state.
247
248 unlang_thread_instantiate_t thread_instantiate; //!< per-thread instantiation function
250 char const *thread_inst_type;
251
252 unlang_op_flag_t flag; //!< Flags for this operation.
253
254 size_t frame_state_size; //!< size of instance data in the stack frame
255
256 char const *frame_state_type; //!< talloc name of the frame instance data
257
258 size_t frame_state_pool_objects; //!< How many sub-allocations we expect.
259
260 size_t frame_state_pool_size; //!< The total size of the pool to alloc.
262
263typedef struct {
264 unlang_t const *instruction; //!< instruction which we're executing
265 void *thread_inst; //!< thread-specific instance data
266#ifdef WITH_PERF
267 uint64_t use_count; //!< how many packets it has processed
268 uint64_t running; //!< currently running this instruction
269 uint64_t yielded; //!< currently yielded
270 fr_time_tracking_t tracking; //!< tracking cpu time
271#endif
273
274void *unlang_thread_instance(unlang_t const *instruction);
275
276#ifdef WITH_PERF
281#else
282#define unlang_frame_perf_init(_x)
283#define unlang_frame_perf_yield(_x)
284#define unlang_frame_perf_resume(_x)
285#define unlang_frame_perf_cleanup(_x)
286#endif
287
288void unlang_stack_signal(request_t *request, fr_signal_t action, int limit);
289
290typedef struct {
292 int depth; //!< of this retry structure
297
298/** Our interpreter stack, as distinct from the C stack
299 *
300 * We don't call the modules recursively. Instead we iterate over a list of #unlang_t and
301 * and manage the call stack ourselves.
302 *
303 * After looking at various green thread implementations, it was decided that using the existing
304 * unlang interpreter stack was the best way to perform async I/O.
305 *
306 * Each request as an unlang interpreter stack associated with it, which represents its progress
307 * through the server. Because the interpreter stack is distinct from the C stack, we can have
308 * a single system thread with many thousands of pending requests.
309 */
311 unlang_t const *instruction; //!< The unlang node we're evaluating.
312 unlang_t const *next; //!< The next unlang node we will evaluate
313
314 unlang_process_t process; //!< function to call for interpreting this stack frame
315 unlang_signal_t signal; //!< function to call when signalling this stack frame
316
317 /** Stack frame specialisations
318 *
319 * These store extra (mutable) state data, for the immutable (#unlang_t)
320 * instruction. Instructions can't be used to store data because they
321 * might be shared between multiple threads.
322 *
323 * Which stack_entry specialisation to use is determined by the
324 * instruction->type.
325 */
326 void *state;
327
328 unlang_retry_t *retry; //!< if the frame is being retried.
329
330 rlm_rcode_t result; //!< The result from executing the instruction.
331 int priority; //!< Result priority. When we pop this stack frame
332 ///< this priority will be compared with the one of the
333 ///< frame lower in the stack to determine if the
334 ///< result stored in the lower stack frame should
335 rindent_t indent; //!< Indent level of the request when the frame was
336 ///< created. This is used to restore the indent
337 ///< level when the stack is being forcefully unwound.
338 unlang_frame_flag_t flag; //!< Unwind flags
339
340#ifdef WITH_PERF
341 fr_time_tracking_t tracking; //!< track this instance of this instruction
342#endif
343};
344
345/** An unlang stack associated with a request
346 *
347 */
348typedef struct {
349 unlang_interpret_t *intp; //!< Interpreter that the request is currently
350 ///< associated with.
351 int priority; //!< Current priority.
352 rlm_rcode_t result; //!< The current stack rcode.
353 int depth; //!< Current depth we're executing at.
354 uint8_t unwind; //!< Unwind to this frame if it exists.
355 ///< This is used for break and return.
356 unlang_stack_frame_t frame[UNLANG_STACK_MAX]; //!< The stack...
358
359/** Different operations the interpreter can execute
360 */
361extern unlang_op_t unlang_ops[];
362
363#define MOD_NUM_TYPES (UNLANG_TYPE_XLAT + 1)
364
366extern size_t mod_rcode_table_len;
367
368static inline void repeatable_set(unlang_stack_frame_t *frame) { frame->flag |= UNLANG_FRAME_FLAG_REPEAT; }
370static inline void yielded_set(unlang_stack_frame_t *frame) { frame->flag |= UNLANG_FRAME_FLAG_YIELDED; }
371static inline void unwind_set(unlang_stack_frame_t *frame) { frame->flag |= UNLANG_FRAME_FLAG_UNWIND; }
372
373static inline void repeatable_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_REPEAT; }
374static inline void top_frame_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_TOP_FRAME; }
375static inline void yielded_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_YIELDED; }
376static inline void unwind_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_UNWIND; }
377
378static inline bool is_repeatable(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_REPEAT; }
379static inline bool is_top_frame(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_TOP_FRAME; }
380static inline bool is_yielded(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_YIELDED; }
381static inline bool is_unwinding(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_UNWIND; }
382
383static inline bool _instruction_has_debug_braces(unlang_t const *instruction) { return unlang_ops[instruction->type].flag & UNLANG_OP_FLAG_DEBUG_BRACES; }
385#define has_debug_braces(_thing) \
386 _Generic((_thing), \
387 unlang_t *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
388 unlang_t const *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
389 unlang_stack_frame_t *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)), \
390 unlang_stack_frame_t const *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)) \
391 )
392static inline bool is_rcode_set(unlang_stack_frame_t const *frame) { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_RCODE_SET; }
393static inline bool is_cancellable(unlang_stack_frame_t const *frame) { return !(unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_NO_CANCEL); }
394static inline bool is_break_point(unlang_stack_frame_t const *frame) { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_BREAK_POINT; }
397
398
399/** Find the first frame with a given flag
400 *
401 * @return
402 * - 0 if no frame has the flag.
403 * - The index of the first frame with the flag.
404 */
406{
407 unsigned int i;
408
409 for (i = stack->depth; i > 0; i--) {
410 unlang_stack_frame_t *frame = &stack->frame[i];
411
412 if (frame->flag & flag) return i;
413 }
414 return 0;
415}
416
417/** Find the first frame with a given flag
418 *
419 * @return
420 * - 0 if no frame has the flag.
421 * - The index of the first frame with the flag.
422 */
424{
425 unsigned int i;
426
427 for (i = stack->depth; i > 0; i--) {
428 unlang_stack_frame_t *frame = &stack->frame[i];
429
430 if (unlang_ops[frame->instruction->type].flag & flag) return i;
431 }
432 return 0;
433}
434
435/** Mark up frames as cancelled so they're immediately popped by the interpreter
436 *
437 * @note We used to do this asynchronously, but now we may need to execute timeout sections
438 * which means it's not enough to pop and cleanup the stack, we need continue executing
439 * the request.
440 *
441 * @param[in] stack The current stack.
442 * @param[in] to_depth mark all frames below this depth as cancelled.
443 */
444static inline unlang_action_t unwind_to_depth(unlang_stack_t *stack, unsigned int to_depth)
445{
447 unsigned int i, depth = stack->depth; /* must be signed to avoid underflow */
448
449 if (!fr_cond_assert(to_depth >= 1)) return UNLANG_ACTION_FAIL;
450
451 for (i = depth; i >= to_depth; i--) {
452 frame = &stack->frame[i];
453 if (!is_cancellable(frame)) continue;
454 unwind_set(frame);
455 }
456
458}
459
460/** Mark the entire stack as cancelled
461 *
462 * This cancels all frames up to the next "break" frame.
463 *
464 * @param[out] depth_p Depth of the break || return || continue point.
465 * @param[in] stack The current stack.
466 * @param[in] flag Flag to search for. One of:
467 * - UNLANG_OP_FLAG_BREAK_POINT
468 * - UNLANG_OP_FLAG_RETURN_POINT
469 * - UNLANG_OP_FLAG_CONTINUE_POINT
470 * @return UNLANG_ACTION_CALCULATE_RESULT
471 */
472static inline unlang_action_t unwind_to_op_flag(unsigned int *depth_p, unlang_stack_t *stack, unlang_op_flag_t flag)
473{
474 unsigned int depth;
475
477 if (depth == 0) {
478 if (depth_p) *depth_p = stack->depth + 1; /* Don't cancel any frames! */
480 }
481
482 unwind_to_depth(stack, depth + 1); /* cancel UP TO the break point */
483
484 if (depth_p) *depth_p = depth;
485
487}
488
490{
491 unlang_stack_t *stack = request->stack;
492
493 return &stack->frame[stack->depth];
494}
495
496static inline int stack_depth_current(request_t *request)
497{
498 unlang_stack_t *stack = request->stack;
499
500 return stack->depth;
501}
502
504{
505 unlang_t const *instruction = frame->instruction;
506 unlang_op_t *op;
507 char const *name;
508
510
511 op = &unlang_ops[instruction->type];
512 name = op->frame_state_type ? op->frame_state_type : __location__;
513
514 frame->process = op->interpret;
515 frame->signal = op->signal;
516
517#ifdef HAVE_TALLOC_ZERO_POOLED_OBJECT
518 /*
519 * Pooled object
520 */
522 MEM(frame->state = _talloc_zero_pooled_object(stack,
526 } else
527#endif
528 /*
529 * Pool
530 */
531 if (op->frame_state_pool_size && !op->frame_state_size) {
532 MEM(frame->state = talloc_pool(stack,
534 ((20 + 68 + 15) * op->frame_state_pool_objects))); /* from samba talloc.c */
535 talloc_set_name_const(frame->state, name);
536 /*
537 * Object
538 */
539 } else if (op->frame_state_size) {
540 MEM(frame->state = _talloc_zero(stack, op->frame_state_size, name));
541 }
542
543 /*
544 * Don't change frame->retry, it may be left over from a previous retry.
545 */
546}
547
548/** Cleanup any lingering frame state
549 *
550 */
551static inline void frame_cleanup(unlang_stack_frame_t *frame)
552{
554
555 /*
556 * Don't clear top_frame flag, bad things happen...
557 */
559 if (frame->state) {
560 talloc_free_children(frame->state); /* *(ev->parent) = NULL in event.c */
561 TALLOC_FREE(frame->state);
562 }
563}
564
565/** Advance to the next sibling instruction
566 *
567 */
569{
570 frame_cleanup(frame);
571 frame->instruction = frame->next;
572
573 if (!frame->instruction) return;
574
575 frame->next = frame->instruction->next;
576
577 frame_state_init(stack, frame);
578}
579
580/** Pop a stack frame, removing any associated dynamically allocated state
581 *
582 * @param[in] request The current request.
583 * @param[in] stack frame to pop.
584 */
585static inline void frame_pop(request_t *request, unlang_stack_t *stack)
586{
588
589 fr_assert(stack->depth >= 1);
590
591 frame = &stack->frame[stack->depth];
592
593 /*
594 * Signal the frame to get it back into a consistent state
595 * as we won't be calling the resume function.
596 *
597 * If the frame was cancelled, the signal function will
598 * have already been called.
599 */
600 if (!is_unwinding(frame) && is_repeatable(frame)) {
601 if (frame->signal) frame->signal(request, frame, FR_SIGNAL_CANCEL);
602 repeatable_clear(frame);
603 }
604
605 /*
606 * We clean up the retries when we pop the frame, not
607 * when we do a frame_cleanup(). That's because
608 * frame_cleanup() is called from the signal handler, and
609 * we need to keep frame->retry around to ensure that we
610 * know how to _stop_ the retries after they've hit a timeout.
611 */
612 TALLOC_FREE(frame->retry);
613
614 /*
615 * Ensure log indent is at the same level as it was when
616 * the frame was pushed. This is important when we're
617 * unwinding the stack and forcefully cancelling calls.
618 */
619 request->log.indent = frame->indent;
620
621 frame_cleanup(frame);
622
623 stack->depth--;
624}
625
626/** Mark the current stack frame up for repeat, and set a new process function
627 *
628 */
629static inline void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
630{
631 repeatable_set(frame);
632 frame->process = process;
633}
634
636{
637 /*
638 * We're skipping the remaining siblings, stop the
639 * interpreter from continuing and have it pop
640 * this frame, running cleanups normally.
641 *
642 * We don't explicitly cleanup here, otherwise we
643 * end up doing it twice and bad things happen.
644 */
645 if (!unlang) {
646 frame->next = NULL;
648 }
649
650 /*
651 * Clean up this frame now, so that stats, etc. will be
652 * processed using the correct frame.
653 */
654 frame_cleanup(frame);
655
656 /*
657 * frame_next() will call cleanup *before* resetting the frame->instruction.
658 * but since the instruction is NULL, no duplicate cleanups will happen.
659 *
660 * frame_next() will then set frame->instruction = frame->next, and everything will be OK.
661 */
662 frame->instruction = NULL;
663 frame->next = unlang;
665}
666
667/** @name Conversion functions for converting #unlang_t to its specialisations
668 *
669 * Simple conversions: #unlang_module_t and #unlang_group_t are subclasses of #unlang_t,
670 * so we often want to go back and forth between them.
671 *
672 * @{
673 */
675{
677
678 return UNCONST(unlang_group_t *, p);
679}
680
682{
683 return UNCONST(unlang_t *, p);
684}
685
691
693{
694 return UNCONST(unlang_t *, p);
695}
696/** @} */
697
698/** @name Internal interpreter functions needed by ops
699 *
700 * @{
701 */
702int unlang_interpret_push(request_t *request, unlang_t const *instruction,
703 rlm_rcode_t default_rcode, bool do_next_sibling, bool top_frame)
704 CC_HINT(warn_unused_result);
705
707 rlm_rcode_t default_rcode, bool do_next_sibling)
708 CC_HINT(warn_unused_result);
709
711
712void unlang_op_free(void);
713
714/** @} */
715
716/** @name io shims
717 *
718 * Functions to simulate a 'proto' module when we're running 'fake'
719 * requests. i.e. those created by parallel and subrequest.
720 *
721 * @{
722 */
723request_t *unlang_io_subrequest_alloc(request_t *parent, fr_dict_t const *namespace, bool detachable);
724
725/** @} */
726
727/** @name op init functions
728 *
729 * Functions to trigger registration of the various unlang ops.
730 *
731 * @{
732 */
733void unlang_register(int type, unlang_op_t *op);
734
735void unlang_call_init(void);
736
737void unlang_caller_init(void);
738
739void unlang_condition_init(void);
740
741void unlang_finally_init(void);
742
743void unlang_foreach_init(void);
744
745void unlang_function_init(void);
746
747void unlang_group_init(void);
748
749void unlang_load_balance_init(void);
750
751void unlang_map_init(void);
752
753void unlang_module_init(void);
754
755void unlang_return_init(void);
756
757void unlang_parallel_init(void);
758
760
761void unlang_detach_init(void);
762
763void unlang_switch_init(void);
764
765void unlang_tmpl_init(void);
766
767void unlang_edit_init(void);
768
769void unlang_timeout_init(void);
770
771void unlang_transaction_init(void);
772
773void unlang_limit_init(void);
774
775void unlang_try_init(void);
776
777void unlang_catch_init(void);
778
779 /** @} */
780
781#ifdef __cplusplus
782}
783#endif
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
Definition action.h:38
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define DIAG_ON(_x)
Definition build.h:460
#define DIAG_OFF(_x)
Definition build.h:459
Common header for all CONF_* types.
Definition cf_priv.h:49
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:139
#define MEM(x)
Definition debug.h:36
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:38
static char * stack[MAX_STACK]
Definition radmin.c:159
unsigned int uint32_t
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
#define fr_assert(_expr)
Definition rad_assert.h:38
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
static char const * name
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
fr_aka_sim_id_type_t type
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_get_type_abort_const
Definition talloc.h:287
A timer event.
Definition timer.c:84
fr_retry_state_t state
#define unlang_frame_perf_resume(_x)
static unlang_action_t unwind_to_op_flag(unsigned int *depth_p, unlang_stack_t *stack, unlang_op_flag_t flag)
Mark the entire stack as cancelled.
size_t frame_state_pool_objects
How many sub-allocations we expect.
void unlang_register(int type, unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:63
static void frame_pop(request_t *request, unlang_stack_t *stack)
Pop a stack frame, removing any associated dynamically allocated state.
unlang_t * next
Next node (executed on UNLANG_ACTION_EXECUTE_NEXT et al).
static void frame_next(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Advance to the next sibling instruction.
unlang_frame_flag_t
@ UNLANG_FRAME_FLAG_TOP_FRAME
are we the top frame of the stack? If true, causes the interpreter to stop interpreting and return,...
@ UNLANG_FRAME_FLAG_REPEAT
Repeat the frame on the way up the stack.
@ UNLANG_FRAME_FLAG_NONE
No flags.
@ UNLANG_FRAME_FLAG_UNWIND
This frame should be unwound without evaluation.
@ UNLANG_FRAME_FLAG_YIELDED
frame has yielded
void unlang_switch_init(void)
Definition switch.c:133
static bool _instruction_has_debug_braces(unlang_t const *instruction)
static unsigned int unlang_frame_by_flag(unlang_stack_t *stack, unlang_frame_flag_t flag)
Find the first frame with a given flag.
static bool is_cancellable(unlang_stack_frame_t const *frame)
static bool is_repeatable(unlang_stack_frame_t const *frame)
unlang_interpret_t * intp
Interpreter that the request is currently associated with.
CONF_SECTION * cs
static void repeatable_clear(unlang_stack_frame_t *frame)
static unlang_action_t unwind_to_depth(unlang_stack_t *stack, unsigned int to_depth)
Mark up frames as cancelled so they're immediately popped by the interpreter.
unlang_retry_t * retry
if the frame is being retried.
void unlang_finally_init(void)
Definition finally.c:159
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.
char const * frame_state_type
talloc name of the frame instance data
char const * type_name
Talloc type name.
void * state
Stack frame specialisations.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
void(* unlang_signal_t)(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Function to call if the request was signalled.
unlang_t * parent
Previous node.
static unsigned int unlang_frame_by_op_flag(unlang_stack_t *stack, unlang_op_flag_t flag)
Find the first frame with a given flag.
void unlang_limit_init(void)
Definition limit.c:124
unlang_action_t(* unlang_process_t)(rlm_rcode_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Function to call when interpreting a frame.
unlang_signal_t signal
Function to signal stop / dup / whatever.
int unlang_subrequest_op_init(void)
Initialise subrequest ops.
Definition subrequest.c:516
size_t frame_state_size
size of instance data in the stack frame
static void unwind_set(unlang_stack_frame_t *frame)
char const * thread_inst_type
fr_dict_attr_t const * root
the root of our dictionary
rlm_rcode_t result
The current stack rcode.
int(* unlang_thread_instantiate_t)(unlang_t const *instruction, void *thread_inst)
void unlang_timeout_init(void)
Definition timeout.c:267
static void frame_state_init(unlang_stack_t *stack, unlang_stack_frame_t *frame)
#define unlang_frame_perf_init(_x)
void unlang_edit_init(void)
Definition edit.c:1746
void unlang_tmpl_init(void)
Definition tmpl.c:328
void unlang_call_init(void)
Definition call.c:249
int priority
Result priority.
void unlang_map_init(void)
Definition map.c:374
bool closed
whether or not this section is closed to new statements
unlang_dump_t dump
Dump additional information about the frame state.
static bool _frame_has_debug_braces(unlang_stack_frame_t const *frame)
static unlang_t * unlang_group_to_generic(unlang_group_t const *p)
void unlang_condition_init(void)
Definition condition.c:103
rindent_t indent
Indent level of the request when the frame was created.
uint8_t unwind
Unwind to this frame if it exists.
unlang_t ** tail
pointer to the tail which gets updated
static void top_frame_clear(unlang_stack_frame_t *frame)
fr_timer_t * ev
unlang_process_t interpret
Function to interpret the keyword.
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:143
unlang_t self
int depth
of this retry structure
static void frame_cleanup(unlang_stack_frame_t *frame)
Cleanup any lingering frame state.
static unlang_t * unlang_tmpl_to_generic(unlang_tmpl_t const *p)
void unlang_op_free(void)
request_t * request
void unlang_load_balance_init(void)
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)
void(* unlang_dump_t)(request_t *request, unlang_stack_frame_t *frame)
Custom callback for dumping information about frame state.
unsigned int number
unique node number
void unlang_group_init(void)
Definition group.c:41
size_t mod_rcode_table_len
Definition compile.c:91
void unlang_parallel_init(void)
Definition parallel.c:386
static unlang_stack_frame_t * frame_current(request_t *request)
void unlang_transaction_init(void)
int depth
Current depth we're executing at.
char const * name
Unknown...
request_t * unlang_io_subrequest_alloc(request_t *parent, fr_dict_t const *namespace, bool detachable)
Allocate a child request based on the parent.
Definition io.c:39
static int stack_depth_current(request_t *request)
static bool is_break_point(unlang_stack_frame_t const *frame)
static void unwind_clear(unlang_stack_frame_t *frame)
void unlang_return_init(void)
Definition return.c:43
void unlang_detach_init(void)
Initialise subrequest ops.
Definition detach.c:54
unlang_type_t
Types of unlang_t nodes.
Definition unlang_priv.h:45
@ UNLANG_TYPE_SWITCH
Switch section.
Definition unlang_priv.h:58
@ UNLANG_TYPE_TRANSACTION
transactions for editing lists
Definition unlang_priv.h:74
@ UNLANG_TYPE_FINALLY
run at the end of a virtual server.
Definition unlang_priv.h:77
@ UNLANG_TYPE_SUBREQUEST
create a child subrequest
Definition unlang_priv.h:66
@ UNLANG_TYPE_CONTINUE
Break statement (within a UNLANG_TYPE_FOREACH).
Definition unlang_priv.h:62
@ UNLANG_TYPE_UPDATE
Update block.
Definition unlang_priv.h:57
@ UNLANG_TYPE_ELSIF
!Condition && Condition.
Definition unlang_priv.h:56
@ UNLANG_TYPE_ELSE
!Condition.
Definition unlang_priv.h:55
@ UNLANG_TYPE_LOAD_BALANCE
Load balance section.
Definition unlang_priv.h:51
@ UNLANG_TYPE_DETACH
detach a child
Definition unlang_priv.h:69
@ UNLANG_TYPE_GROUP
Grouping section.
Definition unlang_priv.h:49
@ UNLANG_TYPE_POLICY
Policy section.
Definition unlang_priv.h:78
@ UNLANG_TYPE_TMPL
asynchronously expand a tmpl_t
Definition unlang_priv.h:80
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
Definition unlang_priv.h:59
@ UNLANG_TYPE_LIMIT
limit number of requests in a section
Definition unlang_priv.h:73
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH or UNLANG_TYPE_CASE).
Definition unlang_priv.h:61
@ UNLANG_TYPE_TRY
try / catch blocks
Definition unlang_priv.h:75
@ UNLANG_TYPE_CALL
call another virtual server
Definition unlang_priv.h:70
@ UNLANG_TYPE_RETURN
Return statement.
Definition unlang_priv.h:63
@ UNLANG_TYPE_REDUNDANT
exactly like group, but with different default return codes
Definition unlang_priv.h:50
@ UNLANG_TYPE_MAX
Definition unlang_priv.h:82
@ UNLANG_TYPE_IF
Condition.
Definition unlang_priv.h:54
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
Definition unlang_priv.h:79
@ UNLANG_TYPE_NULL
unlang type not set.
Definition unlang_priv.h:46
@ UNLANG_TYPE_MAP
Mapping section (like UNLANG_TYPE_UPDATE, but uses values from a map_proc_t call).
Definition unlang_priv.h:64
@ UNLANG_TYPE_CALLER
conditionally check parent dictionary type
Definition unlang_priv.h:71
@ UNLANG_TYPE_TIMEOUT
time-based timeouts.
Definition unlang_priv.h:72
@ UNLANG_TYPE_MODULE
Module method.
Definition unlang_priv.h:47
@ UNLANG_TYPE_REDUNDANT_LOAD_BALANCE
Redundant load balance section.
Definition unlang_priv.h:52
@ UNLANG_TYPE_CHILD_REQUEST
a frame at the top of a child's request stack used to signal the parent when the child is complete.
Definition unlang_priv.h:67
@ UNLANG_TYPE_CATCH
catch a previous try
Definition unlang_priv.h:76
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
Definition unlang_priv.h:48
@ UNLANG_TYPE_EDIT
edit VPs in place. After 20 years!
Definition unlang_priv.h:81
@ UNLANG_TYPE_FOREACH
Foreach section.
Definition unlang_priv.h:60
@ UNLANG_TYPE_PARALLEL
execute statements in parallel
Definition unlang_priv.h:53
static void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
Mark the current stack frame up for repeat, and set a new process function.
unlang_t const * instruction
The unlang node we're evaluating.
static bool is_rcode_set(unlang_stack_frame_t const *frame)
size_t len
Total length of the unlang_group_t + specialisation struct.
void unlang_try_init(void)
Definition try.c:42
static bool is_yielded(unlang_stack_frame_t const *frame)
void unlang_catch_init(void)
Definition catch.c:98
size_t frame_state_pool_size
The total size of the pool to alloc.
unlang_type_t type
Keyword.
static void top_frame_set(unlang_stack_frame_t *frame)
unlang_variable_t * variables
rarely used, so we don't usually need it
static unlang_tmpl_t * unlang_generic_to_tmpl(unlang_t const *p)
void unlang_module_init(void)
Definition module.c:956
unlang_t const * instruction
instruction which we're executing
unlang_action_t unlang_interpret_push_children(rlm_rcode_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
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:88
@ UNLANG_FRAME_ACTION_POP
Pop the current frame, and check the next one further up in the stack for what to do next.
Definition unlang_priv.h:89
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
Definition unlang_priv.h:93
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
Definition unlang_priv.h:92
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
Definition unlang_priv.h:91
static void yielded_set(unlang_stack_frame_t *frame)
static bool is_continue_point(unlang_stack_frame_t const *frame)
static unlang_action_t frame_set_next(unlang_stack_frame_t *frame, unlang_t *unlang)
void unlang_function_init(void)
Definition function.c:337
static void yielded_clear(unlang_stack_frame_t *frame)
#define unlang_frame_perf_yield(_x)
int priority
Current priority.
size_t pool_len
How much additional space to allocate for extensions.
unsigned pool_headers
How much additional space to allocate for chunk headers.
#define unlang_frame_perf_cleanup(_x)
unlang_t const * next
The next unlang node we will evaluate.
unlang_op_t unlang_ops[]
Different operations the interpreter can execute.
Definition base.c:31
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:78
int max_attr
1..N local attributes have been defined
unlang_thread_instantiate_t thread_instantiate
per-thread instantiation function
fr_dict_t * dict
our dictionary
void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
Delivers a frame to one or more frames in the stack.
Definition interpret.c:1087
void * unlang_thread_instance(unlang_t const *instruction)
Get the thread-instance data for an instruction.
Definition compile.c:5248
static bool is_return_point(unlang_stack_frame_t const *frame)
tmpl_t const * tmpl
unlang_op_flag_t
@ UNLANG_OP_FLAG_RETURN_POINT
Return point.
@ UNLANG_OP_FLAG_CONTINUE_POINT
Continue point.
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_NONE
No flags.
@ UNLANG_OP_FLAG_RCODE_SET
Set request->rcode to the result of this operation.
@ UNLANG_OP_FLAG_NO_CANCEL
Must not be cancelled.
@ UNLANG_OP_FLAG_BREAK_POINT
Break point.
static void repeatable_set(unlang_stack_frame_t *frame)
void unlang_foreach_init(void)
Definition foreach.c:558
void unlang_caller_init(void)
Definition caller.c:55
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
unlang_t * children
Children beneath this group.
unlang_frame_flag_t flag
Unwind flags.
size_t thread_inst_size
unlang_op_flag_t flag
Flags for this operation.
int unlang_op_init(void)
static bool is_unwinding(unlang_stack_frame_t const *frame)
void * thread_inst
thread-specific instance data
Describes how to allocate an unlang_group_t with additional memory keyword specific data.
Generic representation of a grouping.
An unlang operation.
A node in a graph of unlang_op_t (s) that we execute.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
A naked xlat.
static fr_slen_t parent
Definition pair.h:845
fr_retry_state_t
Definition retry.h:45