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