paragraph for gnunet devs that don't know how to use the web
[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 == ctx->ports)
139     return h;
140   actx->ports = GNUNET_new_array (ctx->port_count,
141                                   struct GNUNET_CADET_Port *);
142   for (unsigned int i = 0; i < ctx->port_count; i++)
143   {
144     actx->ports[i] = GNUNET_CADET_open_port (h,
145                                              ctx->ports[i],
146                                              ctx->connects,
147                                              (void *) (long) actx->peer,
148                                              ctx->window_changes,
149                                              ctx->disconnects,
150                                              ctx->handlers);
151   }
152   return h;
153 }
154
155
156 /**
157  * Adapter function called to destroy a connection to
158  * the CADET service.
159  *
160  * @param cls closure
161  * @param op_result service handle returned from the connect adapter
162  */
163 static void
164 cadet_disconnect_adapter (void *cls,
165                           void *op_result)
166 {
167   struct GNUNET_CADET_Handle *cadet = op_result;
168   struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
169
170   if (NULL != actx->ports)
171   {
172     for (unsigned int i = 0; i < actx->ctx->port_count; i++)
173     {
174       GNUNET_CADET_close_port (actx->ports[i]);
175       actx->ports[i] = NULL;
176     }
177     GNUNET_free (actx->ports);
178   }
179   GNUNET_free (actx);
180   GNUNET_CADET_disconnect (cadet);
181 }
182
183
184 /**
185  * Callback to be called when a service connect operation is completed.
186  *
187  * @param cls The callback closure from functions generating an operation.
188  * @param op The operation that has been finished.
189  * @param ca_result The service handle returned from
190  *                  GNUNET_TESTBED_ConnectAdapter() (cadet handle).
191  * @param emsg Error message in case the operation has failed.
192  *             NULL if operation has executed successfully.
193  */
194 static void
195 cadet_connect_cb (void *cls,
196                  struct GNUNET_TESTBED_Operation *op,
197                  void *ca_result,
198                  const char *emsg)
199 {
200   struct GNUNET_CADET_TEST_Context *ctx = cls;
201
202   if (NULL != emsg)
203   {
204     fprintf (stderr,
205              "Failed to connect to CADET service: %s\n",
206              emsg);
207     GNUNET_SCHEDULER_shutdown ();
208     return;
209   }
210   for (unsigned int i = 0; i < ctx->num_peers; i++)
211     if (op == ctx->ops[i])
212     {
213       ctx->cadets[i] = ca_result;
214       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
215                   "...cadet %u connected\n",
216                   i);
217     }
218   for (unsigned int i = 0; i < ctx->num_peers; i++)
219     if (NULL == ctx->cadets[i])
220       return; /* still some CADET connections missing */
221   /* all CADET connections ready! */
222   ctx->app_main (ctx->app_main_cls,
223                  ctx,
224                  ctx->num_peers,
225                  ctx->peers,
226                  ctx->cadets);
227 }
228
229
230 void
231 GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
232 {
233   for (unsigned int i = 0; i < ctx->num_peers; i++)
234   {
235     GNUNET_assert (NULL != ctx->ops[i]);
236     GNUNET_TESTBED_operation_done (ctx->ops[i]);
237     ctx->ops[i] = NULL;
238   }
239   GNUNET_free (ctx->ops);
240   GNUNET_free (ctx->cadets);
241   GNUNET_free (ctx->handlers);
242   GNUNET_free (ctx);
243   GNUNET_SCHEDULER_shutdown ();
244 }
245
246
247 /**
248  * Callback run when the testbed is ready (peers running and connected to
249  * each other)
250  *
251  * @param cls Closure (context).
252  * @param h the run handle
253  * @param num_peers Number of peers that are running.
254  * @param peers Handles to each one of the @c num_peers peers.
255  * @param links_succeeded the number of overlay link connection attempts that
256  *          succeeded
257  * @param links_failed the number of overlay link connection attempts that
258  *          failed
259  */
260 static void
261 cadet_test_run (void *cls,
262                struct GNUNET_TESTBED_RunHandle *h,
263                unsigned int num_peers,
264                struct GNUNET_TESTBED_Peer **peers,
265                unsigned int links_succeeded,
266                unsigned int links_failed)
267 {
268   struct GNUNET_CADET_TEST_Context *ctx = cls;
269
270   if (0 != links_failed)
271   {
272     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
273                 "Some links failed (%u), ending\n",
274                 links_failed);
275     exit (2);
276   }
277   if  (num_peers != ctx->num_peers)
278   {
279     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
280                 "Peers started %u/%u, ending\n",
281                 num_peers,
282                 ctx->num_peers);
283     exit (1);
284   }
285   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286               "Testbed up, %u peers and %u links\n",
287               num_peers,
288               links_succeeded);
289   ctx->peers = peers;
290   for (unsigned int i = 0; i < num_peers; i++)
291   {
292     struct GNUNET_CADET_TEST_AdapterContext *newctx;
293
294     newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
295     newctx->peer = i;
296     newctx->ctx = ctx;
297     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
298                 "Connecting to cadet %u\n",
299                 i);
300     ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
301                                                   peers[i],
302                                                   "cadet",
303                                                   &cadet_connect_cb,
304                                                   ctx,
305                                                   &cadet_connect_adapter,
306                                                   &cadet_disconnect_adapter,
307                                                   newctx);
308     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
309                 "op handle %p\n",
310                 ctx->ops[i]);
311   }
312 }
313
314
315 /**
316  * Run a test using the given name, configuration file and number of peers.
317  * All cadet callbacks will receive the peer number (long) as the closure.
318  *
319  * @param testname Name of the test (for logging).
320  * @param cfgfile Name of the configuration file.
321  * @param num_peers Number of peers to start.
322  * @param tmain Main function to run once the testbed is ready.
323  * @param tmain_cls Closure for @a tmain.
324  * @param connects Handler for incoming channels.
325  * @param window_changes Handler for the window size change notification.
326  * @param disconnects Cleaner for destroyed incoming channels.
327  * @param handlers Message handlers.
328  * @param ports Ports the peers offer, NULL-terminated.
329  */
330 void
331 GNUNET_CADET_TEST_ruN (const char *testname,
332                        const char *cfgfile,
333                        unsigned int num_peers,
334                        GNUNET_CADET_TEST_AppMain tmain,
335                        void *tmain_cls,
336                        GNUNET_CADET_ConnectEventHandler connects,
337                        GNUNET_CADET_WindowSizeEventHandler window_changes,
338                        GNUNET_CADET_DisconnectEventHandler disconnects,
339                        struct GNUNET_MQ_MessageHandler *handlers,
340                        const struct GNUNET_HashCode **ports)
341 {
342   struct GNUNET_CADET_TEST_Context *ctx;
343
344   ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
345   ctx->num_peers = num_peers;
346   ctx->ops = GNUNET_new_array (num_peers,
347                                struct GNUNET_TESTBED_Operation *);
348   ctx->cadets = GNUNET_new_array (num_peers,
349                                   struct GNUNET_CADET_Handle *);
350   ctx->app_main = tmain;
351   ctx->app_main_cls = tmain_cls;
352   ctx->connects = connects;
353   ctx->window_changes = window_changes;
354   ctx->disconnects = disconnects;
355   ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
356   ctx->ports = ports;
357   ctx->port_count = 0;
358   while (NULL != ctx->ports[ctx->port_count])
359     ctx->port_count++;
360   GNUNET_TESTBED_test_run (testname,
361                            cfgfile,
362                            num_peers,
363                            0LL, NULL, NULL,
364                            &cadet_test_run,
365                            ctx);
366 }
367
368 /* end of cadet_test_lib.c */