- run test_mesh_regex by default
[oweals/gnunet.git] / src / mesh / test_mesh_regex.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/test_mesh_regex.c
22  *
23  * @brief Test for regex announce / by_string connect.
24  * based on the 2dtorus testcase
25  */
26 #include "platform.h"
27 #include "gnunet_testing_lib.h"
28 #include "gnunet_mesh_service.h"
29
30 #define VERBOSE GNUNET_YES
31 #define REMOVE_DIR GNUNET_YES
32
33 /**
34  * How long until we give up on connecting the peers?
35  */
36 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
37
38 /**
39  * Time to wait for stuff that should be rather fast
40  */
41 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
42
43
44 /**
45  * How many events have happened
46  */
47 static int ok;
48
49 /**
50  * Be verbose
51  */
52 static int verbose;
53
54 /**
55  * Total number of peers in the test.
56  */
57 static unsigned long long num_peers;
58
59 /**
60  * Global configuration file
61  */
62 static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
63
64 /**
65  * Total number of currently running peers.
66  */
67 static unsigned long long peers_running;
68
69 /**
70  * Total number of successful connections in the whole network.
71  */
72 static unsigned int total_connections;
73
74 /**
75  * Total number of failed connections in the whole network.
76  */
77 static unsigned int failed_connections;
78
79 /**
80  * The currently running peer group.
81  */
82 static struct GNUNET_TESTING_PeerGroup *pg;
83
84 /**
85  * Task called to disconnect peers
86  */
87 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
88
89 /**
90  * Task called to shutdown test.
91  */
92 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
93
94
95 static struct GNUNET_TESTING_Daemon *d1;
96
97 static struct GNUNET_TESTING_Daemon *d2;
98
99 static struct GNUNET_MESH_Handle *h1;
100
101 static struct GNUNET_MESH_Handle *h2;
102
103 static struct GNUNET_MESH_Tunnel *t;
104
105 static struct GNUNET_MESH_Tunnel *incoming_t;
106
107 /**
108  * Check whether peers successfully shut down.
109  *
110  * @param cls Closure (unused).
111  * @param emsg Error message, NULL on success.
112  */
113 static void
114 shutdown_callback (void *cls, const char *emsg)
115 {
116   if (emsg != NULL)
117   {
118     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
119                 "test: Shutdown of peers failed! (%s)\n", emsg);
120     ok = GNUNET_NO;
121   }
122 #if VERBOSE
123   else
124   {
125     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
126                 "test: All peers successfully shut down!\n");
127   }
128 #endif
129   GNUNET_CONFIGURATION_destroy (testing_cfg);
130 }
131
132
133 /**
134  * Task to run for shutdown: stops peers, ends test.
135  *
136  * @param cls Closure (not used).
137  * @param tc TaskContext.
138  *
139  */
140 static void
141 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
142 {
143 #if VERBOSE
144   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n");
145 #endif
146   shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
147   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
148 }
149
150
151 /**
152  * Ends test: Disconnects peers and calls shutdown.
153  * @param cls Closure (not used).
154  * @param tc TaskContext. 
155  */
156 static void
157 disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
158 {
159     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
160               "************************************************\n");
161     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n");
162
163   GNUNET_MESH_tunnel_destroy (t);
164   GNUNET_MESH_disconnect (h1);
165   GNUNET_MESH_disconnect (h2);
166   if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
167   {
168     GNUNET_SCHEDULER_cancel (shutdown_handle);
169   }
170   shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
171 }
172
173 /**
174  * Function called whenever an inbound tunnel is destroyed.  Should clean up
175  * any associated state.
176  *
177  * @param cls closure (set from GNUNET_MESH_connect)
178  * @param tunnel connection to the other end (henceforth invalid)
179  * @param tunnel_ctx place where local state associated
180  *                   with the tunnel is stored
181  */
182 static void
183 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
184                 void *tunnel_ctx)
185 {
186   long i = (long) cls;
187
188   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
189               "Incoming tunnel disconnected at peer %d\n",
190               i);
191   return;
192 }
193
194
195 /**
196  * Method called whenever a tunnel falls apart.
197  *
198  * @param cls closure
199  * @param peer peer identity the tunnel stopped working with
200  */
201 static void
202 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
203 {
204   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205               "peer %s disconnected\n",
206               GNUNET_i2s (peer));
207   return;
208 }
209
210
211 /**
212  * Method called whenever a peer connects to a tunnel.
213  *
214  * @param cls closure
215  * @param peer peer identity the tunnel was created to, NULL on timeout
216  * @param atsi performance data for the connection
217  */
218 static void
219 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
220     const struct GNUNET_ATS_Information *atsi)
221 {
222   long i = (long) cls;
223
224   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
225               "************************************************************\n");
226   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
227               "Peer connected: %s\n",
228               GNUNET_i2s (peer));
229
230   if (i != 1L || peer == NULL)
231     ok = GNUNET_NO;
232   else
233     ok = GNUNET_OK;
234   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
235   {
236     GNUNET_SCHEDULER_cancel (disconnect_task);
237     disconnect_task =
238         GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL);
239   } 
240 }
241
242 /**
243  * Method called whenever another peer has added us to a tunnel
244  * the other peer initiated.
245  *
246  * @param cls closure
247  * @param tunnel new handle to the tunnel
248  * @param initiator peer that started the tunnel
249  * @param atsi performance information for the tunnel
250  * @return initial tunnel context for the tunnel
251  *         (can be NULL -- that's not an error)
252  */
253 static void *
254 incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
255                  const struct GNUNET_PeerIdentity *initiator,
256                  const struct GNUNET_ATS_Information *atsi)
257 {
258   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
259               "Incoming tunnel from %s to peer %d\n",
260               GNUNET_i2s (initiator), (long) cls);
261 //   ok++;
262   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
263   if ((long) cls == 2L)
264     incoming_t = tunnel;
265   else
266   {
267     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
268                 "Incoming tunnel for unknown client %lu\n", (long) cls);
269   }
270   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
271   {
272     GNUNET_SCHEDULER_cancel (disconnect_task);
273     disconnect_task =
274         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL);
275   }
276   return NULL;
277 }
278
279 /**
280  * Function is called whenever a message is received.
281  *
282  * @param cls closure (set from GNUNET_MESH_connect)
283  * @param tunnel connection to the other end
284  * @param tunnel_ctx place to store local state associated with the tunnel
285  * @param sender who sent the message
286  * @param message the actual message
287  * @param atsi performance data for the connection
288  * @return GNUNET_OK to keep the connection open,
289  *         GNUNET_SYSERR to close it (signal serious error)
290  */
291 int
292 data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
293                const struct GNUNET_PeerIdentity *sender,
294                const struct GNUNET_MessageHeader *message,
295                const struct GNUNET_ATS_Information *atsi)
296 {
297
298     return GNUNET_OK;
299 }
300
301 /**
302  * Handlers, for diverse services
303  */
304 static struct GNUNET_MESH_MessageHandler handlers[] = {
305   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
306   {NULL, 0, 0}
307 };
308
309
310 /**
311  * peergroup_ready: start test when all peers are connected
312  * @param cls closure
313  * @param emsg error message
314  */
315 static void
316 peergroup_ready (void *cls, const char *emsg)
317 {
318   GNUNET_MESH_ApplicationType app;
319
320   if (emsg != NULL)
321   {
322     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323                 "test: Peergroup callback called with error, aborting test!\n");
324     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n",
325                 emsg);
326     ok = GNUNET_NO;
327     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
328     return;
329   }
330 #if VERBOSE
331   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
332               "************************************************************\n");
333   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
334               "test: Peer Group started successfully!\n");
335   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test: Have %u connections\n",
336               total_connections);
337 #endif
338
339   peers_running = GNUNET_TESTING_daemons_running (pg);
340   if (0 < failed_connections)
341   {
342     ok = GNUNET_NO;
343     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n",
344                 failed_connections);
345     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL);
346     return;
347   }
348   disconnect_task =
349     GNUNET_SCHEDULER_add_delayed (TIMEOUT, &disconnect_peers, NULL);
350   d1 = GNUNET_TESTING_daemon_get (pg, 1);
351   d2 = GNUNET_TESTING_daemon_get (pg, 10);
352   app = (GNUNET_MESH_ApplicationType) 0;
353
354   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
355               "************************************************************\n");
356   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
357               "Connect to mesh\n");
358   h1 = GNUNET_MESH_connect (d1->cfg, 5, (void *) 1L,
359                             NULL,
360                             NULL,
361                             handlers,
362                             &app);
363   h2 = GNUNET_MESH_connect (d2->cfg, 5, (void *) 2L,
364                             &incoming_tunnel,
365                             &tunnel_cleaner,
366                             handlers,
367                             &app);
368   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
369               "************************************************************\n");
370   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
371               "Announce REGEX\n");
372   GNUNET_MESH_announce_regex (h2, "abc");
373
374   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
375               "************************************************************\n");
376   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
377               "Create tunnel\n");
378   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L);
379   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
380               "************************************************************\n");
381   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
382               "Connect by string\n");
383   GNUNET_MESH_peer_request_connect_by_string (t, "abc");
384   /* connect handler = success, timeout = error */
385   
386 }
387
388
389 /**
390  * Function that will be called whenever two daemons are connected by
391  * the testing library.
392  *
393  * @param cls closure
394  * @param first peer id for first daemon
395  * @param second peer id for the second daemon
396  * @param distance distance between the connected peers
397  * @param first_cfg config for the first daemon
398  * @param second_cfg config for the second daemon
399  * @param first_daemon handle for the first daemon
400  * @param second_daemon handle for the second daemon
401  * @param emsg error message (NULL on success)
402  */
403 static void
404 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
405             const struct GNUNET_PeerIdentity *second, uint32_t distance,
406             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
407             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
408             struct GNUNET_TESTING_Daemon *first_daemon,
409             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
410 {
411   if (emsg == NULL)
412   {
413     total_connections++;
414   }
415   else
416   {
417     failed_connections++;
418     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419                 "test: Problem with new connection (%s)\n", emsg);
420     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:   (%s)\n", GNUNET_i2s (first));
421     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:   (%s)\n", GNUNET_i2s (second));
422   }
423 }
424
425
426 /**
427  * run: load configuration options and schedule test to run (start peergroup)
428  * @param cls closure
429  * @param args argv
430  * @param cfgfile configuration file name (can be NULL)
431  * @param cfg configuration handle
432  */
433 static void
434 run (void *cls, char *const *args, const char *cfgfile,
435      const struct GNUNET_CONFIGURATION_Handle *cfg)
436 {
437   struct GNUNET_TESTING_Host *hosts;
438
439   ok = GNUNET_NO;
440   total_connections = 0;
441   failed_connections = 0;
442   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
443
444   GNUNET_log_setup ("test_mesh_regex",
445 #if VERBOSE
446                     "DEBUG",
447 #else
448                     "WARNING",
449 #endif
450                     NULL);
451
452 #if VERBOSE
453   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n");
454   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing_old",
455                                          "use_progressbars", "YES");
456 #endif
457
458   if (GNUNET_OK !=
459       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing_old",
460                                              "num_peers", &num_peers))
461   {
462     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
463                 "Option TESTING:NUM_PEERS is required!\n");
464     return;
465   }
466
467   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
468
469   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
470                                        &connect_cb, &peergroup_ready, NULL,
471                                        hosts);
472   GNUNET_assert (pg != NULL);
473   shutdown_handle =
474     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
475                                     &shutdown_task, NULL);
476 }
477
478
479 /**
480  * test_mesh_regex command line options
481  */
482 static struct GNUNET_GETOPT_CommandLineOption options[] = {
483   {'V', "verbose", NULL,
484    gettext_noop ("be verbose (print progress information)"),
485    0, &GNUNET_GETOPT_set_one, &verbose},
486   GNUNET_GETOPT_OPTION_END
487 };
488
489
490 /**
491  * Main: start test
492  */
493 int
494 main (int argc, char *argv[])
495 {
496   char *const argv2[] = {
497     argv[0],
498     "-c",
499     "test_mesh_2dtorus.conf",
500 #if VERBOSE
501     "-L",
502     "DEBUG",
503 #endif
504     NULL
505   };
506
507   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n");
508
509
510   GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
511                       "test_mesh_regex",
512                       gettext_noop ("Test mesh regex integration."),
513                       options, &run, NULL);
514 #if REMOVE_DIR
515   GNUNET_DISK_directory_remove ("/tmp/test_mesh_2dtorus");
516 #endif
517   if (GNUNET_OK != ok)
518   {
519     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED! (ok = %d)\n", ok);
520     return 1;
521   }
522   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n");
523   return 0;
524 }
525
526 /* end of test_mesh_regex.c */