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