The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
control_test.c
Go to the documentation of this file.
1/*
2 * control_test.c Tests for control planes
3 *
4 * Version: $Id: 56090248a9985bfab00f5c40c10640efdb06c25f $
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: 56090248a9985bfab00f5c40c10640efdb06c25f $")
24
25#include <freeradius-devel/io/control.h>
26#include <freeradius-devel/util/debug.h>
27#include <freeradius-devel/util/syserror.h>
28#include <freeradius-devel/util/talloc.h>
29#include <freeradius-devel/util/time.h>
30
31#include <sys/event.h>
32#include <stdio.h>
33#include <string.h>
34#include <pthread.h>
35
36#ifdef HAVE_GETOPT_H
37# include <getopt.h>
38#endif
39
40#undef MEM
41#define MEM(x) if (!(x)) { fprintf(stderr, "%s[%u] OUT OF MEMORY\n", __FILE__, __LINE__); _exit(EXIT_FAILURE); }
42#define MPRINT1 if (debug_lvl) printf
43#define CONTROL_MAGIC 0xabcd6809
44
45static int debug_lvl = 0;
46static int kq = -1;
48static size_t max_messages = 10;
49static int aq_size = 16;
50static fr_control_t *control = NULL;
51static fr_ring_buffer_t *rb = NULL;
52
53/**********************************************************************/
54typedef struct request_s request_t;
56void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request);
57
59{
60 return NULL;
61}
62
63void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
64{
65}
66
67/**********************************************************************/
68
69static NEVER_RETURNS void usage(void)
70{
71 fprintf(stderr, "usage: control_test [OPTS]\n");
72 fprintf(stderr, " -m <messages> Send number of messages.\n");
73 fprintf(stderr, " -x Debugging mode.\n");
74
75 fr_exit_now(EXIT_SUCCESS);
76}
77
78typedef struct {
80 size_t counter;
82
83static void *control_master(UNUSED void *arg)
84{
85 TALLOC_CTX *ctx;
86
87 MEM(ctx = talloc_init_const("control_master"));
88
89 MPRINT1("Master started.\n");
90
91 /*
92 * Busy loop. We're stupid.
93 */
94 while (true) {
95 int num_events;
96 ssize_t data_size;
98 struct kevent kev;
99
100 wait_for_events:
101 MPRINT1("Master waiting for events.\n");
102
103 num_events = kevent(kq, NULL, 0, &kev, 1, NULL);
104 if (num_events < 0) {
105 fprintf(stderr, "Failed reading kevent: %s\n", fr_syserror(errno));
106 fr_exit_now(EXIT_FAILURE);
107 }
108
109 MPRINT1("Master draining the control plane.\n");
110
111 while (true) {
112 uint32_t id;
113
114 data_size = fr_control_message_pop(aq, &id, &m, sizeof(m));
115 if (data_size == 0) goto wait_for_events;
116
117 if (data_size < 0) {
118 fprintf(stderr, "Failed reading control message\n");
119 fr_exit_now(EXIT_FAILURE);
120 }
121
122 fr_assert(data_size == sizeof(m));
124
125 MPRINT1("Master got message %zu.\n", m.counter);
126
128
129 if (m.counter == (max_messages - 1)) goto do_exit;
130 }
131 }
132
133do_exit:
134 MPRINT1("Master exiting.\n");
135
136 talloc_free(ctx);
137
138 return NULL;
139}
140
141static void *control_worker(UNUSED void *arg)
142{
143 size_t i;
144 TALLOC_CTX *ctx;
145
146 MEM(ctx = talloc_init_const("control_worker"));
147
148 MPRINT1("\tWorker started.\n");
149
150 for (i = 0; i < max_messages; i++) {
151 my_message_t m;
152
154 m.counter = i;
155
156retry:
157 if (fr_control_message_send(control, rb, FR_CONTROL_ID_CHANNEL, &m, sizeof(m)) < 0) {
158 MPRINT1("\tWorker retrying message %zu\n", i);
159 usleep(10);
160 goto retry;
161 }
162
163 MPRINT1("\tWorker sent message %zu\n", i);
164 }
165
166 MPRINT1("\tWorker exiting.\n");
167
168 talloc_free(ctx);
169
170 return NULL;
171}
172
173
174
175int main(int argc, char *argv[])
176{
177 int c;
178 TALLOC_CTX *autofree = talloc_autofree_context();
179 pthread_attr_t attr;
180 pthread_t master_id, worker_id;
181
183
184 while ((c = getopt(argc, argv, "hm:o:tx")) != -1) switch (c) {
185 case 'x':
186 debug_lvl++;
187 break;
188
189 case 'm':
190 max_messages = atoi(optarg);
191 break;
192
193 case 'h':
194 default:
195 usage();
196 }
197
198#if 0
199 argc -= (optind - 1);
200 argv += (optind - 1);
201#endif
202
203 kq = kqueue();
204 fr_assert(kq >= 0);
205
207 fr_assert(aq != NULL);
208
210 if (!control) {
211 fprintf(stderr, "control_test: Failed to create control plane\n");
212 fr_exit_now(EXIT_FAILURE);
213 }
214
216 if (!rb) fr_exit_now(EXIT_FAILURE);
217
218 /*
219 * Start the two threads, with the channel.
220 */
221 (void) pthread_attr_init(&attr);
222 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
223
224 (void) pthread_create(&worker_id, &attr, control_worker, NULL);
225 (void) pthread_create(&master_id, &attr, control_master, NULL);
226
227 (void) pthread_join(master_id, NULL);
228 (void) pthread_join(worker_id, NULL);
229
230 close(kq);
231
232 fr_exit_now(EXIT_SUCCESS);
233}
int const char * file
Definition acutest.h:702
va_list args
Definition acutest.h:770
int const char int line
Definition acutest.h:702
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
static fr_control_t * control_worker
static fr_control_t * control_master
#define FR_CONTROL_ID_CHANNEL
Definition control.h:56
#define FR_CONTROL_MAX_SIZE
Definition control.h:51
#define FR_CONTROL_MAX_MESSAGES
Definition control.h:50
static fr_ring_buffer_t * rb
int main(int argc, char *argv[])
#define CONTROL_MAGIC
static int kq
static int aq_size
static fr_atomic_queue_t * aq
request_t * request_alloc(UNUSED TALLOC_CTX *ctx, UNUSED request_init_args_t const *args)
uint32_t header
#define MPRINT1
static size_t max_messages
static fr_control_t * control
#define MEM(x)
static NEVER_RETURNS void usage(void)
void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
static int debug_lvl
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:234
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
int fr_control_message_send(fr_control_t *c, fr_ring_buffer_t *rb, uint32_t id, void *data, size_t data_size)
Send a control-plane message.
Definition control.c:343
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
talloc_free(reap)
unsigned int uint32_t
long int ssize_t
static bool do_exit
Definition event.c:81
#define fr_assert(_expr)
Definition rad_assert.h:38
static TALLOC_CTX * autofree
Optional arguments for initialising requests.
Definition request.h:254
fr_ring_buffer_t * fr_ring_buffer_create(TALLOC_CTX *ctx, size_t size)
Create a ring buffer.
Definition ring_buffer.c:64
static _Thread_local int worker_id
Internal ID of the current worker thread.
Definition schedule.c:151
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
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
close(uq->fd)