The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
module.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 22e706f2bd82a8a8638ce93bbccf9f5be2fe1280 $
19 *
20 * @file unlang/module.c
21 * @brief Defines functions for calling modules asynchronously
22 *
23 * @copyright 2018 The FreeRADIUS server project
24 * @copyright 2018 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 */
26RCSID("$Id: 22e706f2bd82a8a8638ce93bbccf9f5be2fe1280 $")
27
28#include <freeradius-devel/server/modpriv.h>
29#include <freeradius-devel/server/request_data.h>
30
31#include "module_priv.h"
32
33#include "tmpl.h"
34
37
38/** Push a module or submodule onto the stack for evaluation
39 *
40 * @param[out] p_result Where to write the result of calling the module.
41 * @param[in] request The current request.
42 * @param[in] mi Instance of the module to call.
43 * @param[in] method to call.
44 * @param[in] top_frame Set to UNLANG_TOP_FRAME if the interpreter should return.
45 * Set to UNLANG_SUB_FRAME if the interprer should continue.
46 * @return
47 * - 0 on success.
48 * - -1 on failure.
49 */
51 module_instance_t *mi, module_method_t method, bool top_frame)
52{
53 unlang_stack_t *stack = request->stack;
57
58 /*
59 * We need to have a unlang_module_t to push on the
60 * stack. The only sane way to do it is to attach it to
61 * the frame state.
62 */
63 MEM(mc = talloc(stack, unlang_module_t)); /* Still gets allocated from the stack pool */
64 *mc = (unlang_module_t){
65 .self = {
67 .name = mi->name,
68 .debug_name = mi->name,
70 },
71 .mmc = {
72 .mi = mi,
73 .mmb = {
74 .method = method
75 }
76 }
77 };
79
80 /*
81 * Push a new module frame onto the stack
82 */
83 if (unlang_interpret_push(p_result, request, unlang_module_to_generic(mc),
85 return -1;
86 }
87
88 frame = &stack->frame[stack->depth];
89 state = frame->state;
92 };
93
94 /*
95 * Bind the temporary unlang_module_t to the frame state.
96 *
97 * There aren't _that_ many children in the stack context.
98 * so we should be ok.
99 *
100 * Hopefully in future versions of talloc the O(n) problem
101 * will be fixed for stealing.
102 */
103 talloc_steal(state, mc);
104
105 return 0;
106}
107
108/** Change the resume function of a module.
109 *
110 * @param[in] request The current request.
111 * @param[in] resume function to call when the XLAT expansion is complete.
112 * @return
113 * - <0 on error
114 * - 0 on success
115 */
117{
118 unlang_stack_t *stack = request->stack;
119 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
121
122 /*
123 * Can't resume if it isn't yielded.
124 */
125 if (!is_yielded(frame)) return -1;
126
127 /*
128 * It must be yielded in a module.
129 */
130 if (frame->instruction->type != UNLANG_TYPE_MODULE) return -1;
131
132 state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
133 state->resume = resume;
134
135 return 0;
136}
137
138/** Push a pre-compiled xlat and resumption state onto the stack for evaluation
139 *
140 * In order to use the async unlang processor the calling module needs to establish
141 * a resumption point, as the call to an xlat function may require yielding control
142 * back to the interpreter.
143 *
144 * To simplify the calling conventions, this function is provided to first push a
145 * resumption stack frame for the module, and then push an xlat stack frame.
146 *
147 * After pushing those frames the function updates the stack pointer to jump over
148 * the resumption frame and execute the xlat interpreter.
149 *
150 * When the xlat interpreter finishes, and pops the xlat frame, the unlang interpreter
151 * will then call the module resumption frame, allowing the module to continue execution.
152 *
153 * @param[in] ctx To allocate talloc value boxes and values in.
154 * @param[out] p_result Whether xlat evaluation was successful.
155 * @param[out] out Where to write the result of the expansion.
156 * @param[in] request The current request.
157 * @param[in] exp XLAT expansion to evaluate.
158 * @param[in] resume function to call when the XLAT expansion is complete.
159 * @param[in] signal function to call if a signal is received.
160 * @param[in] sigmask Set of signals to block. For example if we wanted to only allow
161 * FR_SIGNAL_CANCEL, we'd pass ~FR_SIGNAL_CANCEL to block the other
162 * signals.
163 * @param[in] rctx to pass to the resume() and signal() callbacks.
164 * @return
165 * - UNLANG_ACTION_PUSHED_CHILD
166 */
167unlang_action_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out,
168 request_t *request, xlat_exp_head_t const *exp,
169 module_method_t resume,
170 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
171{
172 /*
173 * Push the resumption point BEFORE pushing the xlat onto
174 * the parents stack.
175 */
176 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
177
178 /*
179 * Push the xlat function
180 */
181 if (unlang_xlat_push(ctx, p_result, out, request, exp, false) < 0) return UNLANG_ACTION_STOP_PROCESSING;
182
184}
185
186/** Push a pre-compiled tmpl and resumption state onto the stack for evaluation
187 *
188 * In order to use the async unlang processor the calling module needs to establish
189 * a resumption point, as the call to an xlat function may require yielding control
190 * back to the interpreter.
191 *
192 * To simplify the calling conventions, this function is provided to first push a
193 * resumption stack frame for the module, and then push a tmpl stack frame.
194 *
195 * After pushing those frames the function updates the stack pointer to jump over
196 * the resumption frame and execute the tmpl expansion.
197 *
198 * When the tmpl interpreter finishes, and pops the tmpl frame, the unlang interpreter
199 * will then call the module resumption frame, allowing the module to continue execution.
200 *
201 * @param[in] ctx To allocate talloc value boxes and values in.
202 * @param[out] out Where to write the result of the expansion.
203 * @param[in] request The current request.
204 * @param[in] vpt the tmpl to expand
205 * @param[in] args Arguments which control how to evaluate the various
206 * types of xlats.
207 * @param[in] resume function to call when the XLAT expansion is complete.
208 * @param[in] signal function to call if a signal is received.
209 * @param[in] sigmask Set of signals to block. For example if we wanted to only allow
210 * FR_SIGNAL_CANCEL, we'd pass ~FR_SIGNAL_CANCEL to block the other
211 * signals.
212 * @param[in] rctx to pass to the resume() and signal() callbacks.
213 * @return
214 * - UNLANG_ACTION_PUSHED_CHILD
215 */
216unlang_action_t unlang_module_yield_to_tmpl(TALLOC_CTX *ctx, fr_value_box_list_t *out,
217 request_t *request, tmpl_t const *vpt,
219 module_method_t resume,
220 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
221{
222 /*
223 * Push the resumption point BEFORE pushing the xlat onto
224 * the parents stack.
225 */
226 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
227
228 /*
229 * Push the xlat function
230 */
231 if (unlang_tmpl_push(ctx, NULL, out, request, vpt, args, UNLANG_SUB_FRAME) < 0) return UNLANG_ACTION_FAIL;
232
234}
235
237 request_t *request, CONF_SECTION *subcs,
238 rlm_rcode_t default_rcode,
239 module_method_t resume,
240 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
241{
242 /*
243 * When we yield to a section, the request->rcode
244 * should be set to the default rcode, so that
245 * conditional checks work correctly.
246 */
247 RDEBUG3("Resetting request->rcode to %s", fr_table_str_by_value(rcode_table, default_rcode, "<invalid>"));
248 request->rcode = default_rcode;
249
250 if (!subcs) {
251 unlang_stack_t *stack = request->stack;
252 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
255
258
259 /*
260 * Pretend as if we called the section
261 * and used the default rcode value.
262 */
263 frame->scratch_result = (unlang_result_t) {.rcode = default_rcode, .priority = MOD_ACTION_NOT_SET };
264
265 state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
266
267 /*
268 * We must pass a pointer to the scratch
269 * rcode here, as we're pretending we're
270 * executing the resume function using the
271 * interpreter, which means it must modify
272 * the scratch result for the frame, and
273 * _NOT_ what was passed in for p_result.
274 */
275 return resume(&frame->scratch_result,
277 state->env_data, rctx),
278 request);
279 }
280
281 /*
282 * Push the resumption point BEFORE adding the subsection
283 * to the parents stack.
284 */
285 (void) unlang_module_yield(request, resume, signal, sigmask, rctx);
286
287 if (unlang_interpret_push_section(p_result, request, subcs,
288 FRAME_CONF(default_rcode, UNLANG_SUB_FRAME)) < 0) return UNLANG_ACTION_STOP_PROCESSING;
289
291}
292
293/** Run the retry handler. Called from an async signal handler.
294 *
295 */
297{
298 unlang_stack_t *stack = request->stack;
299 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
300 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
301
302 if (!state->retry_cb) return;
303
304 /*
305 * Assert that we have the right things. Note that this function should only be called when the
306 * retry is being used as an expiry time, i.e. mrc==1. If the module has its own retry handlers,
307 * then this function must not be called.
308 */
309 fr_assert(state->retry.config != NULL);
310 fr_assert(state->retry.config->mrc == 1);
311 fr_assert(state->rctx == mctx->rctx);
312 fr_assert(state->request == request);
313
314 /*
315 * Update the time as to when the retry is being called. This is the main purpose of the
316 * function.
317 */
318 state->retry.updated = fr_time();
319
320 state->retry_cb(mctx, request, &state->retry);
321
322}
323
324/** Cancel the retry timer on resume
325 *
326 */
328{
329 unlang_stack_t *stack = request->stack;
330 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
331 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
332
333 /*
334 * Cancel the timers, and clean up any associated retry configuration.
335 */
336 talloc_const_free(state->ev);
337 state->ev = NULL;
338 state->retry_cb = NULL;
339 state->retry.config = NULL;
340
341 return state->retry_resume(p_result, mctx, request);
342}
343
344/** Yield a request back to the interpreter, with retries
345 *
346 * This passes control of the request back to the unlang interpreter, setting
347 * callbacks to execute when the request is 'signalled' asynchronously, or when
348 * the retry timer hits.
349 *
350 * @note The module function which calls #unlang_module_yield_to_retry should return control
351 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield_to_retry.
352 * A common pattern is to use ``return unlang_module_yield_to_retry(...)``.
353 *
354 * @param[in] request The current request.
355 * @param[in] resume Called on unlang_interpret_mark_runnable().
356 * @param[in] retry Called on when a retry timer hits
357 * @param[in] signal Called on unlang_action().
358 * @param[in] sigmask Set of signals to block. For example if we wanted to only allow
359 * FR_SIGNAL_CANCEL, we'd pass ~FR_SIGNAL_CANCEL to block the other
360 * signals.
361 * @param[in] rctx to pass to the callbacks.
362 * @param[in] retry_cfg to set up the retries
363 * @return
364 * - UNLANG_ACTION_YIELD on success
365 * - UNLANG_ACTION_FAIL on failure
366 */
368 unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx,
369 fr_retry_config_t const *retry_cfg)
370{
371 unlang_stack_t *stack = request->stack;
372 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
374 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
375
376 fr_assert(stack->depth > 0);
379
380 fr_assert(!state->retry_cb);
381
382 state->retry_cb = retry;
383 state->retry_resume = resume; // so that we can cancel the retry timer
384 state->rctx = rctx;
385
386 state->request = request;
387 state->mi = m->mmc.mi;
388
389 /*
390 * Allow unlang statements to override the module configuration. i.e. if we already have a
391 * timer from unlang, then just use that.
392 */
393 if (!state->retry.config) {
394 fr_retry_init(&state->retry, fr_time(), retry_cfg);
395
396 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl, &state->ev,
397 state->retry.next,
398 false, unlang_module_event_retry_handler, request) < 0) {
399 RPEDEBUG("Failed inserting event");
400 return UNLANG_ACTION_FAIL;
401 }
402 }
403
404 return unlang_module_yield(request, unlang_module_retry_resume, signal, sigmask, rctx);
405}
406
407
408/** Yield a request back to the interpreter from within a module
409 *
410 * This passes control of the request back to the unlang interpreter, setting
411 * callbacks to execute when the request is 'signalled' asynchronously, or whatever
412 * timer or I/O event the module was waiting for occurs.
413 *
414 * @note The module function which calls #unlang_module_yield should return control
415 * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield.
416 * A common pattern is to use ``return unlang_module_yield(...)``.
417 *
418 * @param[in] request The current request.
419 * @param[in] resume Called on unlang_interpret_mark_runnable().
420 * @param[in] signal Called on unlang_action().
421 * @param[in] sigmask Set of signals to block. For example if we wanted to only allow
422 * FR_SIGNAL_CANCEL, we'd pass ~FR_SIGNAL_CANCEL to block the other
423 * signals.
424 * @param[in] rctx to pass to the callbacks.
425 * @return
426 * - UNLANG_ACTION_YIELD.
427 * - UNLANG_ACTION_FAIL if this is not a module frame.
428 */
430 module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
431{
432 unlang_stack_t *stack = request->stack;
433 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
435
436 REQUEST_VERIFY(request); /* Check the yielded request is sane */
437
438 if (frame->instruction->type != UNLANG_TYPE_MODULE) {
439 fr_assert_msg(0, "unlang_module_yield called on a non-module frame");
440 return UNLANG_ACTION_FAIL;
441 }
442
443 state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
444
445 state->rctx = rctx;
446 state->resume = resume;
447
448#ifndef NDEBUG
449 /*
450 * We can't do asynchronous signals if the module is not thread safe.
451 *
452 * Right now, none of the modules marked THREAD_UNSAFE call yield, or set signal callbacks.
453 * Which means that this code doesn't affect anything.
454 *
455 * At some point if we do have modules which take signals and which are not thread safe, then
456 * those modules have to ensure that their signal handlers do any locking necessary.
457 */
458 if (signal) {
460
462 fr_assert(m);
463
465 }
466#endif
467
468 state->signal = signal;
469 state->sigmask = sigmask;
470
471 /*
472 * We set the repeatable flag here,
473 * so that the resume function is always
474 * called going back up the stack.
475 */
477
478 return UNLANG_ACTION_YIELD;
479}
480
481/*
482 * Lock the mutex for the module
483 */
484static inline CC_HINT(always_inline) void safe_lock(module_instance_t *mi)
485{
486 if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_lock(&mi->mutex);
487}
488
489/*
490 * Unlock the mutex for the module
491 */
492static inline CC_HINT(always_inline) void safe_unlock(module_instance_t *mi)
493{
494 if ((mi->exported->flags & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_unlock(&mi->mutex);
495}
496
497/** Send a signal (usually stop) to a request
498 *
499 * This is typically called via an "async" action, i.e. an action
500 * outside of the normal processing of the request.
501 *
502 * If there is no #unlang_module_signal_t callback defined, the action is ignored.
503 *
504 * @param[in] request The current request.
505 * @param[in] frame current stack frame.
506 * @param[in] action to signal.
507 */
509{
510 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
512 char const *caller;
513
514 if (!state->signal) return;
515
516 if (action == FR_SIGNAL_CANCEL) {
517 /*
518 * Cancel the retry timer, if it is set.
519 *
520 * Because cancellation functions and actual unwinding are done separately
521 * the retry timer can fire after the module has been cancelled.
522 */
523 TALLOC_FREE(state->ev);
524 }
525
526 /*
527 * Async calls can't push anything onto the unlang stack, so we just use a local "caller" here.
528 */
529 caller = request->module;
530 request->module = m->mmc.mi->name;
531
532 /*
533 * Call the signal routines. Note that signals are
534 * explicitely asynchronous, even if the module has
535 * declared itself to be MODULE_TYPE_THREAD_UNSAFE.
536 */
537 if (!(action & state->sigmask)) state->signal(MODULE_CTX(m->mmc.mi, state->thread->data, state->env_data, state->rctx), request, action);
538
539 if (action == FR_SIGNAL_CANCEL) {
540 /*
541 * One fewer caller for this module. Since this module
542 * has been cancelled, decrement the active callers and
543 * ignore any future signals.
544 */
545 state->thread->active_callers--;
546 state->signal = NULL;
547 }
548
549 request->module = caller;
550
551}
552
553/** Cleanup after a module completes
554 *
555 */
557{
558 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
559
560#ifndef NDEBUG
561 fr_assert(state->unlang_indent == request->log.indent.unlang);
562#endif
563
564 fr_assert(p_result->rcode >= RLM_MODULE_NOT_SET);
566
567 RDEBUG("%s (%s)", frame->instruction->name ? frame->instruction->name : "",
568 fr_table_str_by_value(mod_rcode_table, p_result->rcode, "<invalid>"));
569
570 request->module = state->previous_module;
571
573}
574
575/** Cleanup after a yielded module completes
576 *
577 */
579{
580 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
581
582 state->thread->active_callers--;
583
584 return unlang_module_done(p_result, request, frame);
585}
586
587/** Wrapper to call a module's resumption function
588 *
589 * This is called _after_ the module first yields, and again after any
590 * other yields.
591 */
593{
594 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
596 module_method_t resume;
598
599 fr_assert(state->resume != NULL);
600
601 resume = state->resume;
602
603 /*
604 * The module *MUST* explicitly set the resume
605 * function when yielding or pushing children
606 * if it wants to be called again later.
607 */
608 state->resume = NULL;
609
610 /*
611 * Lock is noop unless instance->mutex is set.
612 */
613 safe_lock(m->mmc.mi);
614 ua = resume(p_result, MODULE_CTX(m->mmc.mi, state->thread->data,
615 state->env_data, state->rctx), request);
616 safe_unlock(m->mmc.mi);
617
618 if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
619
620 switch (ua) {
622 RWARN("Module %s or worker signalled to stop processing request", m->mmc.mi->name);
623 state->thread->active_callers--;
624 request->module = state->previous_module;
625 p_result->rcode = RLM_MODULE_NOT_SET;
626 p_result->priority = MOD_ACTION_NOT_SET;
628
630 /*
631 * The module yielded but didn't set a
632 * resume function, this means it's done
633 * and when the I/O operation completes
634 * it shouldn't be called again.
635 */
636 if (!state->resume) {
638 } else {
639 repeatable_set(frame);
640 }
641 return UNLANG_ACTION_YIELD;
642
643 /*
644 * The module is done (for now).
645 * But, running it pushed one or more asynchronous
646 * calls onto the stack for evaluation.
647 * These need to be run before the module resumes
648 * or the next unlang instruction is processed.
649 */
651 /*
652 * The module pushed a child and didn't
653 * set a resume function, this means
654 * it's done, and we won't call it again
655 * but we still need to do some cleanup
656 * after the child returns.
657 */
658 if (!state->resume) {
660 } else {
661 repeatable_set(frame);
662 }
664
666 /*
667 * Module set a resume function but
668 * didn't yield or push additional
669 * children.
670 *
671 * Evaluate the function now and
672 * use the result as the final result.
673 */
674 if (state->resume) return unlang_module_resume(p_result, request, frame);
675 request->module = state->previous_module;
676 break;
677
679 p_result->rcode = RLM_MODULE_FAIL;
680 request->module = state->previous_module;
681 break;
682
683 /*
684 * Module indicates we shouldn't process its rcode
685 */
687 break;
688 }
689
690 unlang_module_resume_done(p_result, request, frame);
691 request->module = state->previous_module;
692
693 return ua;
694}
695
696/** Call the callback registered for a retry event
697 *
698 * @param[in] tl the event timer was inserted into.
699 * @param[in] now The current time, as held by the event_list.
700 * @param[in] ctx the stack frame
701 *
702 */
704{
705 request_t *request = talloc_get_type_abort(ctx, request_t);
706 unlang_stack_t *stack = request->stack;
707 unlang_stack_frame_t *frame = &stack->frame[stack->depth];
708 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
709
710 switch (fr_retry_next(&state->retry, now)) {
712 if (state->retry_cb) {
713 /*
714 * Call the module retry handler, with the state of the retry. On MRD / MRC, the
715 * module is made runnable again, and the "resume" function is called.
716 */
717 state->retry_cb(MODULE_CTX(state->mi, state->thread, state->env_data, state->rctx), state->request, &state->retry);
718 } else {
719 /*
720 * For signals, the module will get either a RETRY
721 * signal, or a TIMEOUT signal (also for max count).
722 *
723 * The signal handler should generally change the resume
724 * function, and mark the request as runnable. We
725 * probably don't want the module to do tons of work in
726 * the signal handler, as it's called from the event
727 * loop. And doing so could affect the other event
728 * timers.
729 *
730 * Note also that we call frame->signal(), and not
731 * unlang_interpret_signal(). That is because we want to
732 * signal only the module. We know that the other frames
733 * on the stack can't handle this particular signal. So
734 * there's no point in calling them. Or, if sections
735 * have their own retry handlers, then we don't want to
736 * signal those _other_ retry handlers with _our_ signal.
737 */
738 frame->signal(request, frame, FR_SIGNAL_RETRY);
739 }
740
741 /*
742 * Reset the timer.
743 */
744 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl, &state->ev, state->retry.next,
745 false, unlang_module_event_retry_handler, request) < 0) {
746 RPEDEBUG("Failed inserting event");
747 unlang_interpret_mark_runnable(request); /* and let the caller figure out what's up */
748 }
749 return;
750
751 case FR_RETRY_MRD:
752 RDEBUG("Reached max_rtx_duration (%pVs > %pVs) - sending timeout",
754 break;
755
756 case FR_RETRY_MRC:
757 RDEBUG("Reached max_rtx_count %u- sending timeout",
758 state->retry.config->mrc);
759 break;
760 }
761
762 /*
763 * Run the retry handler on MRD / MRC, too.
764 */
765 if (state->retry_cb) {
766 state->retry_cb(MODULE_CTX(state->mi, state->thread, state->env_data, state->rctx), state->request, &state->retry);
767 } else {
768 frame->signal(request, frame, FR_SIGNAL_TIMEOUT);
769 }
770
771 /*
772 * On final timeout, always mark the request as runnable.
773 */
775}
776
778{
780 unlang_frame_state_module_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_module_t);
782 fr_time_t now = fr_time_wrap(0);
783
784 p_result->rcode = RLM_MODULE_NOOP;
785 state->previous_module = request->module;
786
787#ifndef NDEBUG
788 state->unlang_indent = request->log.indent.unlang;
789#endif
790 /*
791 * Process a stand-alone child, and fall through
792 * to dealing with it's parent.
793 */
795 fr_assert(m);
796
797 RDEBUG4("[%i] %s - %s (%s)", stack_depth_current(request), __FUNCTION__,
798 m->mmc.mi->module->exported->name, m->mmc.mi->name);
799
800 /*
801 * Return administratively configured return code
802 */
803 if (m->mmc.mi->force) {
804 p_result->rcode = m->mmc.mi->code;
806 goto done;
807 }
808
809 if (m->mmc.mmb.method_env) {
810 if (!state->env_data) {
811 ua = call_env_expand(state, request, &state->env_result, &state->env_data, m->call_env);
812 switch (ua) {
814 goto fail;
815
819
820 default:
821 break;
822 }
823 }
824
825 /*
826 * Fail the module call on callenv failure
827 */
828 if (state->env_result != CALL_ENV_SUCCESS) return UNLANG_ACTION_FAIL;
829 }
830
831 /*
832 * Grab the thread/module specific data if any exists.
833 */
834 state->thread = module_thread(m->mmc.mi);
835 fr_assert(state->thread != NULL);
836
837 /*
838 * For logging unresponsive children.
839 */
840 state->thread->total_calls++;
841
842 /*
843 * If we're doing retries, remember when we started
844 * running the module.
845 */
847
848 /*
849 * Pre-allocate an rctx for the module, if it has one.
850 */
851 fr_assert_msg(state->rctx == NULL, "rctx should be NULL for initial module call");
852 {
853 size_t size = 0;
854 char const *type;
855
856 /*
857 * Use the module method binding's rctx size in preference
858 * to the one set for the module as a whole.
859 */
860 if (m->mmc.mmb.rctx_size) {
861 size = m->mmc.mmb.rctx_size;
862 type = m->mmc.mmb.rctx_type;
863 /*
864 * Use the rctx from the module_t
865 *
866 * The module is still fine to allocate the rctx itself
867 * in the first module method call.
868 */
869 } else if(m->mmc.mi->exported->rctx_size) {
870 size = m->mmc.mi->exported->rctx_size;
872 }
873
874 if (size > 0) {
875 MEM(state->rctx = talloc_zero_array(state, uint8_t, size));
876 if (!type) {
877 talloc_set_name(state->rctx, "%s_rctx_t", m->mmc.mi->name);
878 } else {
879 talloc_set_name_const(state->rctx, type);
880 }
881 }
882 }
883
884 request->module = m->mmc.mi->name;
885 safe_lock(m->mmc.mi); /* Noop unless instance->mutex set */
886 ua = m->mmc.mmb.method(p_result,
887 MODULE_CTX(m->mmc.mi, state->thread->data, state->env_data, state->rctx),
888 request);
889 safe_unlock(m->mmc.mi);
890
891 if (request->master_state == REQUEST_STOP_PROCESSING) ua = UNLANG_ACTION_STOP_PROCESSING;
892
893 switch (ua) {
894 /*
895 * It is now marked as "stop" when it wasn't before, we
896 * must have been blocked.
897 */
899 RWARN("Module %s became unblocked", m->mmc.mi->name);
900 request->module = state->previous_module;
902
904 state->thread->active_callers++;
905
906 /*
907 * The module yielded but didn't set a
908 * resume function, this means it's done
909 * and when the I/O operation completes
910 * it shouldn't be called again.
911 */
912 if (!state->resume) {
914 } else {
916 }
917
918 /*
919 * If we have retry timers, then start the retries.
920 */
923
924 fr_retry_init(&state->retry, now, &frame->instruction->actions.retry);
925
926 if (fr_timer_at(state, unlang_interpret_event_list(request)->tl,
927 &state->ev, state->retry.next,
928 false, unlang_module_event_retry_handler, request) < 0) {
929 RPEDEBUG("Failed inserting event");
930 goto fail;
931 }
932 }
933
934 return UNLANG_ACTION_YIELD;
935
936 /*
937 * The module is done (for now).
938 * But, running it pushed one or more asynchronous
939 * calls onto the stack for evaluation.
940 * These need to be run before the module resumes
941 * or the next unlang instruction is processed.
942 */
944 /*
945 * The module pushed a child and didn't
946 * set a resume function, this means
947 * it's done, and we won't call it again
948 * but we still need to do some cleanup
949 * after the child returns.
950 */
951 if (!state->resume) {
953 } else {
954 repeatable_set(frame);
955 }
957
959 /*
960 * Module set a resume function but
961 * didn't yield or push additional
962 * children.
963 *
964 * Evaluate the function now and
965 * use the result as the final result.
966 */
967 if (state->resume) {
968 frame->process = unlang_module_resume; /* unlang_module_resume will assume this is set */
969 return unlang_module_resume(p_result, request, frame);
970 }
971 break;
972
974 fail:
975 p_result->rcode = RLM_MODULE_FAIL;
976 break;
977
978 /*
979 * Module indicates we shouldn't process its rcode
980 */
982 break;
983 }
984
985done:
986 request->module = state->previous_module;
987 unlang_module_done(p_result, request, frame);
988 return ua;
989}
990
992{
994 .name = "module",
995 .type = UNLANG_TYPE_MODULE,
996
997 /*
998 * - UNLANG_OP_FLAG_RCODE_SET
999 * Set request->rcode to be the rcode from the module.
1000 * - UNLANG_OP_FLAG_RETURN_POINT
1001 * Set the return point to be the module.
1002 */
1003 .flag = UNLANG_OP_FLAG_RCODE_SET |
1006
1007 .interpret = unlang_module,
1008 .signal = unlang_module_signal,
1009
1010 .unlang_size = sizeof(unlang_module_t),
1011 .unlang_name = "unlang_module_t",
1012
1013 .frame_state_size = sizeof(unlang_frame_state_module_t),
1014 .frame_state_type = "unlang_frame_state_module_t",
1015 });
1016}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
Definition action.h:38
@ UNLANG_ACTION_STOP_PROCESSING
Break out of processing the current request (unwind).
Definition action.h:42
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
va_list args
Definition acutest.h:770
#define RCSID(id)
Definition build.h:485
#define UNUSED
Definition build.h:317
unlang_action_t call_env_expand(TALLOC_CTX *ctx, request_t *request, call_env_result_t *env_result, void **env_data, call_env_t const *call_env)
Initialise the expansion of a call environment.
Definition call_env.c:331
@ CALL_ENV_SUCCESS
Definition call_env.h:52
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
fr_table_num_sorted_t const mod_rcode_table[]
Definition compile.c:75
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:202
#define MEM(x)
Definition debug.h:36
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1612
int unlang_interpret_push_section(unlang_result_t *p_result, request_t *request, CONF_SECTION *cs, unlang_frame_conf_t const *conf)
Push a configuration section onto the request stack for later interpretation.
Definition interpret.c:1159
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:280
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2009
unlang_mod_action_t priority
The priority or action for that rcode.
Definition interpret.h:136
#define FRAME_CONF(_default_rcode, _top_frame)
Definition interpret.h:152
#define UNLANG_SUB_FRAME
Definition interpret.h:37
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:134
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RWARN(fmt,...)
Definition log.h:297
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RDEBUG4(fmt,...)
Definition log.h:344
void unlang_register(unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:56
static char * stack[MAX_STACK]
Definition radmin.c:159
unsigned char uint8_t
@ MOD_ACTION_NOT_SET
default "not set by anything"
Definition mod_action.h:37
fr_retry_config_t retry
Definition mod_action.h:65
#define MOD_ACTIONS_FAIL_TIMEOUT_RETURN
Definition mod_action.h:69
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
#define MODULE_CTX(_mi, _thread, _env_data, _rctx)
Wrapper to create a module_ctx_t as a compound literal.
Definition module_ctx.h:128
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Declarations for the unlang module interface.
fr_timer_t * ev
retry timer just for this module.
Definition module_priv.h:79
static unlang_t * unlang_module_to_generic(unlang_module_t *p)
Definition module_priv.h:92
static unlang_module_t * unlang_generic_to_module(unlang_t const *p)
Definition module_priv.h:86
module_instance_t const * mi
Module instance to pass to callbacks.
Definition module_priv.h:76
module_method_t resume
resumption handler
Definition module_priv.h:64
char const * previous_module
old request->module
Definition module_priv.h:46
fr_signal_t sigmask
Signals to block.
Definition module_priv.h:66
module_method_t retry_resume
which stops retries on resume
Definition module_priv.h:73
call_env_result_t env_result
Result of the previous call environment expansion.
Definition module_priv.h:52
module_method_call_t mmc
Everything needed to call a module method.
Definition module_priv.h:38
fr_retry_t retry
retry timers, etc.
Definition module_priv.h:80
void * env_data
Expanded per call "call environment" tmpls.
Definition module_priv.h:53
module_thread_instance_t * thread
thread-local data for this module.
Definition module_priv.h:47
unlang_t self
Common fields in all unlang_t tree nodes.
Definition module_priv.h:36
unlang_module_signal_t signal
for signal handlers
Definition module_priv.h:65
int unlang_indent
Record what this was when we entered the module.
Definition module_priv.h:56
void * rctx
for resume / signal
Definition module_priv.h:63
call_env_t const * call_env
The per call parsed call environment.
Definition module_priv.h:37
unlang_module_retry_t retry_cb
callback to run on timeout
Definition module_priv.h:74
A module stack entry.
Definition module_priv.h:45
A call to a module method.
Definition module_priv.h:35
module_instance_t * mi
The process modules also push module calls onto the stack for execution.
Definition module_rlm.h:63
module_method_binding_t mmb
Method we're calling.
Definition module_rlm.h:70
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#define RDEBUG(fmt,...)
Definition radclient.h:53
fr_table_num_sorted_t const rcode_table[]
Definition rcode.c:35
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:44
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:41
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:50
@ RLM_MODULE_NUMCODES
How many valid return codes there are.
Definition rcode.h:53
#define REQUEST_VERIFY(_x)
Definition request.h:309
@ REQUEST_STOP_PROCESSING
Request has been signalled to stop.
Definition request.h:88
size_t rctx_size
Size of the module's thread-specific data.
Definition module.h:247
char const * name
Instance name e.g. user_database.
Definition module.h:355
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
Definition module.h:49
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:236
uint64_t active_callers
total number of times we've been called
Definition module.h:379
bool force
Force the module to return a specific code.
Definition module.h:317
unlang_action_t(* module_method_t)(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Module section callback.
Definition module.h:69
char const * rctx_type
talloc type to assign to thread instance data.
Definition module.h:248
module_method_t method
Module method to call.
Definition module.h:177
void * data
Thread specific instance data.
Definition module.h:372
rlm_rcode_t code
Code module will return when 'force' has has been set to true.
Definition module.h:320
call_env_method_t const * method_env
Method specific call_env.
Definition module.h:178
static module_thread_instance_t * module_thread(module_instance_t const *mi)
Retrieve module/thread specific instance for a module.
Definition module.h:501
size_t rctx_size
If set, this overrides the module_t rctx_size.
Definition module.h:180
char const * rctx_type
If rctx_size is used from the mmb, this sets the type of the rctx.
Definition module.h:184
module_t * exported
Public module structure.
Definition module.h:296
pthread_mutex_t mutex
Used prevent multiple threads entering a thread unsafe module simultaneously.
Definition module.h:303
Module instance data.
Definition module.h:285
static fr_slen_t vpt
Definition tmpl.h:1269
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_RETRY
a retry timer has hit
Definition signal.h:46
@ FR_SIGNAL_TIMEOUT
a retry timeout or max count has hit
Definition signal.h:47
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
int unlang_module_set_resume(request_t *request, module_method_t resume)
Change the resume function of a module.
Definition module.c:116
static unlang_action_t unlang_module(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition module.c:777
static void safe_lock(module_instance_t *mi)
Definition module.c:484
static void unlang_module_event_retry_handler(UNUSED fr_timer_list_t *tl, fr_time_t now, void *ctx)
Call the callback registered for a retry event.
Definition module.c:703
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
Definition module.c:429
unlang_action_t unlang_module_yield_to_retry(request_t *request, module_method_t resume, unlang_module_retry_t retry, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx, fr_retry_config_t const *retry_cfg)
Yield a request back to the interpreter, with retries.
Definition module.c:367
void unlang_module_init(void)
Definition module.c:991
static unlang_action_t unlang_module_done(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Cleanup after a module completes.
Definition module.c:556
static unlang_action_t unlang_module_resume(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Wrapper to call a module's resumption function.
Definition module.c:592
void unlang_module_retry_now(module_ctx_t const *mctx, request_t *request)
Run the retry handler.
Definition module.c:296
static unlang_action_t unlang_module_resume_done(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Cleanup after a yielded module completes.
Definition module.c:578
unlang_action_t unlang_module_yield_to_section(unlang_result_t *p_result, request_t *request, CONF_SECTION *subcs, rlm_rcode_t default_rcode, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Definition module.c:236
static unlang_action_t unlang_module_retry_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Cancel the retry timer on resume.
Definition module.c:327
unlang_action_t unlang_module_yield_to_tmpl(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt, unlang_tmpl_args_t *args, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Push a pre-compiled tmpl and resumption state onto the stack for evaluation.
Definition module.c:216
int unlang_module_push(unlang_result_t *p_result, request_t *request, module_instance_t *mi, module_method_t method, bool top_frame)
Push a module or submodule onto the stack for evaluation.
Definition module.c:50
static void safe_unlock(module_instance_t *mi)
Definition module.c:492
unlang_action_t unlang_module_yield_to_xlat(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *exp, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Push a pre-compiled xlat and resumption state onto the stack for evaluation.
Definition module.c:167
static void unlang_module_signal(request_t *request, unlang_stack_frame_t *frame, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition module.c:508
fr_aka_sim_id_type_t type
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:772
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition talloc.h:229
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_gt(_a, _b)
Definition time.h:237
#define fr_time_sub(_a, _b)
Subtract one time from another.
Definition time.h:229
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:50
#define fr_timer_at(...)
Definition timer.h:81
int unlang_tmpl_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args, bool top_frame)
Push a tmpl onto the stack for evaluation.
Definition tmpl.c:276
void(* unlang_module_retry_t)(module_ctx_t const *mctx, request_t *request, fr_retry_t const *retry)
A callback when a retry happens.
Definition module.h:53
void(* unlang_module_signal_t)(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
A callback when the request gets a fr_signal_t.
Definition module.h:81
Functions to allow tmpls to push resumption frames onto the stack and inform the interpreter about th...
Arguments for evaluating different types of tmpls.
Definition tmpl.h:48
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:270
unlang_signal_t signal
function to call when signalling this stack frame
void * state
Stack frame specialisations.
unlang_mod_actions_t actions
Priorities, etc. for the various return codes.
#define UNLANG_NEXT_STOP
Definition unlang_priv.h:99
static void unlang_type_init(unlang_t *unlang, unlang_t *parent, unlang_type_t type)
unlang_result_t scratch_result
The result of executing the current instruction.
char const * name
Unknown...
static int stack_depth_current(request_t *request)
@ UNLANG_TYPE_MODULE
Module method.
Definition unlang_priv.h:49
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_yielded(unlang_stack_frame_t const *frame)
@ UNLANG_OP_FLAG_RETURN_POINT
Return point.
@ UNLANG_OP_FLAG_RCODE_SET
Set request->rcode to the result of this operation.
@ UNLANG_OP_FLAG_INTERNAL
it's not a real keyword
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
An unlang operation.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
fr_retry_state_t fr_retry_next(fr_retry_t *r, fr_time_t now)
Initialize a retransmission counter.
Definition retry.c:108
void fr_retry_init(fr_retry_t *r, fr_time_t now, fr_retry_config_t const *config)
Initialize a retransmission counter.
Definition retry.c:36
fr_time_t start
when we started the retransmission
Definition retry.h:53
fr_time_delta_t irt
Initial transmission time.
Definition retry.h:33
uint32_t mrc
Maximum retransmission count.
Definition retry.h:36
fr_retry_config_t const * config
master configuration
Definition retry.h:52
@ FR_RETRY_MRC
reached maximum retransmission count
Definition retry.h:47
@ FR_RETRY_CONTINUE
Definition retry.h:46
@ FR_RETRY_MRD
reached maximum retransmission duration
Definition retry.h:48
fr_time_delta_t mrd
Maximum retransmission duration.
Definition retry.h:35
fr_time_t updated
last update, really a cached "now".
Definition retry.h:56
fr_time_t next
when the next timer should be set
Definition retry.h:55
#define fr_box_time_delta(_val)
Definition value.h:364
static size_t char ** out
Definition value.h:1022