The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
trigger.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: 1182be92451b0916f758c51f39390322b47443c4 $
19 *
20 * @file trigger.c
21 * @brief Execute scripts when a server event occurs.
22 *
23 * @copyright 2015 The FreeRADIUS server project
24 */
25RCSID("$Id: 1182be92451b0916f758c51f39390322b47443c4 $")
26
27#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
28#include <freeradius-devel/server/cf_file.h>
29#include <freeradius-devel/server/cf_parse.h>
30#include <freeradius-devel/server/exec.h>
31#include <freeradius-devel/server/main_loop.h>
32#include <freeradius-devel/server/pair.h>
33#include <freeradius-devel/server/request_data.h>
34#include <freeradius-devel/server/trigger.h>
35#include <freeradius-devel/unlang/function.h>
36#include <freeradius-devel/unlang/subrequest.h>
37#include <freeradius-devel/unlang/xlat.h>
38#include <freeradius-devel/unlang/tmpl.h>
39
40
41#include <sys/wait.h>
42
43/** Whether triggers are enabled globally
44 *
45 */
49
50/** Describes a rate limiting entry for a trigger
51 *
52 */
53typedef struct {
54 fr_rb_node_t node; //!< Entry in the trigger last fired tree.
55 CONF_ITEM *ci; //!< Config item this rate limit counter is associated with.
56 fr_time_t last_fired; //!< When this trigger last fired.
58
62 { .out = &dict_freeradius, .proto = "freeradius" },
63 { NULL }
64};
65
69 { .out = &attr_trigger_name, .name = "Trigger-Name", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
70 { NULL }
71};
72
74{
76}
77
78/** Compares two last fired structures
79 *
80 * @param one first pointer to compare.
81 * @param two second pointer to compare.
82 * @return CMP(one, two)
83 */
84static int8_t _trigger_last_fired_cmp(void const *one, void const *two)
85{
86 trigger_last_fired_t const *a = one, *b = two;
87
88 return CMP(a->ci, b->ci);
89}
90
91/** Return whether triggers are enabled
92 *
93 */
95{
96 return (trigger_cs != NULL);
97}
98
99typedef struct {
100 fr_value_box_list_t out; //!< result of the xlap (which we ignore)
101 unlang_result_t result; //!< the result of expansion
102 tmpl_t *vpt; //!< the template to execute
103 int exec_status; //!< Result of the program (if the trigger is a tmpl)
105
106/** Execute a trigger - call an executable to process an event
107 *
108 * A trigger ties a state change (e.g. connection up) in a module to an action
109 * (e.g. send an SNMP trap) defined in raqddb/triggers.conf or in the trigger
110 * section of a module, and can be created with one call to trigger().
111 *
112 * The trigger function expands the configuration item, and runs the given
113 * function (exec, sql insert, etc.) asynchronously, allowing the server to
114 * keep processing packets while the action is being taken.
115 *
116 * The name of each trigger is based on the module or portion of the server
117 * which runs the trigger, and is usually taken from the state when the module
118 * has a state change.
119 *
120 * Triggers are separate from logs, because log messages are generally
121 * informational, are not time sensitive, and usually require log files to be
122 * parsed and filtered in order to find relevant information.
123 *
124 * In contrast, triggers are something specific which the administrator needs
125 * to be notified about immediately and can't wait to post-process a log file.
126 *
127 * @note Calls to this function will be ignored if #trigger_init has not been called.
128 *
129 * @param[in] intp Interpreter to run the trigger with. If this is NULL the
130 * trigger will be executed synchronously.
131 * @param[in] cs to search for triggers in.
132 * If cs is not NULL, the portion after the last '.' in name is used for the trigger.
133 * If cs is NULL, the entire name is used to find the trigger in the global trigger
134 * section.
135 * @param[in] name the path relative to the global trigger section ending in the trigger name
136 * e.g. module.ldap.pool.start.
137 * @param[in] rate_limit whether to rate limit triggers.
138 * @param[in] args to make available via the @verbatim %trigger(<arg>) @endverbatim xlat.
139 * @return
140 * - 0 on success.
141 * - -1 on failure.
142 */
144 CONF_SECTION const *cs, char const *name, bool rate_limit, fr_pair_list_t *args)
145{
146 CONF_ITEM *ci;
147 CONF_PAIR *cp;
148
149 char const *attr;
150 char const *value;
151
152 request_t *request;
154 ssize_t slen;
155
157 tmpl_rules_t t_rules;
158
159 /*
160 * noop if trigger_init was never called, or if
161 * we're just checking the configuration.
162 */
163 if (!trigger_cs || check_config) return 0;
164
165 /*
166 * A module can have a local "trigger" section. In which
167 * case that is used in preference to the global one.
168 *
169 * @todo - we should really allow triggers via @trigger,
170 * so that all of the triggers are in one location. And
171 * then we can have different triggers for different
172 * module instances.
173 */
174 if (cs) {
175 CONF_SECTION const *subcs;
176
177 subcs = cf_section_find(cs, "trigger", NULL);
178 if (!subcs) goto use_global;
179
180 /*
181 * If a local trigger{...} section exists, then
182 * use the local part of the name, rather than
183 * the full path.
184 */
185 attr = strrchr(name, '.');
186 if (attr) {
187 attr++;
188 } else {
189 attr = name;
190 }
191 } else {
192 use_global:
193 cs = trigger_cs;
194 attr = name;
195 }
196
197 /*
198 * Find the trigger. Note that we do NOT allow searching
199 * from the root of the tree. Triggers MUST be in a
200 * trigger{...} section.
201 */
202 ci = cf_reference_item(cs, cs, attr);
203 if (!ci) {
204 if (cs != trigger_cs) goto use_global; /* not found locally, try to find globally */
205
206 DEBUG3("Failed finding trigger '%s'", attr);
207 return -1;
208 }
209
210 if (!cf_item_is_pair(ci)) {
211 ERROR("Trigger is not a configuration variable: %s", attr);
212 return -1;
213 }
214
215 cp = cf_item_to_pair(ci);
216 if (!cp) return -1;
217
218 value = cf_pair_value(cp);
219 if (!value) {
220 DEBUG3("Trigger has no value: %s", name);
221 return -1;
222 }
223
224 /*
225 * Perform periodic rate_limiting.
226 */
227 if (rate_limit) {
228 trigger_last_fired_t find, *found;
229 fr_time_t now = fr_time();
230
231 find.ci = ci;
232
233 pthread_mutex_lock(trigger_mutex);
234
235 found = fr_rb_find(trigger_last_fired_tree, &find);
236 if (!found) {
237 MEM(found = talloc(NULL, trigger_last_fired_t));
238 found->ci = ci;
239 /*
240 * Initialise last_fired to 2 seconds ago so
241 * the trigger fires on the first occurrence
242 */
243 found->last_fired = fr_time_wrap(NSEC * -2);
244
246 }
247
248 pthread_mutex_unlock(trigger_mutex);
249
250 /*
251 * Send the rate_limited traps at most once per second.
252 *
253 * @todo - make this configurable for longer periods of time.
254 */
255 if (fr_time_to_sec(found->last_fired) == fr_time_to_sec(now)) return -1;
256 found->last_fired = now;
257 }
258
259 /*
260 * Allocate a request to run asynchronously in the interpreter.
261 */
262 request = request_local_alloc_internal(NULL, (&(request_init_args_t){ .detachable = true }));
263 request->name = talloc_typed_asprintf(request, "trigger-%s", name);
264
265 if (args) {
266 fr_pair_t *vp;
267
268 if (fr_pair_list_copy(request->request_ctx, &request->request_pairs, args) < 0) {
269 PERROR("Failed copying trigger arguments");
270 talloc_free(request);
271 return -1;
272 }
273
274 /*
275 * Add the trigger name to the request data
276 */
279 }
280
281 MEM(trigger = talloc_zero(request, fr_trigger_t));
282 fr_value_box_list_init(&trigger->out);
283
285 if (!el) el = main_loop_event_list();
286
287 t_rules = (tmpl_rules_t) {
288 .attr = {
289 .dict_def = request->local_dict, /* we can use local attributes */
290 .list_def = request_attr_request,
291 },
292 .xlat = {
293 .runtime_el = el,
294 },
295 .at_runtime = true,
296 };
297
299 cf_pair_value_quote(cp), NULL, &t_rules);
300 if (slen <= 0) {
301 char *spaces, *text;
302
303 fr_canonicalize_error(trigger, &spaces, &text, slen, value);
304
305 cf_log_err(cp, "Failed parsing trigger expresion");
306 cf_log_err(cp, "%s", text);
307 cf_log_perr(cp, "%s^", spaces);
308
309 talloc_free(request);
311 talloc_free(text);
312 return -1;
313 }
314
315 if (!tmpl_is_exec(trigger->vpt) && !tmpl_is_xlat(trigger->vpt)) {
316 /*
317 * We only support exec and xlat templates.
318 * Anything else is an error.
319 */
320 cf_log_err(cp, "Trigger must be an \"expr\" or `exec`");
321 talloc_free(request);
322 return -1;
323 }
324
325 fr_assert(trigger->vpt != NULL);
326
327 if (unlang_tmpl_push(trigger, &trigger->result, &trigger->out, request, trigger->vpt,
329 .type = UNLANG_TMPL_ARGS_TYPE_EXEC,
330 .exec = {
331 .status_out = &trigger->exec_status,
332 .timeout = fr_time_delta_from_sec(5),
333 },
334 }, UNLANG_TOP_FRAME) < 0) {
335 talloc_free(request);
336 }
337
338 /*
339 * An interpreter was passed in, we can run the expansion
340 * asynchronously in that interpreter. And then the
341 * worker cleans up the detached request.
342 */
343 if (intp) {
344 unlang_interpret_set(request, intp);
345
346 /*
347 * Don't allow the expansion to run for a long time.
348 *
349 * @todo - make the timeout configurable.
350 */
352 DEBUG("Failed setting timeout on trigger %s", value);
353 talloc_free(request);
354 return -1;
355 }
356
358 PERROR("Running trigger failed");
359 talloc_free(request);
360 return -1;
361 }
362 } else {
363 /*
364 * No interpreter, we MUST be running from the
365 * main loop. We then run the expansion
366 * synchronously. This allows the expansion /
367 * notification to finish before the server shuts
368 * down.
369 *
370 * If the expansion was async, then it may be
371 * possible for the server to exit before the
372 * expansion finishes. Arguably the worker
373 * thread should ensure that the server doesn't
374 * exit until all requests have acknowledged that
375 * they've exited.
376 *
377 * But those exits may be advisory. i.e. "please
378 * finish the request". This one here is
379 * mandatary to finish before the server exits.
380 */
381 unlang_interpret_synchronous(NULL, request);
382 talloc_free(request);
383 }
384
385 return 0;
386}
387
388/** Create trigger arguments to describe the server the pool connects to
389 *
390 * @note #trigger_init must be called before calling this function,
391 * else it will return NULL.
392 *
393 * @param[in] ctx to allocate fr_pair_t s in.
394 * @param[out] list to append Pool-Server and Pool-Port pairs to
395 * @param[in] server we're connecting to.
396 * @param[in] port on that server.
397 */
398void trigger_args_afrom_server(TALLOC_CTX *ctx, fr_pair_list_t *list, char const *server, uint16_t port)
399{
400 fr_dict_attr_t const *server_da;
401 fr_dict_attr_t const *port_da;
402 fr_pair_t *vp;
403
404 server_da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CONNECTION_POOL_SERVER);
405 if (!server_da) {
406 ERROR("Incomplete dictionary: Missing definition for \"Connection-Pool-Server\"");
407 return;
408 }
409
410 port_da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_CONNECTION_POOL_PORT);
411 if (!port_da) {
412 ERROR("Incomplete dictionary: Missing definition for \"Connection-Pool-Port\"");
413 return;
414 }
415
416 MEM(vp = fr_pair_afrom_da(ctx, server_da));
417 fr_pair_value_strdup(vp, server, false);
418 fr_pair_append(list, vp);
419
420 MEM(vp = fr_pair_afrom_da(ctx, port_da));
421 vp->vp_uint16 = port;
422 fr_pair_append(list, vp);
423}
424
425static int _mutex_free(pthread_mutex_t *mutex)
426{
427 pthread_mutex_destroy(mutex);
428 return 0;
429}
430
431/** Free trigger resources
432 *
433 */
434static int _trigger_free(UNUSED void *uctx)
435{
437 TALLOC_FREE(trigger_last_fired_tree);
438 TALLOC_FREE(trigger_mutex);
439
440 return 0;
441}
442
443/** Set the global trigger section trigger will search in, and register xlats
444 *
445 * This function exists because triggers are used by the connection pool, which
446 * is used in the server library which may not have the mainconfig available.
447 * Additionally, utilities may want to set their own root config sections.
448 *
449 * We don't register the trigger xlat here, as we may inadvertently initialise
450 * the xlat code, which is annoying when this is called from a utility.
451 *
452 * @param[in] cs_arg to use as global trigger section.
453 * @return
454 * - 0 on success.
455 * - -1 on failure.
456 */
457static int _trigger_init(void *cs_arg)
458{
459 CONF_SECTION *cs;
460
462 PERROR("Failed loading trigger dictionaries");
463 return -1;
464 }
466 PERROR("Failed loading trigger attributes");
467 return -1;
468 }
469
470 cs = talloc_get_type_abort(cs_arg, CONF_SECTION);
471 if (!cs) {
472 ERROR("%s - Pointer to main_config was NULL", __FUNCTION__);
473 return -1;
474 }
475
476 trigger_cs = cf_section_find(cs, "trigger", NULL);
477 if (!trigger_cs) {
478 WARN("trigger { ... } subsection not found, triggers will be disabled");
479 return 0;
480 }
481
485
487 pthread_mutex_init(trigger_mutex, 0);
488 talloc_set_destructor(trigger_mutex, _mutex_free);
489
490 return 0;
491}
492
494{
495 int ret;
496
497 fr_atexit_global_once_ret(&ret, _trigger_init, _trigger_free, UNCONST(CONF_SECTION *, cs));
498
499 return ret;
500}
va_list args
Definition acutest.h:770
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:485
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition build.h:112
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
bool check_config
Definition cf_file.c:66
CONF_ITEM * cf_reference_item(CONF_SECTION const *parent_cs, CONF_SECTION const *outer_cs, char const *ptr)
Definition cf_file.c:3745
Common header for all CONF_* types.
Definition cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
bool cf_item_is_pair(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_PAIR.
Definition cf_util.c:631
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1027
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition cf_util.c:1637
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:663
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1593
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:289
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:296
#define MEM(x)
Definition debug.h:36
static char const * spaces
Definition dependency.c:360
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define DEBUG(fmt,...)
Definition dhcpclient.c:39
#define fr_dict_autofree(_to_free)
Definition dict.h:879
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2475
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:274
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:287
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4206
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4728
#define fr_dict_autoload(_to_load)
Definition dict.h:876
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition dict_util.c:3403
Specifies an attribute which must be present for the module to function.
Definition dict.h:273
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:286
Test enumeration values.
Definition dict_test.h:92
int unlang_interpret_set_timeout(request_t *request, fr_time_delta_t timeout)
Set a timeout for a request.
Definition interpret.c:1504
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:1998
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2017
#define UNLANG_TOP_FRAME
Definition interpret.h:36
rlm_rcode_t unlang_interpret_synchronous(fr_event_list_t *el, request_t *request)
Execute an unlang section synchronously.
#define PERROR(_fmt,...)
Definition log.h:228
#define DEBUG3(_fmt,...)
Definition log.h:266
talloc_free(reap)
Stores all information relating to an event list.
Definition event.c:377
void fr_canonicalize_error(TALLOC_CTX *ctx, char **sp, char **text, ssize_t slen, char const *fmt)
Canonicalize error strings, removing tabs, and generate spaces for error marker.
Definition log.c:87
fr_event_list_t * main_loop_event_list(void)
Return the main loop event list.
Definition main_loop.c:164
unsigned short uint16_t
@ FR_TYPE_STRING
String of printable characters.
long int ssize_t
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition pair.c:2319
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition pair.c:2638
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1343
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:287
#define fr_assert(_expr)
Definition rad_assert.h:38
#define WARN(fmt,...)
Definition radclient.h:47
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition rb.h:246
The main red black tree structure.
Definition rb.h:73
fr_dict_attr_t const * request_attr_request
Definition request.c:43
#define request_local_alloc_internal(_ctx, _args)
Allocate a new internal request outside of the request pool.
Definition request.h:343
Optional arguments for initialising requests.
Definition request.h:287
static char const * name
#define FR_SBUFF_IN(_start, _len_or_end)
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition pair.h:37
#define tmpl_is_xlat(vpt)
Definition tmpl.h:210
#define tmpl_is_exec(vpt)
Definition tmpl.h:211
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:335
struct tmpl_rules_s tmpl_rules_t
Definition tmpl.h:233
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:273
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
int unlang_subrequest_child_push_and_detach(request_t *request)
Add a child request to the runnable queue.
Definition subrequest.c:488
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:514
void * talloc_null_ctx(void)
Retrieve the current talloc NULL ctx.
Definition talloc.c:49
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:294
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
Definition time.h:731
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:590
#define fr_time_wrap(_time)
Definition time.h:145
#define NSEC
Definition time.h:379
"server local" time.
Definition time.h:69
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
tmpl_t * vpt
the template to execute
Definition trigger.c:102
int exec_status
Result of the program (if the trigger is a tmpl)
Definition trigger.c:103
static fr_dict_attr_t const * attr_trigger_name
Definition trigger.c:66
static int _trigger_init(void *cs_arg)
Set the global trigger section trigger will search in, and register xlats.
Definition trigger.c:457
void trigger_args_afrom_server(TALLOC_CTX *ctx, fr_pair_list_t *list, char const *server, uint16_t port)
Create trigger arguments to describe the server the pool connects to.
Definition trigger.c:398
int trigger(unlang_interpret_t *intp, CONF_SECTION const *cs, char const *name, bool rate_limit, fr_pair_list_t *args)
Execute a trigger - call an executable to process an event.
Definition trigger.c:143
static int _mutex_free(pthread_mutex_t *mutex)
Definition trigger.c:425
static fr_dict_t const * dict_freeradius
Definition trigger.c:59
int trigger_init(CONF_SECTION const *cs)
Definition trigger.c:493
fr_dict_autoload_t trigger_dict[]
Definition trigger.c:61
fr_rb_node_t node
Entry in the trigger last fired tree.
Definition trigger.c:54
fr_value_box_list_t out
result of the xlap (which we ignore)
Definition trigger.c:100
fr_time_t last_fired
When this trigger last fired.
Definition trigger.c:56
static fr_rb_tree_t * trigger_last_fired_tree
Definition trigger.c:47
unlang_result_t result
the result of expansion
Definition trigger.c:101
CONF_ITEM * ci
Config item this rate limit counter is associated with.
Definition trigger.c:55
static pthread_mutex_t * trigger_mutex
Definition trigger.c:48
static int8_t _trigger_last_fired_cmp(void const *one, void const *two)
Compares two last fired structures.
Definition trigger.c:84
static CONF_SECTION const * trigger_cs
Whether triggers are enabled globally.
Definition trigger.c:46
static void _trigger_last_fired_free(void *data)
Definition trigger.c:73
bool trigger_enabled(void)
Return whether triggers are enabled.
Definition trigger.c:94
fr_dict_attr_autoload_t trigger_dict_attr[]
Definition trigger.c:68
static int _trigger_free(UNUSED void *uctx)
Free trigger resources.
Definition trigger.c:434
Describes a rate limiting entry for a trigger.
Definition trigger.c:53
static fr_event_list_t * el
Arguments for evaluating different types of tmpls.
Definition tmpl.h:48
static fr_slen_t data
Definition value.h:1291