The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
proto_cron_crontab.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: 7baeba72e84fe7eace244cf37c4e0f4c571304e5 $
19 * @file proto_cron_crontab.c
20 * @brief Generate crontab events.
21 *
22 * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
23 */
24#include <netdb.h>
25#include <fcntl.h>
26#include <freeradius-devel/io/application.h>
27#include <freeradius-devel/io/listen.h>
28#include <freeradius-devel/io/schedule.h>
29#include <freeradius-devel/util/skip.h>
30
31#include "proto_cron.h"
32
34
36
37typedef struct {
38 fr_event_list_t *el; //!< event list
39 fr_network_t *nr; //!< network handler
40
41 char const *name; //!< socket name
42
44
45 fr_timer_t *ev; //!< for writing statistics
46
47 fr_listen_instance_t *parent; //!< master IO handler
48
49 fr_time_t recv_time; //!< when the timer hit.
50
51 bool suspended; //!< we suspend reading from the FD.
52 bool bootstrap; //!< get it started
54
55typedef struct {
56 unsigned int min;
57 unsigned int max;
58
60 size_t offset;
61
62 uint64_t fields;
64
67
68 CONF_SECTION *cs; //!< our configuration
69
70 char const *filename; //!< where to read input packet from
71 fr_pair_list_t pair_list; //!< for input packet
72
73 int code;
74 char const *spec; //!< crontab spec
75
77
78 fr_client_t *client; //!< static client
79
80 fr_dict_t const *dict; //!< our namespace.
81};
82
83
84static int time_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
85
94
95/*
96 * Parse a basic field with sanity checks.
97 */
98static int parse_field(CONF_ITEM *ci, char const **start, char const *name,
99 cron_tab_t *tab, unsigned int min, unsigned int max, size_t offset)
100{
101 char const *p;
102 char *end = NULL;
103 unsigned int num, next, step, last = 0;
104 bool last_is_set = false;
105 bool wildcard = false;
106 unsigned int i;
107 uint64_t fields = 0;
108
109 p = *start;
111
112 if (!*p) {
113 cf_log_err(ci, "Missing field for %s", name);
114 return -1;
115 }
116
117 tab->min = min;
118 tab->max = max;
119 tab->offset = offset;
120 tab->fields = 0;
121
122 /*
123 * See 'man 5 crontab' for the format.
124 */
125 while (p) {
126 /*
127 * Allow wildcards, but only once.
128 */
129 if (*p == '*') {
130 if (wildcard) {
131 cf_log_err(ci, "Cannot use two wildcards for %s at %s", name, p);
132 return -1;
133 }
134
135 end = UNCONST(char *, p) + 1;
136 wildcard = true;
137 num = min;
138 next = max;
139 goto check_step;
140 }
141
142 /*
143 * If there's already a "*", we can't have another one.
144 */
145 if (wildcard) {
146 cf_log_err(ci, "Cannot use wildcard and numbers for %s at %s", name, p);
147 return -1;
148 }
149
150 /*
151 * If it's not a wildcard, it MUST be a number,
152 * which is between min and max.
153 */
154 num = strtoul(p, &end, 10);
155 if ((num < min) || (num > max)) {
156 cf_log_err(ci, "Number is invalid or out of bounds (%u..%u) for %s at %s",
157 min, max, name, p);
158 return -1;
159 }
160
161 /*
162 * Don't allow the same number to be specified
163 * multiple times.
164 */
165 if (!last_is_set) {
166 last_is_set = true;
167
168 } else if (num <= last) {
169 cf_log_err(ci, "Number overlaps with previous value of %u, for %s at %s",
170 last, name, p);
171 return -1;
172 }
173 last = num;
174
175 /*
176 * Ranges are allowed, with potential steps
177 */
178 if (*end == '-') {
179 p = end + 1;
180 next = strtoul(p, &end, 10);
181 if (next <= num) {
182 cf_log_err(ci, "End of range number overlaps with previous value of %u, for %s at %s",
183 num, name, p);
184 return -1;
185 }
186
187 if (next > max) {
188 cf_log_err(ci, "End of range number is invalid or out of bounds (%u..%u) for %s at %s",
189 min, max, name, p);
190 return -1;
191 }
192
193 check_step:
194 last = next;
195
196 /*
197 * Allow /N
198 */
199 if (*end == '/') {
200 p = end + 1;
201
202 step = strtoul(p, &end, 10);
203 if (step >= max) {
204 cf_log_err(ci, "Step value is invalid or out of bounds for %s at %s", name, p);
205 return -1;
206 }
207 } else {
208 step = 1;
209 }
210
211 /*
212 * Set the necessary bits.
213 */
214 for (i = num; i <= next; i += step) {
215 fields |= ((uint64_t) 1) << i;
216 }
217 } /* end of range specifier */
218
219 /*
220 * We can specify multiple fields, separated by a comma.
221 */
222 if (*end == ',') {
223 fields |= ((uint64_t) 1) << num;
224 p = end + 1;
225 continue;
226 }
227
228 /*
229 * EOS or space is end of field.
230 */
231 if (!(!*end || isspace((uint8_t) *end))) {
232 cf_log_err(ci, "Unexpected text for %s at %s", name, end);
233 return -1;
234 }
235
236 /*
237 * We're at the end of the field, stop.
238 */
239 fields |= ((uint64_t) 1) << num;
240 break;
241 }
242
243 /*
244 * Set a wildcard, so we can skip a lot of the later
245 * logic.
246 */
247 tab->wildcard = true;
248 for (i = min; i <= max; i++) {
249 if ((fields & (((uint64_t) 1) << i)) == 0) {
250 tab->wildcard = false;
251 break;
252 }
253 }
254
255 tab->fields = fields;
256 *start = end;
257 return 0;
258}
259
260/*
261 * Special names, including our own extensions.
262 */
264 { L("annually"), "0 0 1 1 *" },
265 { L("daily"), "0 0 * * *" },
266 { L("hourly"), "0 * * * *" },
267 { L("midnight"), "0 0 * * *" },
268 { L("monthly"), "0 0 1 * *" },
269// { L("reboot"), "+" },
270 { L("weekly"), "0 0 * * 0" },
271 { L("yearly"), "0 0 1 1 *" },
272};
274
275/** Checks the syntax of a cron job
276 *
277 * @param[in] ctx to allocate data in (instance of proto_cron).
278 * @param[out] out Where to write a module_instance_t containing the module handle and instance.
279 * @param[in] parent Base structure address.
280 * @param[in] ci #CONF_PAIR specifying the name of the type module.
281 * @param[in] rule unused.
282 * @return
283 * - 0 on success.
284 * - -1 on failure.
285 */
286static int time_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
287{
288 proto_cron_crontab_t *inst = talloc_get_type_abort(parent, proto_cron_crontab_t);
289 CONF_PAIR *cp = cf_item_to_pair(ci);
290 char const *value = cf_pair_value(cp);
291 char const *p;
292
293 p = value;
294
295 /*
296 * Check for special names.
297 */
298 if (*p == '@') {
299 p = fr_table_value_by_str(time_names, p + 1, NULL);
300 if (!p) {
301 cf_log_err(ci, "Invalid time name '%s'", value);
302 return -1;
303 }
304
305 /*
306 * Over-write the special names with standard
307 * ones, so that the rest of the parser is simpler.
308 */
309 *((char const **) out) = p;
310 return 0;
311 }
312
313 *((char const **) out) = value;
314
315 memset(&inst->tab, 0, sizeof(inst->tab)); /* talloc_zeroed, but this shuts up the analuzer */
316
317 if (parse_field(ci, &p, "minute", &inst->tab[0], 0, 59, offsetof(struct tm, tm_min)) < 0) return -1;
318 if (parse_field(ci, &p, "hour", &inst->tab[1], 0, 23, offsetof(struct tm, tm_hour)) < 0) return -1;
319 if (parse_field(ci, &p, "day of month", &inst->tab[2], 1, 31, offsetof(struct tm, tm_mday)) < 0) return -1;
320 if (parse_field(ci, &p, "month", &inst->tab[3], 1,12, offsetof(struct tm, tm_mon)) < 0) return -1;
321 if (parse_field(ci, &p, "day of week", &inst->tab[4], 0, 6, offsetof(struct tm, tm_wday)) < 0) return -1;
322
324
325 if (*p) {
326 cf_log_err(ci, "Unexpected text after cron time specification");
327 return -1;
328 }
329
330 return 0;
331}
332
334 size_t buffer_len, size_t *leftover)
335{
338 proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
339 fr_io_address_t *address, **address_p;
340
341 *leftover = 0;
342
343 /*
344 * Suspend all activity on the FD, because we let the
345 * timers do their work.
346 */
347 if (!thread->suspended) {
348 static fr_event_update_t const pause_read[] = {
350 { 0 }
351 };
352
353 if (fr_event_filter_update(thread->el, li->fd, FR_EVENT_FILTER_IO, pause_read) < 0) {
354 fr_assert(0);
355 }
356
357 /*
358 * Don't read from it the first time.
359 */
360 thread->suspended = true;
361 return 0;
362 }
363
364 /*
365 * Where the addresses should go. This is a special case
366 * for proto_radius.
367 */
368 address_p = (fr_io_address_t **) packet_ctx;
369 address = *address_p;
370
371 memset(address, 0, sizeof(*address));
372 address->socket.inet.src_ipaddr.af = AF_INET;
373 address->socket.inet.dst_ipaddr.af = AF_INET;
374 address->radclient = inst->client;
375
376 *recv_time_p = thread->recv_time;
377
378 if (buffer_len < 1) {
379 DEBUG2("proto_cron_tab read buffer is too small for input packet");
380 return 0;
381 }
382
383 buffer[0] = 0;
384
385 /*
386 * Print out what we received.
387 */
388 DEBUG2("proto_cron_crontab - reading packet for %s",
389 thread->name);
390
391 return 1;
392}
393
394
396 UNUSED uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
397{
398 return buffer_len;
399}
400
401
402/** Open a crontab listener
403 *
404 */
406{
409 proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
410
411 fr_ipaddr_t ipaddr;
412
413 /*
414 * We never read or write to this file, but we need a
415 * readable FD in order to bootstrap the process.
416 */
417 if (inst->filename == NULL) return -1;
418 li->fd = open(inst->filename, O_RDONLY);
419 if (li->fd < 0) {
420 cf_log_err(li->listen->cs, "Failed opening %s - %s", inst->filename, fr_syserror(errno));
421 return -1;
422 }
423
424 memset(&ipaddr, 0, sizeof(ipaddr));
425 ipaddr.af = AF_INET;
426 li->app_io_addr = fr_socket_addr_alloc_inet_src(li, IPPROTO_UDP, 0, &ipaddr, 0);
427
428 fr_assert((cf_parent(inst->cs) != NULL) && (cf_parent(cf_parent(inst->cs)) != NULL)); /* listen { ... } */
429
430 thread->name = talloc_typed_asprintf(thread, "cron_crontab from filename %s", inst->filename);
431 thread->parent = talloc_parent(li);
432
433 return 0;
434}
435
436
437/** Decode the packet
438 *
439 */
440static int mod_decode(void const *instance, request_t *request, UNUSED uint8_t *const data, UNUSED size_t data_len)
441{
443 fr_io_track_t const *track = talloc_get_type_abort_const(request->async->packet_ctx, fr_io_track_t);
444 fr_io_address_t const *address = track->address;
445
446 /*
447 * Hacks for now until we have a lower-level decode routine.
448 */
449 if (inst->code) request->packet->code = inst->code;
450 request->packet->id = fr_rand() & 0xff;
451 request->reply->id = request->packet->id;
452
453 request->packet->data = talloc_zero_array(request->packet, uint8_t, 1);
454 request->packet->data_len = 1;
455
456 (void) fr_pair_list_copy(request->request_ctx, &request->request_pairs, &inst->pair_list);
457
458 /*
459 * Set the rest of the fields.
460 */
461 request->client = UNCONST(fr_client_t *, address->radclient);
462
463 request->packet->socket = address->socket;
464 fr_socket_addr_swap(&request->reply->socket, &address->socket);
465
467
468 return 0;
469}
470
471/*
472 * Get the next time interval.
473 *
474 * Set the relevant "struct tm" field to its next value, and
475 * return "true"
476 *
477 * Set the relevant "struct tm" field to its minimum value, and
478 * return "false".
479 */
480static bool get_next(struct tm *tm, cron_tab_t const *tab)
481{
482 unsigned int i, num = *(int *) (((uint8_t *) tm) + tab->offset);
483
484 num++;
485
486 /*
487 * Simplified process for "do each thing".
488 */
489 if (tab->wildcard) {
490 if (num <= tab->max) goto done;
491 goto next;
492 }
493
494 /*
495 * See when the next time interval is.
496 */
497 for (i = num; i <= tab->max; i++) {
498 if ((tab->fields & (((uint64_t) 1) << i)) != 0) {
499 num = i;
500 break;
501 }
502 }
503
504 /*
505 * We ran out of time intervals. Reset this field to the
506 * minimum, and ask the caller to go to the next
507 * interval.
508 */
509 if (i > tab->max) {
510 next:
511 *(int *) (((uint8_t *) tm) + tab->offset) = tab->min;
512 return false;
513 }
514
515done:
516 *(int *) (((uint8_t *) tm) + tab->offset) = num;
517 return true;
518}
519
520/*
521 * Called when tm.tm_sec == 0. If it isn't zero, then it means
522 * that the timer is late, and we treat it as if tm.tm_sec == 0.
523 */
524static void do_cron(fr_timer_list_t *tl, fr_time_t now, void *uctx)
525{
526 proto_cron_crontab_thread_t *thread = uctx;
527 struct tm tm;
528 time_t start = time(NULL), end;
529
530 thread->recv_time = now;
531
532 localtime_r(&start, &tm);
533
534 /*
535 * For now, ignore "day of week". If the "day of week"
536 * is a wildcard, then ignore it. Otherwise, calculate
537 * next based on "day of month" and also "day of week",
538 * and then return the time which is closer.
539 */
540 tm.tm_sec = 0;
541 if (get_next(&tm, &thread->inst->tab[0])) goto set; /* minutes */
542 if (get_next(&tm, &thread->inst->tab[1])) goto set; /* hours */
543
544 /*
545 * If we're running it every day of the week, just pay
546 * attention to the day of the month.
547 */
548 if (thread->inst->tab[4].wildcard) {
549 if (get_next(&tm, &thread->inst->tab[2])) goto set; /* days */
550
551 if (get_next(&tm, &thread->inst->tab[3])) goto set; /* month */
552
553 /*
554 * We ran out of months, so we have to go to the next year.
555 */
556 tm.tm_year++;
557
558 } else {
559 /*
560 * Pick the earliest of "day of month" and "day of week".
561 */
562 struct tm m_tm = tm;
563 struct tm w_tm = tm;
564 int tm_wday = tm.tm_wday;
565 bool m_day = get_next(&m_tm, &thread->inst->tab[2]);
566 bool w_day = get_next(&w_tm, &thread->inst->tab[4]);
567 time_t m_time;
568 time_t w_time;
569
570 /*
571 * No more days this week. Go to the
572 * start of the next week.
573 */
574 if (!w_day) {
575 w_tm = tm;
576 w_tm.tm_mday += (6 - tm_wday);
577
578 (void) mktime(&w_tm); /* normalize it */
579
580 tm_wday = w_tm.tm_wday;
581#ifndef NDEBUG
582 w_day = get_next(&w_tm, &thread->inst->tab[4]);
583 fr_assert(w_day);
584#else
585 (void) get_next(&w_tm, &thread->inst->tab[4]);
586#endif
587 }
588
589 /*
590 * Next weekday is ignored by mktime(), so we
591 * have to update the day of the month with the
592 * new value.
593 *
594 * Note that mktime() will also normalize the
595 * values, so we can just add "28 + 5" for a day
596 * of the month, and mktime() will normalize that
597 * to the correct day for the next month.
598 */
599 fr_assert(tm.tm_wday > tm_wday);
600 w_tm.tm_mday += tm.tm_wday - tm_wday;
601
602 /*
603 * No more days this month, go to the next month,
604 * and potentially the next year.
605 */
606 if (!m_day && !get_next(&m_tm, &thread->inst->tab[3])) m_tm.tm_year++;
607
608 /*
609 * We now have 2 times, one for "day of month"
610 * and another for "day of week". Pick the
611 * earliest one.
612 */
613 m_time = mktime(&m_tm);
614 w_time = mktime(&w_tm);
615
616 if (m_time < w_time) {
617 end = m_time;
618 } else {
619 end = w_time;
620 }
621
622 goto use_time;
623 }
624
625set:
626 end = mktime(&tm);
627 fr_assert(end >= start);
628
629use_time:
630 if (DEBUG_ENABLED2) {
631 char buffer[256];
632
633 ctime_r(&end, buffer);
634 DEBUG("TIMER - virtual server %s next cron is at %s, in %ld seconds",
635 cf_section_name2(thread->inst->parent->server_cs), buffer, end - start);
636 }
637
638 if (fr_timer_at(thread, tl, &thread->ev, fr_time_add(now, fr_time_delta_from_sec(end - start)),
639 false, do_cron, thread) < 0) {
640 fr_assert(0);
641 }
642
643 /*
644 * Don't run the event the first time.
645 */
646 if (thread->bootstrap) {
647 thread->bootstrap = false;
648 return;
649 }
650
651 /*
652 * Now that we've set the timer, tell the network side to
653 * call our read routine.
654 */
655 fr_network_listen_read(thread->nr, thread->parent);
656}
657
658/** Close a virtual listener
659 *
660 * The fd only exists to bootstrap the listener, so closing it mostly means
661 * removing the timer that runs the jobs.
662 *
663 * @param[in] li the listener
664 * @return
665 * - 0 on success.
666 * - -1 if the timer could not be deleted. The fd is closed either way.
667 */
669{
670 proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
671 int ret = 0;
672
673 if (thread->ev && (fr_timer_delete(&thread->ev) < 0)) {
674 PERROR("Failed deleting cron timer");
675 ret = -1;
676 }
677
678 close(li->fd);
679
680 return ret;
681}
682
683/** Set the event list for a new socket
684 *
685 * @param[in] li the listener
686 * @param[in] el the event list
687 * @param[in] nr context from the network side
688 */
690{
693 proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
694
695 thread->el = el;
696 thread->nr = nr;
697 thread->inst = inst;
698 thread->bootstrap = true;
699
700 do_cron(el->tl, fr_time(), thread);
701}
702
703static char const *mod_name(fr_listen_instance_t *li)
704{
705 proto_cron_crontab_thread_t *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
706
707 return thread->name;
708}
709
717
718static int mod_instantiate(module_inst_ctx_t const *mctx)
719{
720 proto_cron_crontab_t *inst = talloc_get_type_abort(mctx->mi->data, proto_cron_crontab_t);
721 CONF_SECTION *conf = mctx->mi->conf;
722 fr_client_t *client;
723 fr_pair_t *vp;
724 FILE *fp;
725 bool done = false;
726
727 inst->parent = talloc_get_type_abort(mctx->mi->parent->data, proto_cron_t);
728 inst->cs = mctx->mi->conf;
730 if (!inst->dict) {
731 cf_log_err(conf, "Please define 'namespace' in this virtual server");
732 return -1;
733 }
734
735 fr_pair_list_init(&inst->pair_list);
736 MEM(inst->client = client = talloc_zero(inst, fr_client_t));
737
738 client->ipaddr.af = AF_INET;
739 client->src_ipaddr = client->ipaddr;
740
741 client->longname = client->shortname = inst->filename;
742 client->secret = talloc_strdup(client, "testing123");
743 client->nas_type = talloc_strdup(client, "load");
744 client->use_connected = false;
745
746 fp = fopen(inst->filename, "r");
747 if (!fp) {
748 cf_log_err(conf, "Failed opening %s - %s",
749 inst->filename, fr_syserror(errno));
750 return -1;
751 }
752
753 if (fr_pair_list_afrom_file(inst, inst->dict, &inst->pair_list, fp, &done, true) < 0) {
754 cf_log_perr(conf, "Failed reading %s", inst->filename);
755 fclose(fp);
756 return -1;
757 }
758
759 fclose(fp);
760
761 vp = fr_pair_find_by_da(&inst->pair_list, NULL, inst->parent->attr_packet_type);
762 if (vp) inst->code = vp->vp_uint32;
763
764 return 0;
765}
766
768 .common = {
769 .magic = MODULE_MAGIC_INIT,
770 .name = "cron_crontab",
772 .inst_size = sizeof(proto_cron_crontab_t),
773 .thread_inst_size = sizeof(proto_cron_crontab_thread_t),
774 .instantiate = mod_instantiate
775 },
776 .default_message_size = 4096,
777 .track_duplicates = false,
778
779 .open = mod_open,
780 .close = mod_close,
781 .read = mod_read,
782 .write = mod_write,
783 .event_list_set = mod_event_list_set,
784 .client_find = mod_client_find,
785 .get_name = mod_name,
786
787 .decode = mod_decode,
788};
static int const char char buffer[256]
Definition acutest.h:641
module_t common
Common fields to all loadable modules.
Definition app_io.h:34
Public structure describing an I/O path for a protocol.
Definition app_io.h:33
static int packet_ctx
the tests pass only the address of packet_ctx
static uint8_t request[4]
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:203
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#define UNUSED
Definition build.h:415
#define NUM_ELEMENTS(_t)
Definition build.h:437
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:722
cf_parse_t func
Override default parsing behaviour for the specified type with a custom parsing function.
Definition cf_parse.h:666
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:466
@ CONF_FLAG_NOT_EMPTY
CONF_PAIR is required to have a non zero length value.
Definition cf_parse.h:484
@ CONF_FLAG_FILE_READABLE
File matching value must exist, and must be readable.
Definition cf_parse.h:472
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:649
Common header for all CONF_* types.
Definition cf_priv.h:54
Configuration AVP similar to a fr_pair_t.
Definition cf_priv.h:77
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition cf_util.c:1405
CONF_ITEM * cf_section_to_item(CONF_SECTION const *cs)
Cast a CONF_SECTION to a CONF_ITEM.
Definition cf_util.c:725
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition cf_util.c:651
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition cf_util.c:1758
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_parent(_cf)
Definition cf_util.h:115
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:347
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
#define MEM(x)
Definition debug.h:38
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
Test enumeration values.
Definition dict_test.h:92
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define fr_event_filter_update(...)
Definition event.h:239
#define FR_EVENT_SUSPEND(_s, _f)
Temporarily remove the filter for a func from kevent.
Definition event.h:115
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:83
Callbacks for the FR_EVENT_FILTER_IO filter.
Definition event.h:188
Structure describing a modification to a filter's state.
Definition event.h:96
int af
Address family.
Definition inet.h:64
IPv4/6 prefix.
fr_socket_t socket
src/dst ip and port.
Definition base.h:342
fr_client_t const * radclient
old-style client definition
Definition base.h:344
void fr_network_listen_read(fr_network_t *nr, fr_listen_instance_t *li)
Signal the network to read from a listener.
Definition network.c:287
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition client.h:83
char const * secret
Secret PSK.
Definition client.h:90
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
Definition client.h:84
char const * nas_type
Type of client (arbitrary).
Definition client.h:125
char const * longname
Client identifier.
Definition client.h:87
char const * shortname
Client nickname.
Definition client.h:88
bool use_connected
do we use connected sockets for this client
Definition client.h:115
Describes a host allowed to send packets to the server.
Definition client.h:80
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG_ENABLED2
True if global debug level 1-2 messages are enabled.
Definition log.h:263
#define fr_time()
Definition event.c:58
Stores all information relating to an event list.
Definition event.c:375
fr_listen_t * listen
the listener this is a socket of.
Definition listen.h:65
int fd
file descriptor for this socket - set by open
Definition listen.h:67
void const * app_io_instance
I/O path configuration context.
Definition listen.h:34
CONF_SECTION * cs
of this listener
Definition listen.h:39
fr_socket_t * app_io_addr
for tracking duplicate sockets
Definition listen.h:71
void * thread_instance
thread / socket context
Definition listen.h:69
static fr_event_update_t pause_read[]
Definition master.c:180
fr_io_address_t const * address
of this packet.. shared between multiple packets
Definition master.h:55
long int ssize_t
unsigned char uint8_t
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition missing.c:162
char * ctime_r(time_t const *l_clock, char *l_buf)
Definition missing.c:181
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
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:2312
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:716
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:47
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone, bool allow_exec)
Read valuepairs from the fp up to End-Of-File.
Cron master protocol handler.
CONF_SECTION * server_cs
server CS for this listener
Definition proto_cron.h:38
static const conf_parser_t crontab_listen_config[]
fr_client_t * client
static client
char const * name
socket name
static ssize_t mod_write(UNUSED fr_listen_instance_t *li, UNUSED void *packet_ctx, UNUSED fr_time_t request_time, UNUSED uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
static int mod_decode(void const *instance, request_t *request, UNUSED uint8_t *const data, UNUSED size_t data_len)
Decode the packet.
static fr_client_t * mod_client_find(fr_listen_instance_t *li, UNUSED fr_ipaddr_t const *ipaddr, UNUSED int ipproto)
static size_t time_names_len
static void do_cron(fr_timer_list_t *tl, fr_time_t now, void *uctx)
fr_timer_t * ev
for writing statistics
char const * filename
where to read input packet from
fr_time_t recv_time
when the timer hit.
fr_event_list_t * el
event list
proto_cron_t * parent
unsigned int max
struct proto_cron_tab_s proto_cron_crontab_t
static int time_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
static int mod_open(fr_listen_instance_t *li)
Open a crontab listener.
fr_listen_instance_t * parent
master IO handler
unsigned int min
static int mod_close(fr_listen_instance_t *li)
Close a virtual listener.
static ssize_t mod_read(fr_listen_instance_t *li, void **packet_ctx, fr_time_t *recv_time_p, uint8_t *buffer, size_t buffer_len, size_t *leftover)
static void mod_event_list_set(fr_listen_instance_t *li, fr_event_list_t *el, void *nr)
Set the event list for a new socket.
fr_app_io_t proto_cron_crontab
bool suspended
we suspend reading from the FD.
static bool get_next(struct tm *tm, cron_tab_t const *tab)
static char const * mod_name(fr_listen_instance_t *li)
static int parse_field(CONF_ITEM *ci, char const **start, char const *name, cron_tab_t *tab, unsigned int min, unsigned int max, size_t offset)
CONF_SECTION * cs
our configuration
char const * spec
crontab spec
proto_cron_crontab_t const * inst
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_network_t * nr
network handler
static fr_table_ptr_sorted_t time_names[]
fr_dict_t const * dict
our namespace.
fr_pair_list_t pair_list
for input packet
#define fr_assert(_expr)
Definition rad_assert.h:37
#define DEBUG2(fmt,...)
static bool done
Definition radclient.c:80
static int ipproto
Definition radclient.c:91
static rs_t * conf
Definition radsniff.c:52
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:128
#define REQUEST_VERIFY(_x)
Definition request.h:310
static char const * name
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:355
void * data
Module's instance data.
Definition module.h:297
module_instance_t const * parent
Parent module's instance (if any).
Definition module.h:363
conf_parser_t const * config
How to convert a CONF_SECTION to a module instance.
Definition module.h:207
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition skip.h:36
eap_aka_sim_process_conf_t * inst
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
An element in a lexicographically sorted array of name to ptr mappings.
Definition table.h:65
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:621
#define talloc_get_type_abort_const
Definition talloc.h:117
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:599
#define fr_time_add(_a, _b)
Add a time/time delta together.
Definition time.h:196
"server local" time.
Definition time.h:69
int fr_timer_delete(fr_timer_t **ev_p)
Delete a timer event and free its memory.
Definition timer.c:713
An event timer list.
Definition timer.c:49
A timer event.
Definition timer.c:83
#define fr_timer_at(...)
Definition timer.h:81
static fr_event_list_t * el
static fr_slen_t parent
Definition pair.h:864
static fr_socket_t * fr_socket_addr_alloc_inet_src(TALLOC_CTX *ctx, int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port)
A variant of fr_socket_addr_init_inet_src will also allocates a fr_socket_t.
Definition socket.h:249
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:83
static void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
Swap src/dst information of a fr_socket_t.
Definition socket.h:126
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
Definition value.h:1061
static fr_slen_t data
Definition value.h:1366
static fr_sbuff_err_t char ** out
Definition value.h:1061
fr_dict_t const * virtual_server_dict_by_child_ci(CONF_ITEM const *ci)
Return the namespace for a given virtual server specified by a CONF_ITEM within the virtual server.