23RCSID(
"$Id: 1eeac385cefd9396515ad0b28a03804fd6597090 $")
25#include <freeradius-devel/io/channel.h>
26#include <freeradius-devel/util/debug.h>
27#include <freeradius-devel/util/syserror.h>
28#include <freeradius-devel/util/talloc.h>
36#define MAX_MESSAGES (2048)
37#define MAX_CONTROL_PLANE (1024)
38#define MAX_KEVENTS (10)
40#define MPRINT1 if (debug_lvl) printf
41#define MPRINT2 if (debug_lvl > 1) printf
68 fprintf(stderr,
"usage: channel_test [OPTS]\n");
69 fprintf(stderr,
" -c <control-plane> Size of the control plane queue.\n");
70 fprintf(stderr,
" -m <messages> Send number of messages.\n");
71 fprintf(stderr,
" -o <outstanding> Keep number of messages outstanding.\n");
72 fprintf(stderr,
" -t Touch memory for fake packets.\n");
73 fprintf(stderr,
" -x Debugging mode.\n");
80 bool running, signaled_close;
81 int rcode, i, num_events;
82 int num_outstanding, num_messages;
95 fprintf(stderr,
"Failed creating message set\n");
106 fprintf(stderr,
"Failed signaling open: %s\n",
fr_syserror(errno));
113 num_replies = num_outstanding = num_messages = 0;
116 signaled_close =
false;
130 MPRINT1(
"Master got reply %d, outstanding=%d, %d/%d sent.\n",
131 num_replies, num_outstanding, num_messages,
max_messages);
140 MPRINT1(
"Master DONE sending\n");
148 MPRINT1(
"Master sending %d messages\n", num_to_send);
150 for (i = 0; i < num_to_send; i++) {
169 memcpy(cd->
m.
data, &num_messages,
sizeof(num_messages));
171 MPRINT1(
"Master sent message %d\n", num_messages);
174 fprintf(stderr,
"Failed sending request: %s\n",
fr_syserror(errno));
180 MPRINT1(
"Master got reply %d, outstanding=%d, %d/%d sent.\n",
181 num_replies, num_outstanding, num_messages,
max_messages);
191 if (!signaled_close && (num_messages >=
max_messages) && (num_outstanding == 0)) {
192 MPRINT1(
"Master signaling worker to exit.\n");
195 fprintf(stderr,
"Failed signaling close: %s\n",
fr_syserror(errno));
199 signaled_close =
true;
202 MPRINT1(
"Master waiting on events.\n");
206 MPRINT1(
"Master kevent returned %d\n", num_events);
208 if (num_events < 0) {
209 if (errno == EINTR)
continue;
211 fprintf(stderr,
"Failed waiting for kevent: %s\n",
fr_syserror(errno));
215 if (num_events == 0)
continue;
220 for (i = 0; i < num_events; i++) {
234 if (!data_size)
break;
239 MPRINT1(
"Master got channel event %d\n", ce);
243 MPRINT1(
"Master got data ready signal\n");
248 MPRINT1(
"Master SIGNAL WITH NO DATA!\n");
255 MPRINT1(
"Master got reply %d, outstanding=%d, %d/%d sent.\n",
256 num_replies, num_outstanding, num_messages,
max_messages);
262 MPRINT1(
"Master received close signal\n");
273 fprintf(stderr,
"Master got unexpected CE %d\n", ce);
298 MPRINT2(
"Master messages used = %d\n", rcode);
309 int rcode, num_events;
310 int worker_messages = 0;
321 fprintf(stderr,
"Failed creating message set\n");
325 MPRINT1(
"\tWorker started.\n");
332 MPRINT1(
"\tWorker waiting on events.\n");
335 MPRINT1(
"\tWorker kevent returned %d events\n", num_events);
337 if (num_events < 0) {
338 if (errno == EINTR)
continue;
340 fprintf(stderr,
"Failed waiting for kevent: %s\n",
fr_syserror(errno));
344 if (num_events == 0)
continue;
346 for (i = 0; i < num_events; i++) {
361 if (!data_size)
break;
366 MPRINT1(
"\tWorker got channel event %d\n", ce);
371 MPRINT1(
"\tWorker received a new channel\n");
376 MPRINT1(
"\tWorker requested to close the channel.\n");
385 MPRINT1(
"\tWorker got message %d\n", worker_messages);
393 MPRINT1(
"\tWorker got data ready signal\n");
398 MPRINT1(
"\tWorker SIGNAL WITH NO DATA!\n");
408 memcpy(&message_id, cd->
m.
data,
sizeof(message_id));
409 MPRINT1(
"\tWorker got message %d (says %d)\n", worker_messages, message_id);
420 for (j = k = 0; j < reply->
m.
data_size; j++) {
421 k += reply->
m.
data[j];
424 reply->
m.
data[4] = k;
428 MPRINT1(
"\tWorker sending reply to messages %d\n", worker_messages);
431 fprintf(stderr,
"Failed sending reply: %s\n",
fr_syserror(errno));
438 MPRINT1(
"\tWorker got NOOP\n");
443 fprintf(stderr,
"\tWorker got unexpected CE %d\n", ce);
459 MPRINT1(
"\tWorker exiting.\n");
482int main(
int argc,
char *argv[])
492 while ((c = getopt(argc, argv,
"c:hm:o:tx")) != -1)
switch (c) {
526 argc -= (optind - 1);
527 argv += (optind - 1);
550 fprintf(stderr,
"channel_test: Failed to create channel\n");
557 (void) pthread_attr_init(&attr);
558 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
560 (void) pthread_create(&master_id, &attr,
channel_master, channel);
563 (void) pthread_join(master_id, NULL);
569 fr_channel_debug(channel, stdout);
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.
static TALLOC_CTX * autofree
#define NEVER_RETURNS
Should be placed before the function return type.
bool fr_channel_recv_reply(fr_channel_t *ch)
Receive a reply message from the channel.
int fr_channel_signal_responder_close(fr_channel_t *ch)
Signal a responder that the channel is closing.
int fr_channel_send_request(fr_channel_t *ch, fr_channel_data_t *cd)
Send a request message into the channel.
fr_channel_t * fr_channel_create(TALLOC_CTX *ctx, fr_control_t *requestor, fr_control_t *responder, bool same)
Create a new channel.
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.
bool fr_channel_recv_request(fr_channel_t *ch)
Receive a request message from the channel.
int fr_channel_service_kevent(fr_channel_t *ch, fr_control_t *c, UNUSED struct kevent const *kev)
Service a control-plane event.
int fr_channel_send_reply(fr_channel_t *ch, fr_channel_data_t *cd)
Send a reply message into the channel.
int fr_channel_responder_ack_close(fr_channel_t *ch)
Acknowledge that the channel is closing.
int fr_channel_signal_open(fr_channel_t *ch)
Send a channel to a responder.
A full channel, which consists of two ends.
fr_message_t m
the message header
@ FR_CHANNEL_DATA_READY_REQUESTOR
@ FR_CHANNEL_DATA_READY_RESPONDER
#define FR_CONTROL_ID_CHANNEL
Channel information which is added to a message.
static int max_control_plane
static void * channel_master(void *arg)
int main(int argc, char *argv[])
static void * channel_worker(void *arg)
static fr_atomic_queue_t * aq_master
#define MAX_CONTROL_PLANE
request_t * request_alloc(UNUSED TALLOC_CTX *ctx, UNUSED request_init_args_t const *args)
void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t const *request)
static int max_outstanding
static fr_control_t * control_worker
static fr_control_t * control_master
static NEVER_RETURNS void usage(void)
static fr_atomic_queue_t * aq_worker
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
fr_control_t * fr_control_create(TALLOC_CTX *ctx, fr_event_list_t *el, fr_atomic_queue_t *aq, size_t num_callbacks)
Create a control-plane signaling path.
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.
fr_message_set_t * fr_message_set_create(TALLOC_CTX *ctx, int num_messages, size_t message_size, size_t ring_buffer_size, bool unlimited_size)
Create a message set.
int fr_message_done(fr_message_t *m)
Mark a message as done.
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.
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
void fr_message_set_debug(FILE *fp, fr_message_set_t *ms)
Print debug information about the message set.
A Message set, composed of message headers and ring buffer data.
fr_time_t when
when this message was sent
uint8_t * data
pointer to the data in the ring buffer
size_t data_size
size of the data in the ring buffer
static fr_event_list_t * events
rlm_rcode_t rcode
Last rcode returned by a module.
Optional arguments for initialising requests.
static _Thread_local int worker_id
Internal ID of the current worker thread.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
int fr_time_start(void)
Initialize the local time.