- dont run regex test until mesh_new is made 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, "test: disconnecting peers\n");
160
161   GNUNET_MESH_tunnel_destroy (t);
162   GNUNET_MESH_disconnect (h1);
163   GNUNET_MESH_disconnect (h2);
164   if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle)
165   {
166     GNUNET_SCHEDULER_cancel (shutdown_handle);
167   }
168   shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
169 }
170
171 /**
172  * Function called whenever an inbound tunnel is destroyed.  Should clean up
173  * any associated state.
174  *
175  * @param cls closure (set from GNUNET_MESH_connect)
176  * @param tunnel connection to the other end (henceforth invalid)
177  * @param tunnel_ctx place where local state associated
178  *                   with the tunnel is stored
179  */
180 static void
181 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
182                 void *tunnel_ctx)
183 {
184   long i = (long) cls;
185
186   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
187               "Incoming tunnel disconnected at peer %d\n",
188               i);
189   return;
190 }
191
192
193 /**
194  * Method called whenever a tunnel falls apart.
195  *
196  * @param cls closure
197  * @param peer peer identity the tunnel stopped working with
198  */
199 static void
200 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
201 {
202   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
203               "peer %s disconnected\n",
204               GNUNET_i2s (peer));
205   return;
206 }
207
208
209 /**
210  * Method called whenever a peer connects to a tunnel.
211  *
212  * @param cls closure
213  * @param peer peer identity the tunnel was created to, NULL on timeout
214  * @param atsi performance data for the connection
215  */
216 static void
217 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
218     const struct GNUNET_ATS_Information *atsi)
219 {
220   long i = (long) cls;
221
222   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
223               "Peer connected: %s\n",
224               GNUNET_i2s (peer));
225
226   if (i != 1L || peer == NULL)
227     ok = GNUNET_NO;
228   else
229     ok = GNUNET_OK;
230   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
231   {
232     GNUNET_SCHEDULER_cancel (disconnect_task);
233     disconnect_task =
234         GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL);
235   } 
236 }
237
238 /**
239  * Method called whenever another peer has added us to a tunnel
240  * the other peer initiated.
241  *
242  * @param cls closure
243  * @param tunnel new handle to the tunnel
244  * @param initiator peer that started the tunnel
245  * @param atsi performance information for the tunnel
246  * @return initial tunnel context for the tunnel
247  *         (can be NULL -- that's not an error)
248  */
249 static void *
250 incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
251                  const struct GNUNET_PeerIdentity *initiator,
252                  const struct GNUNET_ATS_Information *atsi)
253 {
254   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
255               "Incoming tunnel from %s to peer %d\n",
256               GNUNET_i2s (initiator), (long) cls);
257 //   ok++;
258   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
259   if ((long) cls == 2L)
260     incoming_t = tunnel;
261   else
262   {
263     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
264                 "Incoming tunnel for unknown client %lu\n", (long) cls);
265   }
266   if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
267   {
268     GNUNET_SCHEDULER_cancel (disconnect_task);
269     disconnect_task =
270         GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL);
271   }
272   return NULL;
273 }
274
275 /**
276  * Function is called whenever a message is received.
277  *
278  * @param cls closure (set from GNUNET_MESH_connect)
279  * @param tunnel connection to the other end
280  * @param tunnel_ctx place to store local state associated with the tunnel
281  * @param sender who sent the message
282  * @param message the actual message
283  * @param atsi performance data for the connection
284  * @return GNUNET_OK to keep the connection open,
285  *         GNUNET_SYSERR to close it (signal serious error)
286  */
287 int
288 data_callback (void *cls, struct GNUNET_MESH_Tunnel *tunnel, void **tunnel_ctx,
289                const struct GNUNET_PeerIdentity *sender,
290                const struct GNUNET_MessageHeader *message,
291                const struct GNUNET_ATS_Information *atsi)
292 {
293
294     return GNUNET_OK;
295 }
296
297 /**
298  * Handlers, for diverse services
299  */
300 static struct GNUNET_MESH_MessageHandler handlers[] = {
301   {&data_callback, 1, sizeof (struct GNUNET_MessageHeader)},
302   {NULL, 0, 0}
303 };
304
305
306 /**
307  * peergroup_ready: start test when all peers are connected
308  * @param cls closure
309  * @param emsg error message
310  */
311 static void
312 peergroup_ready (void *cls, const char *emsg)
313 {
314   GNUNET_MESH_ApplicationType app;
315
316   if (emsg != NULL)
317   {
318     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
319                 "test: Peergroup callback called with error, aborting test!\n");
320     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error from testing: `%s'\n",
321                 emsg);
322     ok = GNUNET_NO;
323     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
324     return;
325   }
326 #if VERBOSE
327   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
328               "test: Peer Group started successfully!\n");
329   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test: Have %u connections\n",
330               total_connections);
331 #endif
332
333   peers_running = GNUNET_TESTING_daemons_running (pg);
334   if (0 < failed_connections)
335   {
336     ok = GNUNET_NO;
337     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n",
338                 failed_connections);
339     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL);
340     return;
341   }
342   disconnect_task =
343     GNUNET_SCHEDULER_add_delayed (TIMEOUT, &disconnect_peers, NULL);
344   d1 = GNUNET_TESTING_daemon_get (pg, 1);
345   d2 = GNUNET_TESTING_daemon_get (pg, 10);
346   app = (GNUNET_MESH_ApplicationType) 0;
347
348   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
349               "Connect to mesh\n");
350   h1 = GNUNET_MESH_connect (d1->cfg, 5, (void *) 1L,
351                             NULL,
352                             NULL,
353                             handlers,
354                             &app);
355   h2 = GNUNET_MESH_connect (d2->cfg, 5, (void *) 2L,
356                             &incoming_tunnel,
357                             &tunnel_cleaner,
358                             handlers,
359                             &app);
360   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
361               "Announce REGEX\n");
362   GNUNET_MESH_announce_regex (h2, "0123456789ABC");
363
364   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
365               "Create tunnel\n");
366   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L);
367   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
368               "Connect by string\n");
369   GNUNET_MESH_peer_request_connect_by_string (t, "01234567890ABC");
370   /* connect handler = success, timeout = error */
371   
372 }
373
374
375 /**
376  * Function that will be called whenever two daemons are connected by
377  * the testing library.
378  *
379  * @param cls closure
380  * @param first peer id for first daemon
381  * @param second peer id for the second daemon
382  * @param distance distance between the connected peers
383  * @param first_cfg config for the first daemon
384  * @param second_cfg config for the second daemon
385  * @param first_daemon handle for the first daemon
386  * @param second_daemon handle for the second daemon
387  * @param emsg error message (NULL on success)
388  */
389 static void
390 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
391             const struct GNUNET_PeerIdentity *second, uint32_t distance,
392             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
393             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
394             struct GNUNET_TESTING_Daemon *first_daemon,
395             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
396 {
397   if (emsg == NULL)
398   {
399     total_connections++;
400   }
401   else
402   {
403     failed_connections++;
404     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
405                 "test: Problem with new connection (%s)\n", emsg);
406     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:   (%s)\n", GNUNET_i2s (first));
407     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:   (%s)\n", GNUNET_i2s (second));
408   }
409 }
410
411
412 /**
413  * run: load configuration options and schedule test to run (start peergroup)
414  * @param cls closure
415  * @param args argv
416  * @param cfgfile configuration file name (can be NULL)
417  * @param cfg configuration handle
418  */
419 static void
420 run (void *cls, char *const *args, const char *cfgfile,
421      const struct GNUNET_CONFIGURATION_Handle *cfg)
422 {
423   struct GNUNET_TESTING_Host *hosts;
424
425   ok = GNUNET_NO;
426   total_connections = 0;
427   failed_connections = 0;
428   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
429
430   GNUNET_log_setup ("test_mesh_regex",
431 #if VERBOSE
432                     "DEBUG",
433 #else
434                     "WARNING",
435 #endif
436                     NULL);
437
438 #if VERBOSE
439   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n");
440   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing_old",
441                                          "use_progressbars", "YES");
442 #endif
443
444   if (GNUNET_OK !=
445       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing_old",
446                                              "num_peers", &num_peers))
447   {
448     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
449                 "Option TESTING:NUM_PEERS is required!\n");
450     return;
451   }
452
453   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
454
455   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
456                                        &connect_cb, &peergroup_ready, NULL,
457                                        hosts);
458   GNUNET_assert (pg != NULL);
459   shutdown_handle =
460     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
461                                     &shutdown_task, NULL);
462 }
463
464
465 /**
466  * test_mesh_regex command line options
467  */
468 static struct GNUNET_GETOPT_CommandLineOption options[] = {
469   {'V', "verbose", NULL,
470    gettext_noop ("be verbose (print progress information)"),
471    0, &GNUNET_GETOPT_set_one, &verbose},
472   GNUNET_GETOPT_OPTION_END
473 };
474
475
476 /**
477  * Main: start test
478  */
479 int
480 main (int argc, char *argv[])
481 {
482   char *const argv2[] = {
483     argv[0],
484     "-c",
485     "test_mesh_2dtorus.conf",
486 #if VERBOSE
487     "-L",
488     "DEBUG",
489 #endif
490     NULL
491   };
492
493   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n");
494
495
496   GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
497                       "test_mesh_regex",
498                       gettext_noop ("Test mesh regex integration."),
499                       options, &run, NULL);
500 #if REMOVE_DIR
501   GNUNET_DISK_directory_remove ("/tmp/test_mesh_2dtorus");
502 #endif
503   if (GNUNET_OK != ok)
504   {
505     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED! (ok = %d)\n", ok);
506     return 1;
507   }
508   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n");
509   return 0;
510 }
511
512 /* end of test_mesh_regex.c */