The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
radius1_test.c
Go to the documentation of this file.
1/*
2 * radius_test.c Tests for channels
3 *
4 * Version: $Id: 8fd3b9be6e033327bce66dc34c4054afcfd8cc12 $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 * @copyright 2016 Alan DeKok (aland@freeradius.org)
21 */
22
23RCSID("$Id: 8fd3b9be6e033327bce66dc34c4054afcfd8cc12 $")
24
25#include <freeradius-devel/io/control.h>
26#include <freeradius-devel/io/listen.h>
27#include <freeradius-devel/io/worker.h>
28#include <freeradius-devel/radius/defs.h>
29#include <freeradius-devel/util/debug.h>
30#include <freeradius-devel/util/inet.h>
31#include <freeradius-devel/util/log.h>
32#include <freeradius-devel/util/md5.h>
33#include <freeradius-devel/util/syserror.h>
34
35#ifdef HAVE_GETOPT_H
36# include <getopt.h>
37#endif
38
39#include <pthread.h>
40#include <signal.h>
41
42#include <sys/event.h>
43
44#define MAX_MESSAGES (2048)
45#define MAX_CONTROL_PLANE (1024)
46#define MAX_KEVENTS (10)
47#define MAX_WORKERS (1024)
48
49#define MPRINT1 if (debug_lvl) printf
50#define MPRINT2 if (debug_lvl > 1) printf
51
52
53typedef struct {
54 int id; //!< ID of the worker 0..N
55 pthread_t pthread_id; //!< pthread ID of the worker
56 fr_worker_t *worker; //!< pointer to the worker
57 fr_channel_t *ch; //!< channel for communicating with the worker
59
60typedef struct {
61 uint8_t vector[16];
63
64 struct sockaddr_storage src;
65 socklen_t salen;
67
68static int debug_lvl = 0;
69static int max_control_plane = 0;
70static int num_workers = 1;
71static bool quiet = false;
72
75static char const *secret = "testing123";
76
78
79static NEVER_RETURNS void usage(void)
80{
81 fprintf(stderr, "usage: radius_test [OPTS]\n");
82 fprintf(stderr, " -c <control-plane> Size of the control plane queue.\n");
83 fprintf(stderr, " -i <address>[:port] Set IP address and optional port.\n");
84 fprintf(stderr, " -q quiet - suppresses worker stats.\n");
85 fprintf(stderr, " -s <secret> Set shared secret.\n");
86 fprintf(stderr, " -w N Create N workers. Default is 1.\n");
87 fprintf(stderr, " -x Debugging mode.\n");
88
89 fr_exit_now(EXIT_FAILURE);
90}
91
92static rlm_rcode_t test_process(UNUSED void const *instance, request_t *request, fr_io_action_t action)
93{
94 MPRINT1("\t\tPROCESS --- request %"PRIu64" action %d\n", request->number, action);
96}
97
98
99static int test_decode(UNUSED void const *instance, request_t *request, uint8_t *const data, size_t data_len)
100{
101 fr_packet_ctx_t const *pc = talloc_get_type_abort_const(request->async->listen->app_instance,
103
104 request->number = pc->id;
105 request->async->process = test_process;
106
107 if (!debug_lvl) return 0;
108
109 MPRINT1("\t\tDECODE <<< request %"PRIu64" - %p data %p size %zd\n", request->number, pc, data, data_len);
110
111 return 0;
112}
113
114static ssize_t test_encode(UNUSED void const *instance, request_t *request, uint8_t *buffer, size_t buffer_len)
115{
116 fr_md5_ctx_t *md5_ctx;
117 fr_packet_ctx_t const *pc = talloc_get_type_abort_const(request->async->listen->app_instance,
119
120 MPRINT1("\t\tENCODE >>> request %"PRIu64" - data %p %p room %zd\n",
121 request->number, pc, buffer, buffer_len);
122
124 buffer[1] = pc->id;
125 buffer[2] = 0;
126 buffer[3] = 20;
127
128 memcpy(buffer + 4, pc->vector, 16);
129
130 md5_ctx = fr_md5_ctx_alloc_from_list();
131 fr_md5_update(md5_ctx, buffer, 20);
132 fr_md5_update(md5_ctx, (uint8_t const *) secret, strlen(secret));
133 fr_md5_final(buffer + 4, md5_ctx);
135
136 return 20;
137}
138
139static size_t test_nak(void const *instance, UNUSED void *packet_ctx, uint8_t *const packet, size_t packet_len, UNUSED uint8_t *reply, UNUSED size_t reply_len)
140{
141 MPRINT1("\t\tNAK !!! request %d - data %p %p size %zd\n", packet[1], instance, packet, packet_len);
142
143 return 10;
144}
145
147 .name = "worker-test",
148 .default_message_size = 4096,
149 .nak = test_nak,
150 .encode = test_encode,
151 .decode = test_decode
152};
153
154static void *worker_thread(void *arg)
155{
156 TALLOC_CTX *ctx;
157 fr_worker_t *worker;
160
161 sw = (fr_schedule_worker_t *) arg;
162
163 MPRINT1("\tWorker %d started.\n", sw->id);
164
165 MEM(ctx = talloc_init_const("worker"));
166
167 el = fr_event_list_alloc(ctx, NULL, NULL);
168 if (!el) {
169 fprintf(stderr, "radius_test: Failed to create the event list\n");
170 fr_exit_now(EXIT_FAILURE);
171 }
172
173 worker = sw->worker = fr_worker_create(ctx, el, "test", &default_log, L_DBG_LVL_MAX);
174 if (!worker) {
175 fprintf(stderr, "radius_test: Failed to create the worker\n");
176 fr_exit_now(EXIT_FAILURE);
177 }
178
179 MPRINT1("\tWorker %d looping.\n", sw->id);
180 fr_worker(worker);
181
182 sw->worker = NULL;
183 MPRINT1("\tWorker %d exiting.\n", sw->id);
184
185 talloc_free(ctx);
186 return NULL;
187}
188
189
190static void send_reply(int sockfd, fr_channel_data_t *reply)
191{
192 fr_packet_ctx_t *pc = talloc_get_type_abort(reply->packet_ctx, fr_packet_ctx_t);
193
194 MPRINT1("Master got reply %d size %zd\n", pc->id, reply->m.data_size);
195
196 if (sendto(sockfd, reply->m.data, reply->m.data_size, 0, (struct sockaddr *) &pc->src, pc->salen) < 0) {
197 fprintf(stderr, "Failed sending reply: %s\n", fr_syserror(errno));
198 fr_exit_now(EXIT_FAILURE);
199 }
200
201 talloc_free(pc);
202
203 fr_message_done(&reply->m);
204}
205
206
207static void master_process(TALLOC_CTX *ctx)
208{
209 bool running;
210 int rcode, i, num_events, which_worker;
211 int num_outstanding;
213 fr_channel_t *ch;
215 pthread_attr_t pthread_attr;
217 struct kevent events[MAX_KEVENTS];
218 int kq_master;
221 fr_listen_t listen = { .app_io = &app_io };
222 int sockfd;
223
224 MPRINT1("Master started.\n");
225
227 if (!ms) {
228 fprintf(stderr, "Failed creating message set\n");
229 fr_exit_now(EXIT_FAILURE);
230 }
231
232 /*
233 * Create the KQ and associated sockets.
234 */
235 kq_master = kqueue();
236 fr_assert(kq_master >= 0);
237
239 fr_assert(aq_master != NULL);
240
242 fr_assert(control_master != NULL);
243
245 if (sockfd < 0) {
246 fr_perror("radius_test: Failed creating socket");
247 fr_exit_now(EXIT_FAILURE);
248 }
249
250 if (fr_socket_bind(sockfd, NULL, &my_ipaddr, &my_port) < 0) {
251 fr_perror("radius_test: Failed binding to socket");
252 fr_exit_now(EXIT_FAILURE);
253 }
254
255 /*
256 * Set up the KQ filter for reading.
257 */
258 EV_SET(&events[0], sockfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
259 if (kevent(kq_master, events, 1, NULL, 0, NULL) < 0) {
260 fr_perror("Failed setting KQ for EVFILT_READ");
261 fr_exit_now(EXIT_FAILURE);
262 }
263
264 /*
265 * Create the worker threads.
266 */
267 (void) pthread_attr_init(&pthread_attr);
268 (void) pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_JOINABLE);
269
270 for (i = 0; i < num_workers; i++) {
271 workers[i].id = i;
272 (void) pthread_create(&workers[i].pthread_id, &pthread_attr, worker_thread, &workers[i]);
273 }
274
275 MPRINT1("Master created %d workers.\n", num_workers);
276
277 /*
278 * Busy loop because that's fine for the test
279 */
280 num_outstanding = 0;
281 while (num_outstanding < num_workers) {
282 for (i = 0; i < num_workers; i++) {
283 if (!workers[i].worker) continue;
284 if (workers[i].ch != NULL) continue;
285
286 /*
287 * Create the channel and signal the
288 * worker that it is open
289 */
290 MPRINT1("Master creating channel to worker %d.\n", num_workers);
292 fr_assert(workers[i].ch != NULL);
293
294 (void) fr_channel_master_ctx_add(workers[i].ch, &workers[i]);
295
296 num_outstanding++;
297 }
298 }
299
300 MPRINT1("Master created all channels.\n");
301
302 which_worker = 0;
303 running = true;
304
305 while (running) {
306 bool control_plane_signal;
307 fr_time_t now;
308 fr_channel_data_t *cd, *reply;
309
310 MPRINT1("Master waiting on events.\n");
311
312 num_events = kevent(kq_master, NULL, 0, events, MAX_KEVENTS, NULL);
313 MPRINT1("Master kevent returned %d\n", num_events);
314
315 if (num_events < 0) {
316 if (errno == EINTR) continue;
317
318 fprintf(stderr, "Failed waiting for kevent: %s\n", fr_syserror(errno));
319 fr_exit_now(EXIT_FAILURE);
320 }
321
322 if (num_events == 0) continue;
323
324 control_plane_signal = false;
325
326 /*
327 * Service the events.
328 *
329 * @todo this should NOT take a channel pointer
330 */
331 for (i = 0; i < num_events; i++) {
332 uint8_t *packet, *attr, *end;
333 size_t total_len;
334 ssize_t data_size;
335 fr_packet_ctx_t *packet_ctx;
336
337 if (events[i].filter == EVFILT_USER) {
339 control_plane_signal = true;
340 break;
341 }
342
343 fr_assert(events[i].filter == EVFILT_READ);
344
345 cd = (fr_channel_data_t *) fr_message_reserve(ms, 4096);
346 fr_assert(cd != NULL);
347
348 packet_ctx = talloc(ctx, fr_packet_ctx_t);
349 fr_assert(packet_ctx != NULL);
350 packet_ctx->salen = sizeof(packet_ctx->src);
351
352 cd->priority = 0;
353 cd->packet_ctx = packet_ctx;
354 cd->listen = &listen;
355
356 data_size = recvfrom(sockfd, cd->m.data, cd->m.rb_size, 0,
357 (struct sockaddr *) &packet_ctx->src, &packet_ctx->salen);
358 MPRINT1("Master got packet size %zd\n", data_size);
359 if (data_size <= 20) {
360 MPRINT1("Master ignoring packet (data length %zd)\n", data_size);
361
362 discard:
363 fr_message_done(&cd->m); /* yeah, reuse it for the next packet... */
364 continue;
365 }
366
367 /*
368 * Verify the packet before doing anything more with it.
369 */
370 packet = cd->m.data;
371 if (packet[0] != FR_RADIUS_CODE_ACCESS_REQUEST) {
372 MPRINT1("Master ignoring packet code %u\n", packet[0]);
373 goto discard;
374 }
375
376 total_len = fr_nbo_to_uint16(packet + 2);
377 if (total_len < 20) {
378 MPRINT1("Master ignoring packet (header length %zu)\n", total_len);
379 goto discard;
380 }
381 if (total_len > (size_t) data_size) {
382 MPRINT1("Master ignoring truncated packet (read %zd, says %zu)\n",
383 data_size, total_len);
384 goto discard;
385 }
386
387 attr = packet + 20;
388 end = packet + data_size;
389 while (attr < end) {
390 if ((end - attr) < 2) goto discard;
391 if (attr[0] == 0) goto discard;
392 if (attr[1] < 2) goto discard;
393 if ((attr + attr[1]) > end) goto discard;
394
395 attr += attr[1];
396 }
397
398 (void) fr_message_alloc(ms, &cd->m, total_len);
399
400 MPRINT1("Master sending packet size %zd to worker %d\n", cd->m.data_size, which_worker);
401 cd->m.when = fr_time();
402
403 packet_ctx->id = packet[1];
404 memcpy(packet_ctx->vector, packet + 4, 16);
405
406 rcode = fr_channel_send_request(workers[which_worker].ch, cd, &reply);
407 if (rcode < 0) {
408 fprintf(stderr, "Failed sending request: %s\n", fr_syserror(errno));
409 fr_exit_now(EXIT_FAILURE);
410 }
411 which_worker++;
412 if (which_worker >= num_workers) which_worker = 0;
413
414 fr_assert(rcode == 0);
415 if (reply) send_reply(sockfd, reply);
416 }
417
418 if (!control_plane_signal) continue;
419
420 now = fr_time();
421
422 MPRINT1("Master servicing control-plane\n");
423
424 while (true) {
425 uint32_t id;
426 size_t data_size;
427 char data[256];
428
429 data_size = fr_control_message_pop(aq_master, &id, data, sizeof(data));
430 if (!data_size) break;
431
433
434 ce = fr_channel_service_message(now, &ch, data, data_size);
435 MPRINT1("Master got channel event %d\n", ce);
436
437 switch (ce) {
439 MPRINT1("Master got data ready signal\n");
440
441 reply = fr_channel_recv_reply(ch);
442 if (!reply) {
443 MPRINT1("Master SIGNAL WITH NO DATA!\n");
444 continue;
445 }
446
447 do {
448 send_reply(sockfd, reply);
449 } while ((reply = fr_channel_recv_reply(ch)) != NULL);
450 break;
451
452 case FR_CHANNEL_CLOSE:
453 sw = fr_channel_master_ctx_get(ch);
454 fr_assert(sw != NULL);
455
456 MPRINT1("Master received close ack signal for worker %d\n", sw->id);
457
458 (void) pthread_kill(sw->pthread_id, SIGTERM);
459 running = false;
460 break;
461
462 case FR_CHANNEL_NOOP:
463 break;
464
465 default:
466 fprintf(stderr, "Master got unexpected CE %d\n", ce);
467
468 /*
469 * Not written yet!
470 */
471 fr_assert(0 == 1);
472 break;
473 } /* switch over signal returned */
474 } /* drain the control plane */
475 } /* loop until told to exit */
476
477 MPRINT1("Master exiting.\n");
478
479 fr_time_t last_checked = fr_time();
480
481 /*
482 * Busy-wait for the workers to exit;
483 */
484 do {
485 fr_time_t now = fr_time();
486
487 num_outstanding = num_workers;
488
489 for (i = 0; i < num_workers; i++) {
490 if (!workers[i].worker) num_outstanding--;
491 }
492
493 if ((now - last_checked) > (NSEC / 10)) {
494 MPRINT1("still num_outstanding %d\n", num_outstanding);
495 }
496
497 } while (num_outstanding > 0);
498
499 /*
500 * Force all messages to be garbage collected
501 */
502 MPRINT2("GC\n");
504
505 if (debug_lvl > 1) fr_message_set_debug(ms, stdout);
506
507 /*
508 * After the garbage collection, all messages marked "done" MUST also be marked "free".
509 */
511 MPRINT2("Master messages used = %d\n", rcode);
512 fr_assert(rcode == 0);
513 close(sockfd);
514}
515
516static void sig_ignore(int sig)
517{
518 (void) signal(sig, sig_ignore);
519}
520
521int main(int argc, char *argv[])
522{
523 int c;
524 TALLOC_CTX *autofree = talloc_autofree_context();
525 uint16_t port16 = 0;
526
528
530
531 memset(&my_ipaddr, 0, sizeof(my_ipaddr));
532 my_ipaddr.af = AF_INET;
533 my_ipaddr.prefix = 32;
534 my_ipaddr.addr.v4.s_addr = htonl(INADDR_LOOPBACK);
535 my_port = 1812;
536
537 while ((c = getopt(argc, argv, "c:hi:qs:w:x")) != -1) switch (c) {
538 case 'x':
539 debug_lvl++;
540 break;
541
542 case 'c':
543 max_control_plane = atoi(optarg);
544 break;
545
546 case 'i':
547 if (fr_inet_pton_port(&my_ipaddr, &port16, optarg, -1, AF_INET, true, false) < 0) {
548 fr_perror("Failed parsing ipaddr");
549 fr_exit_now(EXIT_FAILURE);
550 }
551 my_port = port16;
552 break;
553
554 case 'q':
555 quiet = true;
556 break;
557
558 case 's':
559 secret = optarg;
560 break;
561
562 case 'w':
563 num_workers = atoi(optarg);
564 if ((num_workers <= 0) || (num_workers >= MAX_WORKERS)) usage();
565 break;
566
567 case 'h':
568 default:
569 usage();
570 }
571
572 if (!max_control_plane) {
575 }
576
577#if 0
578 argc -= (optind - 1);
579 argv += (optind - 1);
580#endif
581
582 signal(SIGTERM, sig_ignore);
583
584 if (debug_lvl) {
585 setvbuf(stdout, NULL, _IONBF, 0);
586 }
587
589
590 fr_exit_now(EXIT_SUCCESS);
591}
static int const char char buffer[256]
Definition acutest.h:576
size_t default_message_size
Usually maximum message size.
Definition app_io.h:39
Public structure describing an I/O path for a protocol.
Definition app_io.h:33
fr_atomic_queue_t * fr_atomic_queue_alloc(TALLOC_CTX *ctx, size_t size)
Create fixed-size atomic queue.
Structure to hold the atomic queue.
#define RCSID(id)
Definition build.h:483
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:313
#define UNUSED
Definition build.h:315
bool fr_channel_recv_reply(fr_channel_t *ch)
Receive a reply message from the channel.
Definition channel.c:408
int fr_channel_send_request(fr_channel_t *ch, fr_channel_data_t *cd)
Send a request message into the channel.
Definition channel.c:306
fr_channel_event_t fr_channel_service_message(fr_time_t when, fr_channel_t **p_channel, void const *data, size_t data_size)
Service a control-plane message.
Definition channel.c:685
int fr_channel_service_kevent(fr_channel_t *ch, fr_control_t *c, UNUSED struct kevent const *kev)
Service a control-plane event.
Definition channel.c:788
A full channel, which consists of two ends.
Definition channel.c:144
fr_message_t m
the message header
Definition channel.h:105
fr_channel_event_t
Definition channel.h:67
@ FR_CHANNEL_NOOP
Definition channel.h:74
@ FR_CHANNEL_CLOSE
Definition channel.h:72
@ FR_CHANNEL_DATA_READY_REQUESTOR
Definition channel.h:70
void * packet_ctx
Packet specific context for holding client information, and other proto_* specific information that n...
Definition channel.h:142
fr_listen_t * listen
for tracking packet transport, etc.
Definition channel.h:146
uint32_t priority
Priority of this packet.
Definition channel.h:140
Channel information which is added to a message.
Definition channel.h:104
static fr_atomic_queue_t * aq_master
static fr_control_t * control_master
static int kq_master
#define FR_CONTROL_ID_CHANNEL
Definition control.h:56
#define MEM(x)
Definition debug.h:36
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:234
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
Definition defs.h:33
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition defs.h:34
static int sockfd
Definition dhcpclient.c:56
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Definition inet.c:937
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:69
int af
Address family.
Definition inet.h:64
union fr_ipaddr_t::@130 addr
IPv4/6 prefix.
ssize_t fr_control_message_pop(fr_atomic_queue_t *aq, uint32_t *p_id, void *data, size_t data_size)
Pop control-plane message.
Definition control.c:377
fr_control_t * fr_control_create(TALLOC_CTX *ctx, fr_event_list_t *el, fr_atomic_queue_t *aq)
Create a control-plane signaling path.
Definition control.c:149
The control structure.
Definition control.c:79
fr_app_io_t const * app_io
I/O path functions.
Definition listen.h:31
talloc_free(reap)
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
Definition event.c:2899
Stores all information relating to an event list.
Definition event.c:411
int fr_log_init_legacy(fr_log_t *log, bool daemonize)
Initialise file descriptors based on logging destination.
Definition log.c:907
fr_log_t default_log
Definition log.c:291
@ L_DBG_LVL_MAX
Lowest priority debug messages (-xxxxx | -Xxxx).
Definition log.h:74
fr_md5_update_t fr_md5_update
Definition md5.c:442
fr_md5_final_t fr_md5_final
Definition md5.c:443
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Definition md5.c:522
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Definition md5.c:477
void fr_md5_ctx_t
Definition md5.h:28
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
int fr_message_done(fr_message_t *m)
Mark a message as done.
Definition message.c:190
fr_message_t * fr_message_alloc(fr_message_set_t *ms, fr_message_t *m, size_t actual_packet_size)
Allocate packet data for a message.
Definition message.c:988
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
Definition message.c:1212
void fr_message_set_debug(fr_message_set_t *ms, FILE *fp)
Print debug information about the message set.
Definition message.c:1262
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
Definition message.c:1238
fr_message_t * fr_message_reserve(fr_message_set_t *ms, size_t reserve_size)
Reserve a message.
Definition message.c:934
fr_message_set_t * fr_message_set_create(TALLOC_CTX *ctx, int num_messages, size_t message_size, size_t ring_buffer_size)
Create a message set.
Definition message.c:127
A Message set, composed of message headers and ring buffer data.
Definition message.c:95
size_t rb_size
cache-aligned size in the ring buffer
Definition message.h:51
fr_time_t when
when this message was sent
Definition message.h:47
uint8_t * data
pointer to the data in the ring buffer
Definition message.h:49
size_t data_size
size of the data in the ring buffer
Definition message.h:50
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
#define fr_assert(_expr)
Definition rad_assert.h:38
static TALLOC_CTX * autofree
static int max_control_plane
uint8_t vector[16]
int main(int argc, char *argv[])
#define MAX_KEVENTS
static void * worker_thread(void *arg)
#define MAX_MESSAGES
static rlm_rcode_t test_process(UNUSED void const *instance, request_t *request, fr_io_action_t action)
static fr_schedule_worker_t workers[MAX_WORKERS]
static int test_decode(UNUSED void const *instance, request_t *request, uint8_t *const data, size_t data_len)
static ssize_t test_encode(UNUSED void const *instance, request_t *request, uint8_t *buffer, size_t buffer_len)
struct sockaddr_storage src
static size_t test_nak(void const *instance, UNUSED void *packet_ctx, uint8_t *const packet, size_t packet_len, UNUSED uint8_t *reply, UNUSED size_t reply_len)
#define MAX_CONTROL_PLANE
#define MAX_WORKERS
static char const * secret
socklen_t salen
#define MPRINT2
#define MPRINT1
static uint16_t my_port
static fr_ipaddr_t my_ipaddr
static void sig_ignore(int sig)
static bool quiet
static fr_app_io_t app_io
static int num_workers
static NEVER_RETURNS void usage(void)
static void send_reply(int sockfd, fr_channel_data_t *reply)
static int debug_lvl
static fr_event_list_t * events
Definition radsniff.c:59
#define RETURN_MODULE_OK
Definition rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
Signals that can be sent to a request.
int fr_socket_server_udp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *port_name, bool async)
Open an IPv4/IPv6 unconnected UDP socket.
Definition socket.c:867
int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
Definition socket.c:229
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define talloc_get_type_abort_const
Definition talloc.h:282
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition talloc.h:112
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:51
int fr_time_start(void)
Initialize the local time.
Definition time.c:150
#define NSEC
Definition time.h:379
"server local" time.
Definition time.h:69
close(uq->fd)
static fr_event_list_t * el
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:733
static fr_slen_t data
Definition value.h:1265
fr_channel_t * fr_worker_channel_create(fr_worker_t *worker, TALLOC_CTX *ctx, fr_control_t *master)
Create a channel to the worker.
Definition worker.c:1609
fr_worker_t * fr_worker_create(TALLOC_CTX *ctx, fr_event_list_t *el, char const *name, fr_log_t const *logger, fr_log_lvl_t lvl, fr_worker_config_t *config)
Create a worker.
Definition worker.c:1356
void fr_worker(fr_worker_t *worker)
The main loop and entry point of the stand-alone worker thread.
Definition worker.c:1493
A worker which takes packets from a master, and processes them.
Definition worker.c:94
int id
ID of the worker 0..N.
fr_channel_t * ch
channel for communicating with the worker
pthread_t pthread_id
the thread of this worker
Definition schedule.c:86
static void master_process(void)
fr_worker_t * worker
the worker data structure
Definition schedule.c:97
Scheduler specific information for worker threads.
Definition schedule.c:83