- added mesh testing library
[oweals/gnunet.git] / src / mesh / mesh_test_lib.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file mesh/mesh_test_lib.c
22  * @author Bartlomiej Polot
23  * @brief library for writing MESH tests
24  */
25 #include "platform.h"
26 #include "mesh_test_lib.h"
27
28 /**
29  * Test context for a MESH Test.
30  */
31 struct GNUNET_MESH_TEST_Context
32 {
33   /**
34    * Array of running peers.
35    */
36   struct GNUNET_TESTBED_Peer **peers;
37
38   /**
39    * Array of handles to the MESH for each peer.
40    */
41   struct GNUNET_MESH_Handle **meshes;
42
43   /**
44    * Operation associated with the connection to the MESH.
45    */
46   struct GNUNET_TESTBED_Operation **ops;
47
48   /**
49    * Main function of the test to run once all MESHs are available.
50    */
51   GNUNET_MESH_TEST_AppMain app_main;
52   
53   /**
54    * Closure for 'app_main'.
55    */
56   void *app_main_cls;
57
58   /**
59    * Number of peers running, size of the arrays above.
60    */
61   unsigned int num_peers;
62
63   /**
64    * Handler for incoming tunnels.
65    */
66   GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel;
67
68   /**
69    * Cleaner for destroyed incoming tunnels.
70    */
71   GNUNET_MESH_TunnelEndHandler cleaner;
72
73   /**
74    * Message handlers.
75    */
76   GNUNET_MESH_MessageHandler* handlers;
77
78   /**
79    * Application types.
80    */
81   const GNUNET_MESH_ApplicationType* stypes;
82
83 };
84
85
86 /**
87  * Context for a mesh adapter callback.
88  */
89 struct GNUNET_MESH_TEST_AdapterContext
90 {
91   /**
92    * Peer number for the particular peer.
93    */
94   unsigned int peer;
95
96   /**
97    * General context.
98    */
99   struct GNUNET_MESH_TEST_Context *ctx;
100 };
101
102
103 /**
104  * Adapter function called to establish a connection to
105  * the MESH service.
106  *
107  * @param cls closure
108  * @param cfg configuration of the peer to connect to; will be available until
109  *          GNUNET_TESTBED_operation_done() is called on the operation returned
110  *          from GNUNET_TESTBED_service_connect()
111  * @return service handle to return in 'op_result', NULL on error
112  */
113 static void *
114 mesh_connect_adapter (void *cls,
115                       const struct GNUNET_CONFIGURATION_Handle *cfg)
116 {
117   struct GNUNET_MESH_TEST_AdapterContext *actx = cls;
118   struct GNUNET_MESH_TEST_Context *ctx = actx->ctx;
119   struct GNUNET_MESH_Handle *h;
120
121   h = GNUNET_MESH_connect (cfg,
122                            (void *) (long) actx->peer,
123                            ctx->new_tunnel,
124                            ctx->cleaner,
125                            ctx->handlers,
126                            ctx->stypes);
127   return h;
128 }
129
130
131 /**
132  * Adapter function called to destroy a connection to
133  * the MESH service.
134  *
135  * @param cls closure
136  * @param op_result service handle returned from the connect adapter
137  */
138 static void 
139 mesh_disconnect_adapter (void *cls,
140                          void *op_result)
141 {
142   struct GNUNET_MESH_Handle *mesh = op_result;
143   struct GNUNET_MESH_TEST_AdapterContext *actx = cls;
144
145   GNUNET_free (actx);
146   GNUNET_MESH_disconnect (mesh);
147 }
148
149
150 /**
151  * Callback to be called when a service connect operation is completed.
152  *
153  * @param cls The callback closure from functions generating an operation.
154  * @param op The operation that has been finished.
155  * @param ca_result The service handle returned from 
156  *                  GNUNET_TESTBED_ConnectAdapter() (mesh handle).
157  * @param emsg Error message in case the operation has failed.
158  *             NULL if operation has executed successfully.
159  */
160 static void 
161 mesh_connect_cb (void *cls,
162                  struct GNUNET_TESTBED_Operation *op,
163                  void *ca_result,
164                  const char *emsg)
165 {
166   struct GNUNET_MESH_TEST_Context *ctx = cls;
167   unsigned int i;
168  
169   if (NULL != emsg)
170   {
171     fprintf (stderr, "Failed to connect to MESH service: %s\n",
172              emsg);
173     GNUNET_SCHEDULER_shutdown ();
174     return;
175   }
176   for (i = 0; i < ctx->num_peers; i++)
177     if (op == ctx->ops[i])
178       ctx->meshes[i] = ca_result;
179   for (i = 0; i < ctx->num_peers; i++)
180     if (NULL == ctx->meshes[i])
181       return; /* still some MESH connections missing */
182   /* all MESH connections ready! */
183   ctx->app_main (ctx->app_main_cls,
184                  ctx,
185                  ctx->num_peers,
186                  ctx->peers,
187                  ctx->meshes);
188 }
189
190
191 /**
192  * Clean up the testbed.
193  *
194  * @param ctx handle for the testbed
195  */
196 void
197 GNUNET_MESH_TEST_cleanup (struct GNUNET_MESH_TEST_Context *ctx)
198 {
199   unsigned int i;
200
201   for (i = 0; i < ctx->num_peers; i++)
202     GNUNET_TESTBED_operation_done (ctx->ops[i]);
203   GNUNET_free (ctx->ops);
204   GNUNET_free (ctx->meshes);
205   GNUNET_free (ctx);
206   GNUNET_SCHEDULER_shutdown ();
207 }
208
209
210 /**
211  * Callback run when the testbed is ready (peers running and connected to
212  * each other)
213  * 
214  * @param cls Closure (context).
215  * @param num_peers Number of peers that are running.
216  * @param peers Handles to each one of the @c num_peers peers.
217  */
218 static void
219 mesh_test_run (void *cls,
220                unsigned int num_peers,
221                struct GNUNET_TESTBED_Peer **peers)
222 {
223   struct GNUNET_MESH_TEST_Context *ctx = cls;
224   unsigned int i;
225
226   GNUNET_assert (num_peers == ctx->num_peers);
227   ctx->peers = peers;
228   for (i = 0; i < num_peers; i++)
229   {
230     struct GNUNET_MESH_TEST_AdapterContext *newctx;
231     newctx = GNUNET_malloc (sizeof (struct GNUNET_MESH_TEST_AdapterContext));
232     newctx->peer = i;
233     newctx->ctx = ctx;
234     ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
235                                                   peers[i],
236                                                   "mesh",
237                                                   &mesh_connect_cb,
238                                                   ctx,
239                                                   &mesh_connect_adapter,
240                                                   &mesh_disconnect_adapter,
241                                                   newctx);
242   }
243 }
244
245
246 /**
247  * Run a test using the given name, configuration file and number of
248  * peers.
249  * All mesh callbacks will receive the peer number as the closure.
250  *
251  * @param testname Name of the test (for logging).
252  * @param cfgname Name of the configuration file.
253  * @param num_peers Number of peers to start.
254  * @param tmain Main function to run once the testbed is ready.
255  * @param tmain_cls Closure for 'tmain'.
256  * @param new_tunnel Handler for incoming tunnels.
257  * @param cleaner Cleaner for destroyed incoming tunnels.
258  * @param handlers Message handlers.
259  * @param stypes Application types.
260  */
261 void 
262 GNUNET_MESH_TEST_run (const char *testname,
263                       const char *cfgname,
264                       unsigned int num_peers,
265                       GNUNET_MESH_TEST_AppMain tmain,
266                       void *tmain_cls,
267                       GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel,
268                       GNUNET_MESH_TunnelEndHandler cleaner,
269                       GNUNET_MESH_MessageHandler* handlers,
270                       const GNUNET_MESH_ApplicationType* stypes)
271 {
272   struct GNUNET_MESH_TEST_Context *ctx;
273   
274   ctx = GNUNET_malloc (sizeof (struct GNUNET_MESH_TEST_Context));
275   ctx->num_peers = num_peers;
276   ctx->ops = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Operation *));
277   ctx->meshes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_MESH_Handle *));
278   ctx->app_main = tmain;
279   ctx->app_main_cls = tmain_cls;
280   ctx->new_tunnel = new_tunnel;
281   ctx->cleaner = cleaner;
282   ctx->handlers = handlers;
283   ctx->stypes = stypes;
284   GNUNET_TESTBED_test_run (testname,
285                            cfgname,
286                            num_peers,
287                            0LL, NULL, NULL,
288                            &mesh_test_run, ctx);
289 }
290
291 /* end of mesh_test_lib.c */