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