The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: 705cd70647da95d7f4b682bc9096911833b06371 $
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/util/dlist.h>
34#include <freeradius-devel/unlang/base.h>
35#include <freeradius-devel/unlang/map.h>
36#include <freeradius-devel/io/listen.h>
37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42/** Types of unlang_t nodes
43 *
44 * Here are our basic types: unlang_t, unlang_group_t, and unlang_module_t. For an
45 * explanation of what they are all about, see doc/unlang/configurable_failover.adoc
46 */
47typedef enum {
48 UNLANG_TYPE_NULL = 0, //!< unlang type not set.
49 UNLANG_TYPE_MODULE = 1, //!< Module method.
50 UNLANG_TYPE_FUNCTION, //!< Internal call to a function or submodule.
51 UNLANG_TYPE_GROUP, //!< Grouping section.
52 UNLANG_TYPE_REDUNDANT, //!< exactly like group, but with different default return codes
53 UNLANG_TYPE_LOAD_BALANCE, //!< Load balance section.
54 UNLANG_TYPE_REDUNDANT_LOAD_BALANCE, //!< Redundant load balance section.
55 UNLANG_TYPE_PARALLEL, //!< execute statements in parallel
56 UNLANG_TYPE_IF, //!< Condition.
57 UNLANG_TYPE_ELSE, //!< !Condition.
58 UNLANG_TYPE_ELSIF, //!< !Condition && Condition.
59 UNLANG_TYPE_SWITCH, //!< Switch section.
60 UNLANG_TYPE_CASE, //!< Case section (within a #UNLANG_TYPE_SWITCH).
61 UNLANG_TYPE_FOREACH, //!< Foreach section.
62 UNLANG_TYPE_BREAK, //!< Break statement (within a #UNLANG_TYPE_FOREACH or #UNLANG_TYPE_CASE).
63 UNLANG_TYPE_CONTINUE, //!< Break statement (within a #UNLANG_TYPE_FOREACH).
64 UNLANG_TYPE_RETURN, //!< Return statement.
65 UNLANG_TYPE_MAP, //!< Mapping section (like #UNLANG_TYPE_UPDATE, but uses
66 //!< values from a #map_proc_t call).
67 UNLANG_TYPE_SUBREQUEST, //!< create a child subrequest
68 UNLANG_TYPE_CHILD_REQUEST, //!< a frame at the top of a child's request stack used to signal the
69 ///< parent when the child is complete.
70 UNLANG_TYPE_DETACH, //!< detach a child
71 UNLANG_TYPE_CALL, //!< call another virtual server
72 UNLANG_TYPE_CALLER, //!< conditionally check parent dictionary type
73 UNLANG_TYPE_TIMEOUT, //!< time-based timeouts.
74 UNLANG_TYPE_LIMIT, //!< limit number of requests in a section
75 UNLANG_TYPE_TRANSACTION, //!< transactions for editing lists
76 UNLANG_TYPE_TRY, //!< try / catch blocks
77 UNLANG_TYPE_CATCH, //!< catch a previous try
78 UNLANG_TYPE_FINALLY, //!< run at the end of a virtual server.
79 UNLANG_TYPE_POLICY, //!< Policy section.
80 UNLANG_TYPE_XLAT, //!< Represents one level of an xlat expansion.
81 UNLANG_TYPE_TMPL, //!< asynchronously expand a tmpl_t
82 UNLANG_TYPE_EDIT, //!< edit VPs in place. After 20 years!
85
86/** Allows the frame evaluator to signal the interpreter
87 *
88 */
89typedef enum {
90 UNLANG_FRAME_ACTION_POP = 1, //!< Pop the current frame, and check the next one further
91 ///< up in the stack for what to do next.
92 UNLANG_FRAME_ACTION_RETRY, //!< retry the current frame
93 UNLANG_FRAME_ACTION_NEXT, //!< Process the next instruction at this level.
94 UNLANG_FRAME_ACTION_YIELD //!< Temporarily return control back to the caller on the C
95 ///< stack.
97
98#define UNLANG_NEXT_STOP (false)
99#define UNLANG_NEXT_SIBLING (true)
100
101#define UNLANG_DETACHABLE (true)
102#define UNLANG_NORMAL_CHILD (false)
103
104DIAG_OFF(attributes)
105typedef enum CC_HINT(flag_enum) {
106 UNLANG_FRAME_FLAG_NONE = 0x00, //!< No flags.
107 UNLANG_FRAME_FLAG_REPEAT = 0x01, //!< Repeat the frame on the way up the stack.
108 UNLANG_FRAME_FLAG_TOP_FRAME = 0x02, //!< are we the top frame of the stack?
109 ///< If true, causes the interpreter to stop
110 ///< interpreting and return, control then passes
111 ///< to whatever called the interpreter.
112 UNLANG_FRAME_FLAG_YIELDED = 0x04, //!< frame has yielded
113 UNLANG_FRAME_FLAG_UNWIND = 0x08, //!< This frame should be unwound without evaluation.
115DIAG_ON(attributes)
116
117typedef struct unlang_s unlang_t;
119
121FR_DLIST_TYPEDEFS(unlang_list, unlang_list_t, unlang_entry_t)
122
123/** A node in a graph of #unlang_op_t (s) that we execute
124 *
125 * The interpreter acts like a turing machine, with #unlang_t nodes forming the tape
126 * and the #unlang_action_t the instructions.
127 *
128 * This is the parent 'class' for multiple #unlang_t node specialisations.
129 * The #unlang_t struct is listed first in the specialisation so that we can cast between
130 * parent/child classes without knowledge of the layout of the structures.
131 *
132 * The specialisations of the nodes describe additional details of the operation to be performed.
133 */
134struct unlang_s {
135 unlang_t *parent; //!< Previous node.
136 unlang_list_t *list; //!< so we have fewer run-time dereferences
137 unlang_entry_t entry; //!< next / prev entries
138 char const *name; //!< Unknown...
139 char const *debug_name; //!< Printed in log messages when the node is executed.
140 unlang_type_t type; //!< The specialisation of this node.
141 bool closed; //!< whether or not this section is closed to new statements
142 bool add_filename; //!< add the filename when printing in debug mode
143 CONF_ITEM *ci; //!< used to generate this item
144 unsigned int number; //!< unique node number
145 unlang_mod_actions_t actions; //!< Priorities, etc. for the various return codes.
146};
147
149#define unlang_list_foreach(_list_head, _iter) fr_dlist_foreach(unlang_list_dlist_head(_list_head), unlang_t, _iter)
150
151typedef struct {
152 fr_dict_t *dict; //!< our dictionary
153 fr_dict_attr_t const *root; //!< the root of our dictionary
154 int max_attr; //!< 1..N local attributes have been defined
156
157/** Generic representation of a grouping
158 *
159 * Can represent IF statements, maps, update sections etc...
160 */
161typedef struct {
163
165 unlang_list_t children;
166
167 unlang_variable_t *variables; //!< rarely used, so we don't usually need it
169
170/** A naked xlat
171 *
172 * @note These are vestigial and may be removed in future.
173 */
174typedef struct {
176 tmpl_t const *tmpl;
178
179/** Function to call when interpreting a frame
180 *
181 * @param[in,out] p_result Pointer to the current rcode, may be modified by the function.
182 * @param[in] request The current request.
183 * @param[in] frame being executed.
184 *
185 * @return an action for the interpreter to perform.
186 */
188 unlang_stack_frame_t *frame);
189
190/** Function to call if the request was signalled
191 *
192 * This is the instruction specific cancellation function.
193 * This function will usually either call a more specialised cancellation function
194 * set when something like a module yielded, or just cleanup the state of the original
195 * #unlang_process_t.
196 *
197 * @param[in] request The current request.
198 * @param[in] frame being signalled.
199 * @param[in] action We're being signalled with.
200 */
201typedef void (*unlang_signal_t)(request_t *request,
202 unlang_stack_frame_t *frame, fr_signal_t action);
203
204/** Custom callback for dumping information about frame state
205 *
206 * @param[in] request The current request.
207 * @param[in] frame to provide additional information for.
208 */
209typedef void (*unlang_dump_t)(request_t *request, unlang_stack_frame_t *frame);
210
211typedef int (*unlang_thread_instantiate_t)(unlang_t const *instruction, void *thread_inst);
212
213typedef struct {
214 virtual_server_t const *vs; //!< Virtual server we're compiling in the context of.
215 ///< This shouldn't change during the compilation of
216 ///< a single unlang section.
217 char const *section_name1;
218 char const *section_name2;
222
223typedef unlang_t *(*unlang_compile_t)(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci);
224
225#define UNLANG_IGNORE ((unlang_t *) -1)
226
228
230
232
234
236 fr_dict_attr_t const *ref);
237
239
240/*
241 * @todo - These functions should be made private once all of they keywords have been moved to foo(args) syntax.
242 */
243bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict);
244bool pass2_fixup_map(map_t *map, tmpl_rules_t const *rules, fr_dict_attr_t const *parent);
245bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules);
246bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules);
247
248/*
249 * When we switch to a new unlang ctx, we use the new component
250 * name and number, but we use the CURRENT actions.
251 */
252static inline CC_HINT(always_inline)
254{
255#ifndef NDEBUG
256 int i;
257#endif
258
259 *dst = *src;
260
261#ifndef NDEBUG
262 /*
263 * Ensure that none of the actions are RETRY. The actions { ... } section is applied to the
264 * instruction, and not to the unlang_compile_ctx_t
265 */
266 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
267 fr_assert(dst->actions.actions[i] != MOD_ACTION_RETRY);
268 fr_assert(MOD_ACTION_VALID(dst->actions.actions[i]));
269 }
270#endif
271}
272
273
274#ifndef NDEBUG
275static inline CC_HINT(always_inline) int unlang_attr_rules_verify(tmpl_attr_rules_t const *rules)
276{
277 if (!fr_cond_assert_msg(rules->dict_def, "No protocol dictionary set")) return -1;
278 if (!fr_cond_assert_msg(rules->dict_def != fr_dict_internal(), "rules->attr.dict_def must not be the internal dictionary")) return -1;
279 if (!fr_cond_assert_msg(!rules->allow_foreign, "rules->attr.allow_foreign must be false")) return -1;
280
281 return 0;
282}
283
284static inline CC_HINT(always_inline) int unlang_rules_verify(tmpl_rules_t const *rules)
285{
286 if (!fr_cond_assert_msg(!rules->at_runtime, "rules->at_runtime must be false")) return -1;
287 return unlang_attr_rules_verify(&rules->attr);
288}
289
290#define RULES_VERIFY(_rules) do { if (unlang_rules_verify(_rules) < 0) return NULL; } while (0)
291#else
292#define RULES_VERIFY(_rules)
293#endif
294
295DIAG_OFF(attributes)
296typedef enum CC_HINT(flag_enum) {
297 UNLANG_OP_FLAG_NONE = 0x00, //!< No flags.
298 UNLANG_OP_FLAG_DEBUG_BRACES = 0x01, //!< Print debug braces.
299 UNLANG_OP_FLAG_RCODE_SET = 0x02, //!< Set request->rcode to the result of this operation.
300 UNLANG_OP_FLAG_NO_FORCE_UNWIND = 0x04, //!< Must not be cancelled.
301 ///< @Note Slightly confusingly, a cancellation signal
302 ///< can still be delivered to a frame that is not
303 ///< cancellable, but the frame won't be automatically
304 ///< unwound. This lets the frame know that cancellation
305 ///< is desired, but can be ignored.
306 UNLANG_OP_FLAG_BREAK_POINT = 0x08, //!< Break point.
307 UNLANG_OP_FLAG_RETURN_POINT = 0x10, //!< Return point.
308 UNLANG_OP_FLAG_CONTINUE_POINT = 0x20, //!< Continue point.
309
310 UNLANG_OP_FLAG_SINGLE_WORD = 0x1000, //!< the operation is parsed and compiled as a single word
311 UNLANG_OP_FLAG_INTERNAL = 0x2000, //!< it's not a real keyword
312
314DIAG_ON(attributes)
315
316/** An unlang operation
317 *
318 * These are like the opcodes in other interpreters. Each operation, when executed
319 * will return an #unlang_action_t, which determines what the interpreter does next.
320 */
321typedef struct {
322 char const *name; //!< Name of the keyword
323 unlang_type_t type; //!< enum value for the keyword
324
325 unlang_compile_t compile; //!< compile the keyword
326
327 unlang_process_t interpret; //!< Function to interpret the keyword
328
329 unlang_signal_t signal; //!< Function to signal stop / dup / whatever
330
331 unlang_dump_t dump; //!< Dump additional information about the frame state.
332
333 size_t unlang_size; //!< Total length of the unlang_t + specialisation struct.
334 char const *unlang_name; //!< Talloc type name for the unlang_t
335
336 unsigned pool_headers; //!< How much additional space to allocate for chunk headers.
337 size_t pool_len; //!< How much additional space to allocate for chunks
338
339
340 unlang_thread_instantiate_t thread_instantiate; //!< per-thread instantiation function
342 char const *thread_inst_type;
343
344 unlang_op_flag_t flag; //!< Interpreter flags for this operation.
345
346 size_t frame_state_size; //!< size of instance data in the stack frame
347
348 char const *frame_state_type; //!< talloc name of the frame instance data
349
350 size_t frame_state_pool_objects; //!< How many sub-allocations we expect.
351
352 size_t frame_state_pool_size; //!< The total size of the pool to alloc.
354
355typedef struct {
356 unlang_t const *instruction; //!< instruction which we're executing
357 void *thread_inst; //!< thread-specific instance data
358
359 bool use_forced_result; //!< Do we force a result for this module?
360 unlang_result_t forced_result; //!< the result to force
361 fr_timer_t *ev; //!< run on expiry
362
363#ifdef WITH_PERF
364 uint64_t uses; //!< how many packets it has processed
365 uint64_t active; //!< currently active in this instruction
366 uint64_t yielded; //!< currently yielded
367 fr_time_tracking_t tracking; //!< tracking cpu time
368#endif
370
371void *unlang_thread_instance(unlang_t const *instruction);
372
373#ifdef WITH_PERF
378#else
379#define unlang_frame_perf_init(_x)
380#define unlang_frame_perf_yield(_x)
381#define unlang_frame_perf_resume(_x)
382#define unlang_frame_perf_cleanup(_x)
383#endif
384
385unlang_thread_t const *unlang_thread_stats(unlang_t const *instruction) CC_HINT(nonnull);
386
387#define debug_braces(_type) (unlang_ops[_type].flag & UNLANG_OP_FLAG_DEBUG_BRACES)
388
389void unlang_stack_signal(request_t *request, fr_signal_t action, int limit);
390
391typedef struct {
393 int depth; //!< of this retry structure
398
399/** Our interpreter stack, as distinct from the C stack
400 *
401 * We don't call the modules recursively. Instead we iterate over a list of #unlang_t and
402 * and manage the call stack ourselves.
403 *
404 * After looking at various green thread implementations, it was decided that using the existing
405 * unlang interpreter stack was the best way to perform async I/O.
406 *
407 * Each request as an unlang interpreter stack associated with it, which represents its progress
408 * through the server. Because the interpreter stack is distinct from the C stack, we can have
409 * a single system thread with many thousands of pending requests.
410 */
412 unlang_t const *instruction; //!< The unlang node we're evaluating.
413 unlang_t const *next; //!< The next unlang node we will evaluate
414
415 unlang_process_t process; //!< function to call for interpreting this stack frame
416 unlang_signal_t signal; //!< function to call when signalling this stack frame
417
418 /** Stack frame specialisations
419 *
420 * These store extra (mutable) state data, for the immutable (#unlang_t)
421 * instruction. Instructions can't be used to store data because they
422 * might be shared between multiple threads.
423 *
424 * Which stack_entry specialisation to use is determined by the
425 * instruction->type.
426 */
427 void *state;
428
429 unlang_result_t section_result; //!< The aggregate result of executing all siblings
430 ///< in this section. This will be merged with the
431 ///< higher stack frame's rcode when the frame is popped.
432 ///< If the rcode is set to RLM_MODULE_NOT_SET when
433 ///< the frame is popped, then the rcode of the frame
434 ///< does not modify the rcode of the frame above it.
435
436 unlang_result_t scratch_result; //!< The result of executing the current instruction.
437 ///< This will be set to RLM_MODULE_NOT_SET, and
438 ///< MOD_ACTION_NOT_SET when a new instruction is set
439 ///< for the frame. If p_result does not point to this
440 ///< field, the rcode and priority returned will be
441 ///< left as NOT_SET and will be ignored.
442 ///< This values here will persist between yields.
443
444 unlang_result_t *p_result; //!< Where to write the result of executing the current
445 ///< instruction. Will either point to `scratch_result`,
446 ///< OR if the parent does not want its rcode to be updated
447 ///< by a child it pushed for evaluation, it will point to
448 ///< memory in the parent's frame state, so that the parent
449 ///< can manually process the rcode.
450
451 unlang_retry_t *retry; //!< if the frame is being retried.
452
453
454 rindent_t indent; //!< Indent level of the request when the frame was
455 ///< created. This is used to restore the indent
456 ///< level when the stack is being forcefully unwound.
457
458 unlang_frame_flag_t flag; //!< Flags that mark up the frame for various things
459 ///< such as being the point where break, return or
460 ///< continue stop, or for forced unwinding.
461
462 struct { //!< reference to a previous frame
463 uint8_t frame_break; //!< previous "break" frame
464 uint8_t frame_continue; //!< previous "continue" frame
465 uint8_t frame_return; //!< previous "return" frame
466 uint8_t frame_load_balance; //!< previous "load-balance" frame
467 uint8_t frame_call; //!< previous "call" frame
469
470#ifdef WITH_PERF
471 fr_time_tracking_t tracking; //!< track this instance of this instruction
472#endif
473};
474
475/** An unlang stack associated with a request
476 *
477 */
478typedef struct {
479 unlang_interpret_t *intp; //!< Interpreter that the request is currently
480 ///< associated with.
481
482 int depth; //!< Current depth we're executing at.
483 uint8_t unwind; //!< Unwind to this frame if it exists.
484 ///< This is used for break and return.
485 unlang_stack_frame_t frame[UNLANG_STACK_MAX]; //!< The stack...
487
488/** Different operations the interpreter can execute
489 */
490extern unlang_op_t unlang_ops[];
492
493#define MOD_NUM_TYPES (UNLANG_TYPE_XLAT + 1)
494
496extern size_t mod_rcode_table_len;
497
498static inline void repeatable_set(unlang_stack_frame_t *frame) { frame->flag |= UNLANG_FRAME_FLAG_REPEAT; }
500static inline void yielded_set(unlang_stack_frame_t *frame) { frame->flag |= UNLANG_FRAME_FLAG_YIELDED; }
501static inline void unwind_set(unlang_stack_frame_t *frame) { frame->flag |= UNLANG_FRAME_FLAG_UNWIND; }
502
503static inline void repeatable_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_REPEAT; }
504static inline void top_frame_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_TOP_FRAME; }
505static inline void yielded_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_YIELDED; }
506static inline void unwind_clear(unlang_stack_frame_t *frame) { frame->flag &= ~UNLANG_FRAME_FLAG_UNWIND; }
507
508static inline bool is_repeatable(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_REPEAT; }
509static inline bool is_top_frame(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_TOP_FRAME; }
510static inline bool is_yielded(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_YIELDED; }
511static inline bool is_unwinding(unlang_stack_frame_t const *frame) { return frame->flag & UNLANG_FRAME_FLAG_UNWIND; }
512static inline bool is_private_result(unlang_stack_frame_t const *frame) { return !(frame->p_result == &frame->section_result); }
513
514static inline bool _instruction_has_debug_braces(unlang_t const *instruction) { return unlang_ops[instruction->type].flag & UNLANG_OP_FLAG_DEBUG_BRACES; }
516#define has_debug_braces(_thing) \
517 _Generic((_thing), \
518 unlang_t *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
519 unlang_t const *: _instruction_has_debug_braces((unlang_t const *)(_thing)), \
520 unlang_stack_frame_t *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)), \
521 unlang_stack_frame_t const *: _frame_has_debug_braces((unlang_stack_frame_t const *)(_thing)) \
522 )
523static inline bool is_rcode_set(unlang_stack_frame_t const *frame) { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_RCODE_SET; }
524static inline bool is_cancellable(unlang_stack_frame_t const *frame) { return !(unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_NO_FORCE_UNWIND); }
525static inline bool is_break_point(unlang_stack_frame_t const *frame) { return unlang_ops[frame->instruction->type].flag & UNLANG_OP_FLAG_BREAK_POINT; }
528
529/** @name Debug functions
530 *
531 * @{
532 */
533void stack_dump(request_t *request);
535/** @} */
536
537/** Find the first frame with a given flag
538 *
539 * @return
540 * - 0 if no frame has the flag.
541 * - The index of the first frame with the flag.
542 */
544{
545 unsigned int i;
546
547 for (i = stack->depth; i > 0; i--) {
548 unlang_stack_frame_t *frame = &stack->frame[i];
549
550 if (frame->flag & flag) return i;
551 }
552 return 0;
553}
554
555/** Find the first frame with a given flag
556 *
557 * @return
558 * - 0 if no frame has the flag.
559 * - The index of the first frame with the flag.
560 */
562{
564
565#ifndef NDEBUG
566 unlang_stack_frame_t *current = &stack->frame[stack->depth];
567 unsigned int i;
568
569 for (i = stack->depth; i > 0; i--) {
570 frame = &stack->frame[i];
571
572 if (unlang_ops[frame->instruction->type].flag & flag) {
573 switch (flag) {
574 default:
575 fr_assert(0);
576 break;
577
579 fr_assert(frame->prev.frame_break == i);
580 fr_assert(current->prev.frame_break == i);
581 break;
582
584 fr_assert(frame->prev.frame_return == i);
585 fr_assert(current->prev.frame_return == i);
586 break;
587
589 fr_assert(frame->prev.frame_continue == i);
590 fr_assert(current->prev.frame_continue == i);
591 break;
592 }
593
594 return i;
595 }
596
597 /*
598 * Do not unwind past a top frame.
599 */
600 if (is_top_frame(frame)) return 0;
601 }
602#else
603 frame = &stack->frame[stack->depth];
604
605 /*
606 * No asserts in NDEBUG mode. Just return the frame, and stop looping up the stack.
607 */
608 switch (flag) {
609 default:
610 break;
611
613 return frame->prev.frame_break;
614
616 return frame->prev.frame_return;
617
619 return frame->prev.frame_continue;
620 }
621#endif
622
623 return 0;
624}
625
626/** Mark up frames as cancelled so they're immediately popped by the interpreter
627 *
628 * @note We used to do this asynchronously, but now we may need to execute timeout sections
629 * which means it's not enough to pop and cleanup the stack, we need continue executing
630 * the request.
631 *
632 * @param[in] stack The current stack.
633 * @param[in] to_depth mark all frames up to and including this depth as cancelled.
634 */
635static inline unlang_action_t unwind_to_depth(unlang_stack_t *stack, unsigned int to_depth)
636{
638 unsigned int i, depth = stack->depth;
639
640 if (!fr_cond_assert(to_depth >= 1)) return UNLANG_ACTION_FAIL;
641
642 for (i = depth; i >= to_depth; i--) {
643 frame = &stack->frame[i];
644 if (!is_cancellable(frame)) continue;
645 unwind_set(frame);
646 }
647
649}
650
651/** Mark the entire stack as cancelled
652 *
653 * This cancels all frames up to the next "break" frame.
654 *
655 * @param[out] depth_p Depth of the break || return || continue point.
656 * @param[in] stack The current stack.
657 * @param[in] flag Flag to search for. One of:
658 * - UNLANG_OP_FLAG_BREAK_POINT
659 * - UNLANG_OP_FLAG_RETURN_POINT
660 * - UNLANG_OP_FLAG_CONTINUE_POINT
661 * @return UNLANG_ACTION_CALCULATE_RESULT
662 */
663static inline unlang_action_t unwind_to_op_flag(unsigned int *depth_p, unlang_stack_t *stack, unlang_op_flag_t flag)
664{
665 unsigned int depth;
666
668 if (depth == 0) {
669 if (depth_p) *depth_p = stack->depth + 1; /* Don't cancel any frames! */
671 }
672
673 unwind_to_depth(stack, depth + 1); /* cancel UP TO the break point */
674
675 if (depth_p) *depth_p = depth;
676
678}
679
681{
682 unlang_stack_t *stack = request->stack;
683
684 return &stack->frame[stack->depth];
685}
686
687static inline int stack_depth_current(request_t *request)
688{
689 unlang_stack_t *stack = request->stack;
690
691 return stack->depth;
692}
693
694/** Initialise memory and instruction for a frame when a new instruction is to be evaluated
695 *
696 * @note We don't change frame->p_result here, we only reset the scratch values. This is because
697 * Whatever pushed the frame onto the stack generally wants the aggregate result of
698 * the complete section, not just the first instruction.
699 *
700 * @param[in] stack the current request stack.
701 * @param[in] frame frame to initialise
702 */
704{
705 unlang_t const *instruction = frame->instruction;
706 unlang_op_t *op;
707 char const *name;
708
710
711 op = &unlang_ops[instruction->type];
712 name = op->frame_state_type ? op->frame_state_type : __location__;
713
714 /*
715 * Reset for each instruction
716 */
718
719 frame->process = op->interpret;
720 frame->signal = op->signal;
721
722#ifdef HAVE_TALLOC_ZERO_POOLED_OBJECT
723 /*
724 * Pooled object
725 */
727 MEM(frame->state = _talloc_zero_pooled_object(stack,
731 } else
732#endif
733 /*
734 * Pool
735 */
736 if (op->frame_state_pool_size && !op->frame_state_size) {
737 MEM(frame->state = talloc_pool(stack,
739 ((20 + 68 + 15) * op->frame_state_pool_objects))); /* from samba talloc.c */
740 talloc_set_name_const(frame->state, name);
741 /*
742 * Object
743 */
744 } else if (op->frame_state_size) {
745 MEM(frame->state = _talloc_zero(stack, op->frame_state_size, name));
746 }
747
748 /*
749 * Don't change frame->retry, it may be left over from a previous retry.
750 */
751
752 /*
753 * Normal frames get their "prev" pointers copied from the previous frame, and then get the break
754 * / continue / etc. point update, if the current instruction warrants it.
755 */
756 if (!is_top_frame(frame)) {
757 /*
758 * A sub-frame / xlat can be the first item pushed on a stack. In that case, stack frame 0 is all zeros.
759 */
760 fr_assert(stack->depth >= 1);
761 frame->prev = (frame - 1)->prev;
762
763 if (unlang_ops[frame->instruction->type].flag) {
764 /*
765 * TBD: A return point should (or should not?) erase any previous frame settings.
766 */
768 frame->prev.frame_return = stack->depth;
769 }
770
772 frame->prev.frame_break = stack->depth;
773 }
774
776 frame->prev.frame_continue = stack->depth;
777 }
778
779 if ((frame->instruction->type == UNLANG_TYPE_LOAD_BALANCE) ||
781 frame->prev.frame_load_balance = stack->depth;
782 }
783 }
784 } else {
785 /*
786 * TBD: Top frames are also return points?
787 */
788 frame->prev.frame_return = stack->depth;
789 }
790}
791
792/** Cleanup any lingering frame state
793 *
794 */
795static inline void frame_cleanup(unlang_stack_frame_t *frame)
796{
798
799 /*
800 * Don't clear top_frame flag, bad things happen...
801 */
803 TALLOC_FREE(frame->retry);
804 if (frame->state) {
805 talloc_free_children(frame->state); /* *(ev->parent) = NULL in event.c */
806 TALLOC_FREE(frame->state);
807 }
808}
809
810/** Advance to the next sibling instruction
811 *
812 */
814{
815 frame_cleanup(frame);
816 frame->instruction = frame->next;
817
818 if (!frame->instruction) return; /* No siblings, need to pop instead */
819
820 frame->next = unlang_list_next(frame->instruction->list, frame->instruction);
821
822 /*
823 * We _may_ want to take a new frame->p_result value in future but
824 * for now default to the scratch result. Generally the thing
825 * advancing the frame is within this library, and doesn't
826 * need custom behaviour for rcodes.
827 */
828 frame_state_init(stack, frame);
829}
830
831/** Pop a stack frame, removing any associated dynamically allocated state
832 *
833 * @param[in] request The current request.
834 * @param[in] stack frame to pop.
835 */
836static inline void frame_pop(request_t *request, unlang_stack_t *stack)
837{
839
840 fr_assert(stack->depth >= 1);
841
842 frame = &stack->frame[stack->depth];
843
844 /*
845 * Signal the frame to get it back into a consistent state
846 * as we won't be calling the resume function.
847 *
848 * If the frame was cancelled, the signal function will
849 * have already been called.
850 */
851 if (!is_unwinding(frame) && is_repeatable(frame)) {
852 if (frame->signal) frame->signal(request, frame, FR_SIGNAL_CANCEL);
853 repeatable_clear(frame);
854 }
855
856 /*
857 * We clean up the retries when we pop the frame, not
858 * when we do a frame_cleanup(). That's because
859 * frame_cleanup() is called from the signal handler, and
860 * we need to keep frame->retry around to ensure that we
861 * know how to _stop_ the retries after they've hit a timeout.
862 */
863 TALLOC_FREE(frame->retry);
864
865 /*
866 * Ensure log indent is at the same level as it was when
867 * the frame was pushed. This is important when we're
868 * unwinding the stack and forcefully cancelling calls.
869 */
870 request->log.indent = frame->indent;
871
872 frame_cleanup(frame);
873
874 stack->depth--;
875}
876
877/** Mark the current stack frame up for repeat, and set a new process function
878 *
879 */
880static inline void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
881{
882 repeatable_set(frame);
883 frame->process = process;
884}
885
887{
888 /*
889 * We're skipping the remaining siblings, stop the
890 * interpreter from continuing and have it pop
891 * this frame, running cleanups normally.
892 *
893 * We don't explicitly cleanup here, otherwise we
894 * end up doing it twice and bad things happen.
895 */
896 if (!unlang) {
897 frame->next = NULL;
899 }
900
901 /*
902 * Clean up this frame now, so that stats, etc. will be
903 * processed using the correct frame.
904 */
905 frame_cleanup(frame);
906
907 /*
908 * frame_next() will call cleanup *before* resetting the frame->instruction.
909 * but since the instruction is NULL, no duplicate cleanups will happen.
910 *
911 * frame_next() will then set frame->instruction = frame->next, and everything will be OK.
912 */
913 frame->instruction = NULL;
914 frame->next = unlang;
916}
917
918/** @name Conversion functions for converting #unlang_t to its specialisations
919 *
920 * Simple conversions: #unlang_module_t and #unlang_group_t are subclasses of #unlang_t,
921 * so we often want to go back and forth between them.
922 *
923 * @{
924 */
926{
928
929 return UNCONST(unlang_group_t *, p);
930}
931
933{
934 return UNCONST(unlang_t *, p);
935}
936
937static inline CC_HINT(always_inline) unlang_list_t *unlang_list(unlang_t *unlang)
938{
939 return &unlang_generic_to_group(unlang)->children;
940}
941
942static inline CC_HINT(always_inline) void unlang_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
943{
944 unlang->type = type;
945 unlang->parent = parent;
946 if (parent) unlang->list = unlang_list(parent);
947 unlang_list_entry_init(unlang);
948}
949
950static inline CC_HINT(always_inline) void unlang_group_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
951{
952 unlang_type_init(unlang, parent, type);
953 unlang_list_init(&((unlang_group_t *) unlang)->children);
954}
955
961
963{
964 return UNCONST(unlang_t *, p);
965}
966/** @} */
967
968/** @name Internal interpreter functions needed by ops
969 *
970 * @{
971 */
972int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction,
973 unlang_frame_conf_t const *conf, bool do_next_sibling)
974 CC_HINT(warn_unused_result);
975
977 rlm_rcode_t default_rcode, bool do_next_sibling)
978 CC_HINT(warn_unused_result);
979
981
982void unlang_op_free(void);
983
984/** @} */
985
986/** @name io shims
987 *
988 * Functions to simulate a 'proto' module when we're running 'fake'
989 * requests. i.e. those created by parallel and subrequest.
990 *
991 * @{
992 */
993request_t *unlang_io_subrequest_alloc(request_t *parent, fr_dict_t const *namespace, bool detachable);
994
995/** @} */
996
997/** @name op init functions
998 *
999 * Functions to trigger registration of the various unlang ops.
1000 *
1001 * @{
1002 */
1003void unlang_register(unlang_op_t *op) CC_HINT(nonnull);
1004
1005void unlang_call_init(void);
1006
1007void unlang_caller_init(void);
1008
1009void unlang_condition_init(void);
1010
1011void unlang_finally_init(void);
1012
1013void unlang_foreach_init(void);
1014
1015void unlang_function_init(void);
1016
1017void unlang_group_init(void);
1018
1019void unlang_load_balance_init(void);
1020
1021void unlang_map_init(void);
1022
1023void unlang_module_init(void);
1024
1025void unlang_return_init(void);
1026
1027void unlang_parallel_init(void);
1028
1030
1031void unlang_detach_init(void);
1032
1033void unlang_switch_init(void);
1034
1035void unlang_tmpl_init(void);
1036
1037void unlang_edit_init(void);
1038
1039void unlang_timeout_init(void);
1040
1041void unlang_transaction_init(void);
1042
1043void unlang_limit_init(void);
1044
1045void unlang_try_init(void);
1046
1047void unlang_catch_init(void);
1048
1049 /** @} */
1050
1051#ifdef __cplusplus
1052}
1053#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:186
#define DIAG_ON(_x)
Definition build.h:535
#define UNUSED
Definition build.h:384
#define DIAG_OFF(_x)
Definition build.h:534
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:172
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:189
#define MEM(x)
Definition debug.h:38
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4926
#define FR_DLIST_TYPES(_name)
Define type specific wrapper structs for dlists.
Definition dlist.h:1146
#define FR_DLIST_FUNCS(_name, _element_type, _element_entry)
Define type specific wrapper functions for dlists.
Definition dlist.h:1169
#define FR_DLIST_TYPEDEFS(_name, _head, _entry)
Define friendly names for type specific dlist head and entry structures.
Definition dlist.h:1156
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:40
#define UNLANG_RESULT_NOT_SET
Definition interpret.h:145
Configuration structure to make it easier to pass configuration options to initialise the frame with.
Definition interpret.h:150
static TALLOC_CTX * unlang_ctx
Definition base.c:71
static char * stack[MAX_STACK]
Definition radmin.c:158
fr_type_t
unsigned int uint32_t
unsigned char uint8_t
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
@ MOD_ACTION_RETRY
retry the instruction, MUST also set a retry config
Definition mod_action.h:39
#define MOD_ACTION_VALID(_x)
Definition mod_action.h:65
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:69
#define fr_assert(_expr)
Definition rad_assert.h:37
static rs_t * conf
Definition radsniff.c:52
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:57
static char const * name
bool at_runtime
Produce an ephemeral/runtime tmpl.
Definition tmpl.h:348
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:339
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:336
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
Value pair map.
Definition map.h:77
Define entry and head types for tmpl request references.
Definition tmpl.h:272
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:273
unsigned int allow_foreign
Allow arguments not found in dict_def.
Definition tmpl.h:314
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:117
A timer event.
Definition timer.c:83
fr_retry_state_t state
#define unlang_frame_perf_resume(_x)
void stack_dump_with_actions(request_t *request)
Definition interpret.c:595
unlang_result_t section_result
The aggregate result of executing all siblings in this section.
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.
static unlang_action_t frame_set_next(unlang_stack_frame_t *frame, unlang_t const *unlang)
unlang_t * unlang_compile_children(unlang_group_t *g, unlang_compile_ctx_t *unlang_ctx)
Definition compile.c:1285
size_t frame_state_pool_objects
How many sub-allocations we expect.
static void frame_pop(request_t *request, unlang_stack_t *stack)
Pop a stack frame, removing any associated dynamically allocated state.
static void frame_next(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Advance to the next sibling instruction.
unlang_frame_flag_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:544
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.
unlang_t * unlang_compile_section(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:1518
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
unlang_result_t * p_result
Where to write the result of executing the current instruction.
static void repeatable_clear(unlang_stack_frame_t *frame)
static unlang_action_t unwind_to_depth(unlang_stack_t *stack, unsigned int to_depth)
Mark up frames as cancelled so they're immediately popped by the interpreter.
bool pass2_fixup_map_rhs(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:206
unlang_retry_t * retry
if the frame is being retried.
void unlang_finally_init(void)
Definition finally.c:169
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.
unlang_mod_actions_t actions
char const * frame_state_type
talloc name of the frame instance data
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.
virtual_server_t const * vs
Virtual server we're compiling in the context of.
tmpl_rules_t const * rules
bool pass2_fixup_tmpl(UNUSED TALLOC_CTX *ctx, tmpl_t **vpt_p, CONF_ITEM const *ci, fr_dict_t const *dict)
Definition compile.c:87
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:222
bool unlang_compile_limit_subsection(CONF_SECTION *cs, char const *name)
Definition compile.c:1596
static void unlang_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
unlang_signal_t signal
Function to signal stop / dup / whatever.
int unlang_subrequest_op_init(void)
Initialise subrequest ops.
Definition subrequest.c:813
size_t frame_state_size
size of instance data in the stack frame
static void unwind_set(unlang_stack_frame_t *frame)
unlang_t *(* unlang_compile_t)(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_ITEM const *ci)
char const * thread_inst_type
fr_dict_attr_t const * root
the root of our dictionary
int(* unlang_thread_instantiate_t)(unlang_t const *instruction, void *thread_inst)
void unlang_timeout_init(void)
Definition timeout.c:282
size_t pool_len
How much additional space to allocate for chunks.
static void frame_state_init(unlang_stack_t *stack, unlang_stack_frame_t *frame)
Initialise memory and instruction for a frame when a new instruction is to be evaluated.
static void unlang_compile_ctx_copy(unlang_compile_ctx_t *dst, unlang_compile_ctx_t const *src)
#define unlang_frame_perf_init(_x)
unlang_t * unlang_compile_empty(unlang_t *parent, unlang_compile_ctx_t *unlang_ctx, CONF_SECTION *cs, unlang_type_t type)
void unlang_edit_init(void)
Definition edit.c:1813
void stack_dump(request_t *request)
Definition interpret.c:590
void unlang_tmpl_init(void)
Definition tmpl.c:366
void unlang_call_init(void)
Definition call.c:338
void unlang_map_init(void)
Definition map.c:438
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:278
rindent_t indent
Indent level of the request when the frame was created.
uint8_t unwind
Unwind to this frame if it exists.
struct unlang_stack_frame_s::@122 prev
static void top_frame_clear(unlang_stack_frame_t *frame)
fr_timer_t * ev
unlang_process_t interpret
Function to interpret the keyword.
unlang_result_t scratch_result
The result of executing the current instruction.
unlang_t self
int depth
of this retry structure
char const * unlang_name
Talloc type name for the unlang_t.
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:49
size_t unlang_size
Total length of the unlang_t + specialisation struct.
char const * section_name1
size_t mod_rcode_table_len
Definition compile.c:80
void unlang_parallel_init(void)
Definition parallel.c:457
static unlang_stack_frame_t * frame_current(request_t *request)
unlang_list_t children
void unlang_transaction_init(void)
fr_timer_t * ev
run on expiry
static bool is_private_result(unlang_stack_frame_t const *frame)
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
bool use_forced_result
Do we force a result for this module?
static int stack_depth_current(request_t *request)
static bool is_break_point(unlang_stack_frame_t const *frame)
unlang_thread_t const * unlang_thread_stats(unlang_t const *instruction)
Definition interpret.c:61
static void unwind_clear(unlang_stack_frame_t *frame)
void unlang_return_init(void)
Definition return.c:68
void unlang_detach_init(void)
Initialise subrequest ops.
Definition detach.c:82
unlang_type_t
Types of unlang_t nodes.
Definition unlang_priv.h:47
@ UNLANG_TYPE_SWITCH
Switch section.
Definition unlang_priv.h:59
@ UNLANG_TYPE_TRANSACTION
transactions for editing lists
Definition unlang_priv.h:75
@ UNLANG_TYPE_FINALLY
run at the end of a virtual server.
Definition unlang_priv.h:78
@ UNLANG_TYPE_SUBREQUEST
create a child subrequest
Definition unlang_priv.h:67
@ UNLANG_TYPE_CONTINUE
Break statement (within a UNLANG_TYPE_FOREACH).
Definition unlang_priv.h:63
@ UNLANG_TYPE_ELSIF
!Condition && Condition.
Definition unlang_priv.h:58
@ UNLANG_TYPE_ELSE
!Condition.
Definition unlang_priv.h:57
@ UNLANG_TYPE_LOAD_BALANCE
Load balance section.
Definition unlang_priv.h:53
@ UNLANG_TYPE_DETACH
detach a child
Definition unlang_priv.h:70
@ UNLANG_TYPE_GROUP
Grouping section.
Definition unlang_priv.h:51
@ UNLANG_TYPE_POLICY
Policy section.
Definition unlang_priv.h:79
@ UNLANG_TYPE_TMPL
asynchronously expand a tmpl_t
Definition unlang_priv.h:81
@ UNLANG_TYPE_CASE
Case section (within a UNLANG_TYPE_SWITCH).
Definition unlang_priv.h:60
@ UNLANG_TYPE_LIMIT
limit number of requests in a section
Definition unlang_priv.h:74
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH or UNLANG_TYPE_CASE).
Definition unlang_priv.h:62
@ UNLANG_TYPE_TRY
try / catch blocks
Definition unlang_priv.h:76
@ UNLANG_TYPE_CALL
call another virtual server
Definition unlang_priv.h:71
@ UNLANG_TYPE_RETURN
Return statement.
Definition unlang_priv.h:64
@ UNLANG_TYPE_REDUNDANT
exactly like group, but with different default return codes
Definition unlang_priv.h:52
@ UNLANG_TYPE_MAX
Definition unlang_priv.h:83
@ UNLANG_TYPE_IF
Condition.
Definition unlang_priv.h:56
@ UNLANG_TYPE_XLAT
Represents one level of an xlat expansion.
Definition unlang_priv.h:80
@ UNLANG_TYPE_NULL
unlang type not set.
Definition unlang_priv.h:48
@ UNLANG_TYPE_MAP
Mapping section (like #UNLANG_TYPE_UPDATE, but uses values from a map_proc_t call).
Definition unlang_priv.h:65
@ UNLANG_TYPE_CALLER
conditionally check parent dictionary type
Definition unlang_priv.h:72
@ UNLANG_TYPE_TIMEOUT
time-based timeouts.
Definition unlang_priv.h:73
@ UNLANG_TYPE_MODULE
Module method.
Definition unlang_priv.h:49
@ UNLANG_TYPE_REDUNDANT_LOAD_BALANCE
Redundant load balance section.
Definition unlang_priv.h:54
@ 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:68
@ UNLANG_TYPE_CATCH
catch a previous try
Definition unlang_priv.h:77
@ UNLANG_TYPE_FUNCTION
Internal call to a function or submodule.
Definition unlang_priv.h:50
@ UNLANG_TYPE_EDIT
edit VPs in place. After 20 years!
Definition unlang_priv.h:82
@ UNLANG_TYPE_FOREACH
Foreach section.
Definition unlang_priv.h:61
@ UNLANG_TYPE_PARALLEL
execute statements in parallel
Definition unlang_priv.h:55
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 unlang_list_t * unlang_list(unlang_t *unlang)
unsigned pool_headers
How much additional space to allocate for chunk headers.
static bool is_rcode_set(unlang_stack_frame_t const *frame)
void unlang_try_init(void)
Definition try.c:256
static bool is_yielded(unlang_stack_frame_t const *frame)
fr_hash_table_t * unlang_op_table
Definition base.c:45
void unlang_catch_init(void)
Definition catch.c:131
size_t frame_state_pool_size
The total size of the pool to alloc.
unlang_compile_t compile
compile the keyword
static void top_frame_set(unlang_stack_frame_t *frame)
unlang_variable_t * variables
rarely used, so we don't usually need it
unlang_type_t type
enum value for the keyword
unlang_group_t * unlang_group_allocate(unlang_t *parent, CONF_SECTION *cs, unlang_type_t type)
Definition compile.c:451
int unlang_interpret_push(unlang_result_t *p_result, request_t *request, unlang_t const *instruction, unlang_frame_conf_t const *conf, bool do_next_sibling)
Push a new frame onto the stack.
Definition interpret.c:622
static unlang_tmpl_t * unlang_generic_to_tmpl(unlang_t const *p)
void unlang_module_init(void)
Definition module.c:979
unlang_t const * instruction
instruction which we're executing
bool add_filename
add the filename when printing in debug mode
bool pass2_fixup_map(map_t *map, tmpl_rules_t const *rules, fr_dict_attr_t const *parent)
Fixup ONE map (recursively)
Definition compile.c:115
char const * name
Name of the keyword.
unlang_frame_action_t
Allows the frame evaluator to signal the interpreter.
Definition unlang_priv.h:89
@ UNLANG_FRAME_ACTION_POP
Pop the current frame, and check the next one further up in the stack for what to do next.
Definition unlang_priv.h:90
@ UNLANG_FRAME_ACTION_YIELD
Temporarily return control back to the caller on the C stack.
Definition unlang_priv.h:94
@ UNLANG_FRAME_ACTION_NEXT
Process the next instruction at this level.
Definition unlang_priv.h:93
@ UNLANG_FRAME_ACTION_RETRY
retry the current frame
Definition unlang_priv.h:92
static void yielded_set(unlang_stack_frame_t *frame)
static bool is_continue_point(unlang_stack_frame_t const *frame)
bool pass2_fixup_update(unlang_group_t *g, tmpl_rules_t const *rules)
Definition compile.c:179
void unlang_function_init(void)
Definition function.c:549
static void yielded_clear(unlang_stack_frame_t *frame)
#define unlang_frame_perf_yield(_x)
#define unlang_frame_perf_cleanup(_x)
unlang_t const * next
The next unlang node we will evaluate.
unlang_result_t forced_result
the result to force
unlang_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:67
unlang_entry_t entry
next / prev entries
int max_attr
1..N local attributes have been defined
static int unlang_attr_rules_verify(tmpl_attr_rules_t const *rules)
unlang_thread_instantiate_t thread_instantiate
per-thread instantiation function
fr_dict_t * dict
our dictionary
static void unlang_group_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
void unlang_stack_signal(request_t *request, fr_signal_t action, int limit)
Delivers a frame to one or more frames in the stack.
Definition interpret.c:1724
void * unlang_thread_instance(unlang_t const *instruction)
Get the thread-instance data for an instruction.
Definition interpret.c:116
static 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_NO_FORCE_UNWIND
Must not be cancelled.
@ UNLANG_OP_FLAG_SINGLE_WORD
the operation is parsed and compiled as a single word
@ 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_INTERNAL
it's not a real keyword
@ UNLANG_OP_FLAG_BREAK_POINT
Break point.
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_action_t(* unlang_process_t)(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Function to call when interpreting a frame.
void unlang_foreach_init(void)
Definition foreach.c:848
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:56
void unlang_caller_init(void)
Definition caller.c:142
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
unlang_frame_flag_t flag
Flags that mark up the frame for various things such as being the point where break,...
char const * section_name2
unlang_action_t unlang_interpret_push_children(unlang_result_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
Push the children of the current frame onto a new frame onto the stack.
Definition interpret.c:726
int unlang_define_local_variable(CONF_ITEM *ci, unlang_variable_t *var, tmpl_rules_t *t_rules, fr_type_t type, char const *name, fr_dict_attr_t const *ref)
Definition compile.c:1900
size_t thread_inst_size
unlang_op_flag_t flag
Interpreter flags for this operation.
int unlang_op_init(void)
unlang_list_t * list
so we have fewer run-time dereferences
static bool is_unwinding(unlang_stack_frame_t const *frame)
void * thread_inst
thread-specific instance data
static int unlang_rules_verify(tmpl_rules_t const *rules)
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:858
fr_retry_state_t
Definition retry.h:45
int nonnull(2, 5))