glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / cadet / cadet_test_lib.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2017 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  * @file cadet/cadet_test_lib.c
17  * @author Bartlomiej Polot
18  * @brief library for writing CADET tests
19  */
20 #include "platform.h"
21 #include "gnunet_util_lib.h"
22 #include "cadet_test_lib.h"
23 #include "gnunet_cadet_service.h"
24
25
26 /**
27  * Test context for a CADET Test.
28  */
29 struct GNUNET_CADET_TEST_Context
30 {
31   /**
32    * Array of running peers.
33    */
34   struct GNUNET_TESTBED_Peer **peers;
35
36   /**
37    * Array of handles to the CADET for each peer.
38    */
39   struct GNUNET_CADET_Handle **cadets;
40
41   /**
42    * Operation associated with the connection to the CADET.
43    */
44   struct GNUNET_TESTBED_Operation **ops;
45
46   /**
47    * Number of peers running, size of the arrays above.
48    */
49   unsigned int num_peers;
50
51   /**
52    * Main function of the test to run once all CADETs are available.
53    */
54   GNUNET_CADET_TEST_AppMain app_main;
55
56   /**
57    * Closure for 'app_main'.
58    */
59   void *app_main_cls;
60
61   /**
62    * Handler for incoming tunnels.
63    */
64   GNUNET_CADET_ConnectEventHandler connects;
65
66   /**
67    * Function called when the transmit window size changes.
68    */
69   GNUNET_CADET_WindowSizeEventHandler window_changes;
70
71   /**
72    * Cleaner for destroyed incoming tunnels.
73    */
74   GNUNET_CADET_DisconnectEventHandler disconnects;
75
76   /**
77    * Message handlers.
78    */
79   struct GNUNET_MQ_MessageHandler *handlers;
80
81   /**
82    * Application ports.
83    */
84   const struct GNUNET_HashCode **ports;
85
86   /**
87    * Number of ports in #ports.
88    */
89   unsigned int port_count;
90
91 };
92
93
94 /**
95  * Context for a cadet adapter callback.
96  */
97 struct GNUNET_CADET_TEST_AdapterContext
98 {
99   /**
100    * Peer number for the particular peer.
101    */
102   unsigned int peer;
103
104   /**
105    * Port handlers for open ports.
106    */
107   struct GNUNET_CADET_Port **ports;
108
109   /**
110    * General context.
111    */
112   struct GNUNET_CADET_TEST_Context *ctx;
113 };
114
115
116 /**
117  * Adapter function called to establish a connection to
118  * the CADET service.
119  *
120  * @param cls closure
121  * @param cfg configuration of the peer to connect to; will be available until
122  *          GNUNET_TESTBED_operation_done() is called on the operation returned
123  *          from GNUNET_TESTBED_service_connect()
124  * @return service handle to return in 'op_result', NULL on error
125  */
126 static void *
127 cadet_connect_adapter (void *cls,
128                        const struct GNUNET_CONFIGURATION_Handle *cfg)
129 {
130   struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
131   struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
132   struct GNUNET_CADET_Handle *h;
133
134   h = GNUNET_CADET_connect (cfg);
135   if (NULL == ctx->ports)
136     return h;
137   actx->ports = GNUNET_new_array (ctx->port_count,
138                                   struct GNUNET_CADET_Port *);
139   for (unsigned int i = 0; i < ctx->port_count; i++)
140   {
141     actx->ports[i] = GNUNET_CADET_open_port (h,
142                                              ctx->ports[i],
143                                              ctx->connects,
144                                              (void *) (long) actx->peer,
145                                              ctx->window_changes,
146                                              ctx->disconnects,
147                                              ctx->handlers);
148   }
149   return h;
150 }
151
152
153 /**
154  * Adapter function called to destroy a connection to
155  * the CADET service.
156  *
157  * @param cls closure
158  * @param op_result service handle returned from the connect adapter
159  */
160 static void
161 cadet_disconnect_adapter (void *cls,
162                           void *op_result)
163 {
164   struct GNUNET_CADET_Handle *cadet = op_result;
165   struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
166
167   if (NULL != actx->ports)
168   {
169     for (unsigned int i = 0; i < actx->ctx->port_count; i++)
170     {
171       GNUNET_CADET_close_port (actx->ports[i]);
172       actx->ports[i] = NULL;
173     }
174     GNUNET_free (actx->ports);
175   }
176   GNUNET_free (actx);
177   GNUNET_CADET_disconnect (cadet);
178 }
179
180
181 /**
182  * Callback to be called when a service connect operation is completed.
183  *
184  * @param cls The callback closure from functions generating an operation.
185  * @param op The operation that has been finished.
186  * @param ca_result The service handle returned from
187  *                  GNUNET_TESTBED_ConnectAdapter() (cadet handle).
188  * @param emsg Error message in case the operation has failed.
189  *             NULL if operation has executed successfully.
190  */
191 static void
192 cadet_connect_cb (void *cls,
193                  struct GNUNET_TESTBED_Operation *op,
194                  void *ca_result,
195                  const char *emsg)
196 {
197   struct GNUNET_CADET_TEST_Context *ctx = cls;
198
199   if (NULL != emsg)
200   {
201     fprintf (stderr,
202              "Failed to connect to CADET service: %s\n",
203              emsg);
204     GNUNET_SCHEDULER_shutdown ();
205     return;
206   }
207   for (unsigned int i = 0; i < ctx->num_peers; i++)
208     if (op == ctx->ops[i])
209     {
210       ctx->cadets[i] = ca_result;
211       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
212                   "...cadet %u connected\n",
213                   i);
214     }
215   for (unsigned int i = 0; i < ctx->num_peers; i++)
216     if (NULL == ctx->cadets[i])
217       return; /* still some CADET connections missing */
218   /* all CADET connections ready! */
219   ctx->app_main (ctx->app_main_cls,
220                  ctx,
221                  ctx->num_peers,
222                  ctx->peers,
223                  ctx->cadets);
224 }
225
226
227 void
228 GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
229 {
230   for (unsigned int i = 0; i < ctx->num_peers; i++)
231   {
232     GNUNET_assert (NULL != ctx->ops[i]);
233     GNUNET_TESTBED_operation_done (ctx->ops[i]);
234     ctx->ops[i] = NULL;
235   }
236   GNUNET_free (ctx->ops);
237   GNUNET_free (ctx->cadets);
238   GNUNET_free (ctx->handlers);
239   GNUNET_free (ctx);
240   GNUNET_SCHEDULER_shutdown ();
241 }
242
243
244 /**
245  * Callback run when the testbed is ready (peers running and connected to
246  * each other)
247  *
248  * @param cls Closure (context).
249  * @param h the run handle
250  * @param num_peers Number of peers that are running.
251  * @param peers Handles to each one of the @c num_peers peers.
252  * @param links_succeeded the number of overlay link connection attempts that
253  *          succeeded
254  * @param links_failed the number of overlay link connection attempts that
255  *          failed
256  */
257 static void
258 cadet_test_run (void *cls,
259                struct GNUNET_TESTBED_RunHandle *h,
260                unsigned int num_peers,
261                struct GNUNET_TESTBED_Peer **peers,
262                unsigned int links_succeeded,
263                unsigned int links_failed)
264 {
265   struct GNUNET_CADET_TEST_Context *ctx = cls;
266
267   if (0 != links_failed)
268   {
269     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
270                 "Some links failed (%u), ending\n",
271                 links_failed);
272     exit (2);
273   }
274   if  (num_peers != ctx->num_peers)
275   {
276     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
277                 "Peers started %u/%u, ending\n",
278                 num_peers,
279                 ctx->num_peers);
280     exit (1);
281   }
282   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283               "Testbed up, %u peers and %u links\n",
284               num_peers,
285               links_succeeded);
286   ctx->peers = peers;
287   for (unsigned int i = 0; i < num_peers; i++)
288   {
289     struct GNUNET_CADET_TEST_AdapterContext *newctx;
290
291     newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
292     newctx->peer = i;
293     newctx->ctx = ctx;
294     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
295                 "Connecting to cadet %u\n",
296                 i);
297     ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
298                                                   peers[i],
299                                                   "cadet",
300                                                   &cadet_connect_cb,
301                                                   ctx,
302                                                   &cadet_connect_adapter,
303                                                   &cadet_disconnect_adapter,
304                                                   newctx);
305     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
306                 "op handle %p\n",
307                 ctx->ops[i]);
308   }
309 }
310
311
312 /**
313  * Run a test using the given name, configuration file and number of peers.
314  * All cadet callbacks will receive the peer number (long) as the closure.
315  *
316  * @param testname Name of the test (for logging).
317  * @param cfgfile Name of the configuration file.
318  * @param num_peers Number of peers to start.
319  * @param tmain Main function to run once the testbed is ready.
320  * @param tmain_cls Closure for @a tmain.
321  * @param connects Handler for incoming channels.
322  * @param window_changes Handler for the window size change notification.
323  * @param disconnects Cleaner for destroyed incoming channels.
324  * @param handlers Message handlers.
325  * @param ports Ports the peers offer, NULL-terminated.
326  */
327 void
328 GNUNET_CADET_TEST_ruN (const char *testname,
329                        const char *cfgfile,
330                        unsigned int num_peers,
331                        GNUNET_CADET_TEST_AppMain tmain,
332                        void *tmain_cls,
333                        GNUNET_CADET_ConnectEventHandler connects,
334                        GNUNET_CADET_WindowSizeEventHandler window_changes,
335                        GNUNET_CADET_DisconnectEventHandler disconnects,
336                        struct GNUNET_MQ_MessageHandler *handlers,
337                        const struct GNUNET_HashCode **ports)
338 {
339   struct GNUNET_CADET_TEST_Context *ctx;
340
341   ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
342   ctx->num_peers = num_peers;
343   ctx->ops = GNUNET_new_array (num_peers,
344                                struct GNUNET_TESTBED_Operation *);
345   ctx->cadets = GNUNET_new_array (num_peers,
346                                   struct GNUNET_CADET_Handle *);
347   ctx->app_main = tmain;
348   ctx->app_main_cls = tmain_cls;
349   ctx->connects = connects;
350   ctx->window_changes = window_changes;
351   ctx->disconnects = disconnects;
352   ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
353   ctx->ports = ports;
354   ctx->port_count = 0;
355   while (NULL != ctx->ports[ctx->port_count])
356     ctx->port_count++;
357   GNUNET_TESTBED_test_run (testname,
358                            cfgfile,
359                            num_peers,
360                            0LL, NULL, NULL,
361                            &cadet_test_run,
362                            ctx);
363 }
364
365 /* end of cadet_test_lib.c */