plibc: win32 related, socket
[oweals/gnunet.git] / src / util / test_mq.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2018 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file util/test_mq.c
23  * @brief tests for mq
24  * @author Florian Dold
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29
30 #define NUM_TRANSMISSIONS 500
31
32 /**
33  * How long does the receiver take per message?
34  */
35 #define RECEIVER_THROTTLE GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 1)
36
37 static unsigned int received_cnt;
38
39
40 GNUNET_NETWORK_STRUCT_BEGIN
41
42 struct MyMessage {
43   struct GNUNET_MessageHeader header;
44   uint32_t x GNUNET_PACKED;
45 };
46
47 GNUNET_NETWORK_STRUCT_END
48
49 static int global_ret;
50
51 static struct GNUNET_SCHEDULER_Task *tt;
52
53 static struct GNUNET_SCHEDULER_Task *dt;
54
55 static struct GNUNET_MQ_Handle *cmq;
56
57
58 static void
59 do_shutdown(void *cls)
60 {
61   (void)cls;
62   if (NULL != tt)
63     {
64       GNUNET_SCHEDULER_cancel(tt);
65       tt = NULL;
66     }
67   if (NULL != cmq)
68     {
69       GNUNET_MQ_destroy(cmq);
70       cmq = NULL;
71     }
72 }
73
74
75 static void
76 do_timeout(void *cls)
77 {
78   (void)cls;
79   tt = NULL;
80   GNUNET_SCHEDULER_shutdown();
81   global_ret = 1;
82 }
83
84
85 /**
86  * Generic error handler, called with the appropriate
87  * error code and the same closure specified at the creation of
88  * the message queue.
89  * Not every message queue implementation supports an error handler.
90  *
91  * @param cls closure
92  * @param error error code
93  */
94 static void
95 error_cb(void *cls,
96          enum GNUNET_MQ_Error error)
97 {
98   GNUNET_break(0);
99   global_ret = 3;
100   GNUNET_SCHEDULER_shutdown();
101 }
102
103
104 static void
105 client_continue(void *cls)
106 {
107   struct GNUNET_SERVICE_Client *c = cls;
108
109   dt = NULL;
110   GNUNET_SERVICE_client_continue(c);
111 }
112
113
114 static void
115 handle_dummy(void *cls,
116              const struct MyMessage *msg)
117 {
118   struct GNUNET_SERVICE_Client *c = cls;
119
120   GNUNET_assert(NULL == dt);
121   /* artificially make receiver slower than sender */
122   dt = GNUNET_SCHEDULER_add_delayed(RECEIVER_THROTTLE,
123                                     &client_continue,
124                                     c);
125   if (received_cnt != ntohl(msg->x))
126     {
127       GNUNET_break(0);
128       global_ret = 4;
129       GNUNET_SCHEDULER_shutdown();
130     }
131   received_cnt++;
132 }
133
134
135 static void
136 handle_dummy2(void *cls,
137               const struct MyMessage *msg)
138 {
139   struct GNUNET_SERVICE_Client *c = cls;
140
141   GNUNET_SERVICE_client_continue(c);
142   if (NUM_TRANSMISSIONS != received_cnt)
143     {
144       GNUNET_break(0);
145       global_ret = 5;
146     }
147   GNUNET_SCHEDULER_shutdown();
148 }
149
150
151 /**
152  * Function called whenever MQ has sent a message.
153  */
154 static void
155 notify_sent_cb(void *cls)
156 {
157   static unsigned int seen;
158   unsigned int *cnt = cls;
159
160   if (seen != *cnt)
161     {
162       GNUNET_break(0);
163       global_ret = 6;
164       GNUNET_SCHEDULER_shutdown();
165     }
166   seen++;
167   GNUNET_free(cnt);
168 }
169
170
171 /**
172  * Start running the actual test.
173  *
174  * @param cls closure passed to #GNUNET_SERVICE_MAIN
175  * @param cfg configuration to use for this service
176  * @param sh handle to the newly create service
177  */
178 static void
179 run(void *cls,
180     const struct GNUNET_CONFIGURATION_Handle *cfg,
181     struct GNUNET_SERVICE_Handle *sh)
182 {
183   struct GNUNET_MQ_MessageHandler ch[] = {
184     GNUNET_MQ_handler_end()
185   };
186   struct GNUNET_MQ_Envelope *env;
187   struct MyMessage *m;
188
189   (void)cls;
190   (void)sh;
191   cmq = GNUNET_CLIENT_connect(cfg,
192                               "test_client",
193                               ch,
194                               &error_cb,
195                               NULL);
196   GNUNET_SCHEDULER_add_shutdown(&do_shutdown,
197                                 NULL);
198   tt = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_MINUTES,
199                                     &do_timeout,
200                                     NULL);
201   for (unsigned int i = 0; i < NUM_TRANSMISSIONS; i++)
202     {
203       unsigned int *cnt;
204
205       cnt = GNUNET_new(unsigned int);
206       *cnt = i;
207       env = GNUNET_MQ_msg(m,
208                           GNUNET_MESSAGE_TYPE_DUMMY);
209       GNUNET_MQ_notify_sent(env,
210                             &notify_sent_cb,
211                             cnt);
212       m->x = htonl(i);
213       GNUNET_MQ_send(cmq,
214                      env);
215     }
216   env = GNUNET_MQ_msg(m,
217                       GNUNET_MESSAGE_TYPE_DUMMY2);
218   GNUNET_MQ_send(cmq,
219                  env);
220 }
221
222
223 /**
224  * Callback to be called when a client connects to the service.
225  *
226  * @param cls closure for the service
227  * @param c the new client that connected to the service
228  * @param mq the message queue used to send messages to the client
229  * @return the client-specific (`internal') closure
230  */
231 static void *
232 connect_cb(void *cls,
233            struct GNUNET_SERVICE_Client *c,
234            struct GNUNET_MQ_Handle *mq)
235 {
236   (void)cls;
237   (void)mq;
238   return c;
239 }
240
241
242 /**
243  * Callback to be called when a client disconnected from the service
244  *
245  * @param cls closure for the service
246  * @param c the client that disconnected
247  * @param internal_cls the client-specific (`internal') closure
248  */
249 static void
250 disconnect_cb(void *cls,
251               struct GNUNET_SERVICE_Client *c,
252               void *internal_cls)
253 {
254   (void)cls;
255   (void)c;
256   (void)internal_cls;
257 }
258
259
260 static void
261 test1()
262 {
263   struct GNUNET_MQ_Envelope *mqm;
264   struct MyMessage *mm;
265
266   mm = NULL;
267   mqm = NULL;
268
269   mqm = GNUNET_MQ_msg(mm,
270                       GNUNET_MESSAGE_TYPE_DUMMY);
271   GNUNET_assert(NULL != mqm);
272   GNUNET_assert(NULL != mm);
273   GNUNET_assert(GNUNET_MESSAGE_TYPE_DUMMY == ntohs(mm->header.type));
274   GNUNET_assert(sizeof(struct MyMessage) == ntohs(mm->header.size));
275   GNUNET_MQ_discard(mqm);
276 }
277
278
279 static void
280 test2()
281 {
282   struct GNUNET_MQ_Envelope *mqm;
283   struct GNUNET_MessageHeader *mh;
284
285   mqm = GNUNET_MQ_msg_header(GNUNET_MESSAGE_TYPE_DUMMY);
286   /* how could the above be checked? */
287
288   GNUNET_MQ_discard(mqm);
289
290   mqm = GNUNET_MQ_msg_header_extra(mh,
291                                    20,
292                                    GNUNET_MESSAGE_TYPE_DUMMY);
293   GNUNET_assert(GNUNET_MESSAGE_TYPE_DUMMY == ntohs(mh->type));
294   GNUNET_assert(sizeof(struct GNUNET_MessageHeader) + 20 == ntohs(mh->size));
295   GNUNET_MQ_discard(mqm);
296 }
297
298
299 int
300 main(int argc, char **argv)
301 {
302   char * test_argv[] = {
303     (char *)"test_client",
304     "-c",
305     "test_client_data.conf",
306     NULL
307   };
308   struct GNUNET_MQ_MessageHandler mh[] = {
309     GNUNET_MQ_hd_fixed_size(dummy,
310                             GNUNET_MESSAGE_TYPE_DUMMY,
311                             struct MyMessage,
312                             NULL),
313     GNUNET_MQ_hd_fixed_size(dummy2,
314                             GNUNET_MESSAGE_TYPE_DUMMY2,
315                             struct MyMessage,
316                             NULL),
317     GNUNET_MQ_handler_end()
318   };
319
320   (void)argc;
321   (void)argv;
322   GNUNET_log_setup("test-mq",
323                    "INFO",
324                    NULL);
325   test1();
326   test2();
327   if (0 !=
328       GNUNET_SERVICE_run_(3,
329                           test_argv,
330                           "test_client",
331                           GNUNET_SERVICE_OPTION_NONE,
332                           &run,
333                           &connect_cb,
334                           &disconnect_cb,
335                           NULL,
336                           mh))
337     return 1;
338   return global_ret;
339 }