23 RCSID(
"$Id: d322ff20be747104b209c6e9b6c68872e2f19fb7 $")
25 #include <freeradius-devel/io/channel.h>
26 #include <freeradius-devel/io/control.h>
27 #include <freeradius-devel/util/debug.h>
28 #include <freeradius-devel/util/syserror.h>
29 #include <freeradius-devel/util/talloc.h>
36 #include <sys/event.h>
38 #define MAX_MESSAGES (2048)
39 #define MAX_CONTROL_PLANE (1024)
40 #define MAX_KEVENTS (10)
42 #define MPRINT1 if (debug_lvl) printf
43 #define MPRINT2 if (debug_lvl > 1) printf
70 fprintf(stderr,
"usage: channel_test [OPTS]\n");
71 fprintf(stderr,
" -c <control-plane> Size of the control plane queue.\n");
72 fprintf(stderr,
" -m <messages> Send number of messages.\n");
73 fprintf(stderr,
" -o <outstanding> Keep number of messages outstanding.\n");
74 fprintf(stderr,
" -t Touch memory for fake packets.\n");
75 fprintf(stderr,
" -x Debugging mode.\n");
82 bool running, signaled_close;
83 int rcode, i, num_events;
84 int num_outstanding, num_messages;
97 fprintf(stderr,
"Failed creating message set\n");
108 fprintf(stderr,
"Failed signaling open: %s\n",
fr_syserror(errno));
115 num_replies = num_outstanding = num_messages = 0;
118 signaled_close =
false;
132 MPRINT1(
"Master got reply %d, outstanding=%d, %d/%d sent.\n",
133 num_replies, num_outstanding, num_messages,
max_messages);
142 MPRINT1(
"Master DONE sending\n");
150 MPRINT1(
"Master sending %d messages\n", num_to_send);
152 for (i = 0; i < num_to_send; i++) {
171 memcpy(cd->
m.
data, &num_messages,
sizeof(num_messages));
173 MPRINT1(
"Master sent message %d\n", num_messages);
176 fprintf(stderr,
"Failed sending request: %s\n",
fr_syserror(errno));
182 MPRINT1(
"Master got reply %d, outstanding=%d, %d/%d sent.\n",
183 num_replies, num_outstanding, num_messages,
max_messages);
193 if (!signaled_close && (num_messages >=
max_messages) && (num_outstanding == 0)) {
194 MPRINT1(
"Master signaling worker to exit.\n");
197 fprintf(stderr,
"Failed signaling close: %s\n",
fr_syserror(errno));
201 signaled_close =
true;
204 MPRINT1(
"Master waiting on events.\n");
208 MPRINT1(
"Master kevent returned %d\n", num_events);
210 if (num_events < 0) {
211 if (num_events == EINTR)
continue;
213 fprintf(stderr,
"Failed waiting for kevent: %s\n",
fr_syserror(errno));
217 if (num_events == 0)
continue;
222 for (i = 0; i < num_events; i++) {
236 if (!data_size)
break;
241 MPRINT1(
"Master got channel event %d\n", ce);
245 MPRINT1(
"Master got data ready signal\n");
250 MPRINT1(
"Master SIGNAL WITH NO DATA!\n");
257 MPRINT1(
"Master got reply %d, outstanding=%d, %d/%d sent.\n",
258 num_replies, num_outstanding, num_messages,
max_messages);
264 MPRINT1(
"Master received close signal\n");
275 fprintf(stderr,
"Master got unexpected CE %d\n", ce);
300 MPRINT2(
"Master messages used = %d\n", rcode);
311 int rcode, num_events;
312 int worker_messages = 0;
323 fprintf(stderr,
"Failed creating message set\n");
327 MPRINT1(
"\tWorker started.\n");
334 MPRINT1(
"\tWorker waiting on events.\n");
337 MPRINT1(
"\tWorker kevent returned %d events\n", num_events);
339 if (num_events < 0) {
340 if (errno == EINTR)
continue;
342 fprintf(stderr,
"Failed waiting for kevent: %s\n",
fr_syserror(errno));
346 if (num_events == 0)
continue;
348 for (i = 0; i < num_events; i++) {
363 if (!data_size)
break;
368 MPRINT1(
"\tWorker got channel event %d\n", ce);
373 MPRINT1(
"\tWorker received a new channel\n");
378 MPRINT1(
"\tWorker requested to close the channel.\n");
387 MPRINT1(
"\tWorker got message %d\n", worker_messages);
395 MPRINT1(
"\tWorker got data ready signal\n");
400 MPRINT1(
"\tWorker SIGNAL WITH NO DATA!\n");
410 memcpy(&message_id, cd->
m.
data,
sizeof(message_id));
411 MPRINT1(
"\tWorker got message %d (says %d)\n", worker_messages, message_id);
422 for (j = k = 0; j < reply->
m.
data_size; j++) {
423 k += reply->
m.
data[j];
426 reply->
m.
data[4] = k;
430 MPRINT1(
"\tWorker sending reply to messages %d\n", worker_messages);
433 fprintf(stderr,
"Failed sending reply: %s\n",
fr_syserror(errno));
440 MPRINT1(
"\tWorker got NOOP\n");
445 fprintf(stderr,
"\tWorker got unexpected CE %d\n", ce);
461 MPRINT1(
"\tWorker exiting.\n");
484 int main(
int argc,
char *argv[])
494 while ((c = getopt(argc, argv,
"c:hm:o:tx")) != -1)
switch (c) {
528 argc -= (optind - 1);
529 argv += (optind - 1);
552 fprintf(stderr,
"channel_test: Failed to create channel\n");
559 (void) pthread_attr_init(&attr);
560 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
562 (void) pthread_create(&master_id, &attr,
channel_master, channel);
565 (void) pthread_join(master_id, NULL);
571 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.
#define NEVER_RETURNS
Should be placed before the function return type.
fr_channel_t * fr_channel_create(TALLOC_CTX *ctx, fr_control_t *requestor, fr_control_t *responder, bool same)
Create a new channel.
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_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
Channel information which is added to a message.
static int max_control_plane
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 void * channel_master(void *arg)
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_CONTROL_ID_CHANNEL
#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.
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_control_t * fr_control_create(TALLOC_CTX *ctx, fr_event_list_t *el, fr_atomic_queue_t *aq)
Create a control-plane signaling path.
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.
int fr_message_done(fr_message_t *m)
Mark a message as done.
int fr_message_set_messages_used(fr_message_set_t *ms)
Count the number of used messages.
void fr_message_set_debug(fr_message_set_t *ms, FILE *fp)
Print debug information about the message set.
void fr_message_set_gc(fr_message_set_t *ms)
Garbage collect the message set.
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.
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 TALLOC_CTX * autofree
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.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
int fr_time_start(void)
Initialize the local time.