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