Small fix, improved comment
[oweals/gnunet.git] / src / mesh / test_mesh_small_unicast_far.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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_small_unicast_far.c
22  *
23  * @brief Test for the mesh service: unicast to opposite point of 2d grid.
24  */
25 #include "platform.h"
26 #include "gnunet_testing_lib.h"
27 #include "gnunet_mesh_service.h"
28
29 #define VERBOSE GNUNET_YES
30 #define REMOVE_DIR GNUNET_YES
31
32 struct MeshPeer
33 {
34   struct MeshPeer *prev;
35
36   struct MeshPeer *next;
37
38   struct GNUNET_TESTING_Daemon *daemon;
39
40   struct GNUNET_MESH_Handle *mesh_handle;
41 };
42
43
44 struct StatsContext
45 {
46   unsigned long long total_mesh_bytes;
47 };
48
49
50 // static struct MeshPeer *peer_head;
51 //
52 // static struct MeshPeer *peer_tail;
53
54 /**
55  * How long until we give up on connecting the peers?
56  */
57 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
58
59 static int ok;
60
61 /**
62  * Be verbose
63  */
64 static int verbose;
65
66 /**
67  * Total number of peers in the test.
68  */
69 static unsigned long long num_peers;
70
71 /**
72  * Global configuration file
73  */
74 static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
75
76 /**
77  * Total number of currently running peers.
78  */
79 static unsigned long long peers_running;
80
81 /**
82  * Total number of connections in the whole network.
83  */
84 static unsigned int total_connections;
85
86 /**
87  * The currently running peer group.
88  */
89 static struct GNUNET_TESTING_PeerGroup *pg;
90
91 /**
92  * File to report results to.
93  */
94 static struct GNUNET_DISK_FileHandle *output_file;
95
96 /**
97  * File to log connection info, statistics to.
98  */
99 static struct GNUNET_DISK_FileHandle *data_file;
100
101 /**
102  * How many data points to capture before triggering next round?
103  */
104 static struct GNUNET_TIME_Relative wait_time;
105
106 /**
107  * Task called to disconnect peers.
108  */
109 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
110
111 /**
112  * Task To perform tests
113  */
114 static GNUNET_SCHEDULER_TaskIdentifier test_task;
115
116 /**
117  * Task called to shutdown test.
118  */
119 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
120
121 static char *topology_file;
122
123 static struct GNUNET_TESTING_Daemon *d1;
124
125 static struct GNUNET_TESTING_Daemon *d2;
126
127 static struct GNUNET_MESH_Handle *h1;
128
129 static struct GNUNET_MESH_Handle *h2;
130
131 static struct GNUNET_MESH_Tunnel *t;
132
133 static uint16_t *mesh_peers;
134
135 /**
136  * Check whether peers successfully shut down.
137  */
138 static void
139 shutdown_callback (void *cls, const char *emsg)
140 {
141   if (emsg != NULL)
142   {
143 #if VERBOSE
144     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n");
145 #endif
146     ok++;
147   }
148   else
149   {
150 #if VERBOSE
151     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
152                 "test: All peers successfully shut down!\n");
153 #endif
154   }
155 }
156
157
158 static void
159 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
160 {
161 #if VERBOSE
162   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n");
163 #endif
164
165   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
166   {
167     GNUNET_SCHEDULER_cancel (disconnect_task);
168     disconnect_task = GNUNET_SCHEDULER_NO_TASK;
169   }
170
171   if (data_file != NULL)
172     GNUNET_DISK_file_close (data_file);
173   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
174   GNUNET_CONFIGURATION_destroy (testing_cfg);
175 }
176
177
178 /**
179  * Handlers, for diverse services
180  */
181 static struct GNUNET_MESH_MessageHandler handlers[] = {
182 //    {&callback, 1, 0},
183   {NULL, 0, 0}
184 };
185
186
187 static void
188 disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
189 {
190   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191               "test: disconnecting mesh service of peers\n");
192   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
193   GNUNET_MESH_disconnect (h1);
194   GNUNET_MESH_disconnect (h2);
195   GNUNET_SCHEDULER_cancel (shutdown_handle);
196   shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
197 }
198
199
200 /**
201  * Method called whenever another peer has added us to a tunnel
202  * the other peer initiated.
203  *
204  * @param cls closure
205  * @param tunnel new handle to the tunnel
206  * @param initiator peer that started the tunnel
207  * @param atsi performance information for the tunnel
208  * @return initial tunnel context for the tunnel
209  *         (can be NULL -- that's not an error)
210  */
211 static void *
212 incoming_tunnel (void *cls, struct GNUNET_MESH_Tunnel *tunnel,
213                  const struct GNUNET_PeerIdentity *initiator,
214                  const struct GNUNET_ATS_Information *atsi)
215 {
216   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Incoming tunnel from %s\n",
217               GNUNET_i2s (initiator));
218   GNUNET_SCHEDULER_cancel (disconnect_task);
219   disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_mesh_peers, NULL);
220   ok = 0;
221   return NULL;
222 }
223
224 /**
225  * Function called whenever an inbound tunnel is destroyed.  Should clean up
226  * any associated state.
227  *
228  * @param cls closure (set from GNUNET_MESH_connect)
229  * @param tunnel connection to the other end (henceforth invalid)
230  * @param tunnel_ctx place where local state associated
231  *                   with the tunnel is stored
232  */
233 static void
234 tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
235                 void *tunnel_ctx)
236 {
237 #if VERBOSE
238   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: tunnel disconnected\n");
239 #endif
240
241   return;
242 }
243
244 /**
245  * Method called whenever a tunnel falls apart.
246  *
247  * @param cls closure
248  * @param peer peer identity the tunnel stopped working with
249  */
250 static void
251 dh (void *cls, const struct GNUNET_PeerIdentity *peer)
252 {
253   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer %s disconnected\n",
254               GNUNET_i2s (peer));
255   return;
256 }
257
258
259 /**
260  * Method called whenever a tunnel is established.
261  *
262  * @param cls closure
263  * @param peer peer identity the tunnel was created to, NULL on timeout
264  * @param atsi performance data for the connection
265  */
266 static void
267 ch (void *cls, const struct GNUNET_PeerIdentity *peer,
268     const struct GNUNET_ATS_Information *atsi)
269 {
270   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: peer %s connected\n",
271               GNUNET_i2s (peer));
272   return;
273 }
274
275
276 static void
277 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
278 {
279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: test_task\n");
280   GNUNET_MESH_peer_request_connect_add (t, &d2->id);
281   GNUNET_SCHEDULER_cancel (disconnect_task);
282   disconnect_task =
283       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
284                                     (GNUNET_TIME_UNIT_SECONDS, 30),
285                                     &disconnect_mesh_peers, NULL);
286 }
287
288
289 /**
290  * connect_mesh_service: connect to the mesh service of one of the peers
291  *
292  */
293 static void
294 connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
295 {
296   GNUNET_MESH_ApplicationType app;
297   struct GNUNET_PeerIdentity id;
298
299   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: connect_mesh_service\n");
300
301   GNUNET_PEER_resolve (11, &id);
302   d2 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
303   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peer searched: %s\n",
304               GNUNET_i2s (&d2->id));
305   app = (GNUNET_MESH_ApplicationType) 0;
306
307 #if VERBOSE
308   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309               "test: connecting to mesh service of peer %s\n",
310               GNUNET_i2s (&d1->id));
311   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
312               "test: connecting to mesh service of peer %s\n",
313               GNUNET_i2s (&d2->id));
314 #endif
315   h1 = GNUNET_MESH_connect (d1->cfg, 10, NULL, NULL, &tunnel_cleaner, handlers,
316                             &app);
317   h2 = GNUNET_MESH_connect (d2->cfg, 10, NULL, &incoming_tunnel,
318                             &tunnel_cleaner, handlers, &app);
319 #if VERBOSE
320   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321               "test: connected to mesh service of peer %s\n",
322               GNUNET_i2s (&d1->id));
323   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324               "test: connected to mesh service of peer %s\n",
325               GNUNET_i2s (&d2->id));
326 #endif
327   t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, NULL);
328   test_task =
329       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
330                                     (GNUNET_TIME_UNIT_SECONDS, 6), &do_test,
331                                     NULL);
332 }
333
334
335
336 /**
337  * peergroup_ready: start test when all peers are connected
338  * @param cls closure
339  * @param emsg error message
340  */
341 static void
342 peergroup_ready (void *cls, const char *emsg)
343 {
344   char *buf;
345   int buf_len;
346   unsigned int i;
347
348   if (emsg != NULL)
349   {
350     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
351                 "test: Peergroup callback called with error, aborting test!\n");
352     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n",
353                 emsg);
354     ok++;
355     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
356     return;
357   }
358 #if VERBOSE
359   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360               "************************************************************\n");
361   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
362               "test: Peer Group started successfully!\n");
363   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n",
364               total_connections);
365 #endif
366
367   if (data_file != NULL)
368   {
369     buf = NULL;
370     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
371     if (buf_len > 0)
372       GNUNET_DISK_file_write (data_file, buf, buf_len);
373     GNUNET_free (buf);
374   }
375   peers_running = GNUNET_TESTING_daemons_running (pg);
376   for (i = 0; i < num_peers; i++)
377   {
378     d1 = GNUNET_TESTING_daemon_get (pg, i);
379     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test:   %u: %s\n",
380                 GNUNET_PEER_intern (&d1->id), GNUNET_i2s (&d1->id));
381   }
382   d1 = GNUNET_TESTING_daemon_get (pg, 0);
383   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Peer looking: %s\n",
384               GNUNET_i2s (&d1->id));
385
386   GNUNET_SCHEDULER_add_now (&connect_mesh_service, NULL);
387   disconnect_task =
388       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL);
389
390 }
391
392
393 /**
394  * Function that will be called whenever two daemons are connected by
395  * the testing library.
396  *
397  * @param cls closure
398  * @param first peer id for first daemon
399  * @param second peer id for the second daemon
400  * @param distance distance between the connected peers
401  * @param first_cfg config for the first daemon
402  * @param second_cfg config for the second daemon
403  * @param first_daemon handle for the first daemon
404  * @param second_daemon handle for the second daemon
405  * @param emsg error message (NULL on success)
406  */
407 static void
408 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
409             const struct GNUNET_PeerIdentity *second, uint32_t distance,
410             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
411             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
412             struct GNUNET_TESTING_Daemon *first_daemon,
413             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
414 {
415   if (emsg == NULL)
416   {
417     total_connections++;
418   }
419   else
420   {
421     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
422                 "test: Problem with new connection (%s)\n", emsg);
423   }
424
425 }
426
427
428 /**
429  * run: load configuration options and schedule test to run (start peergroup)
430  * @param cls closure
431  * @param args argv
432  * @param cfgfile configuration file name (can be NULL)
433  * @param cfg configuration handle
434  */
435 static void
436 run (void *cls, char *const *args, const char *cfgfile,
437      const struct GNUNET_CONFIGURATION_Handle *cfg)
438 {
439   char *temp_str;
440   unsigned long long temp_wait;
441   struct GNUNET_TESTING_Host *hosts;
442   char *data_filename;
443
444
445   ok = 1;
446   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
447
448   GNUNET_log_setup ("test_mesh_small_unicast",
449 #if VERBOSE
450                     "DEBUG",
451 #else
452                     "WARNING",
453 #endif
454                     NULL);
455
456 #if VERBOSE
457   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n");
458   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
459                                          "use_progressbars", "YES");
460 #endif
461
462   if (GNUNET_OK !=
463       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
464                                              "num_peers", &num_peers))
465   {
466     GNUNET_assert (GNUNET_OK ==
467                    GNUNET_CONFIGURATION_load (testing_cfg,
468                                               "test_mesh_small.conf"));
469     if (GNUNET_OK !=
470         GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
471                                                "num_peers", &num_peers))
472     {
473       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
474                   "Option TESTING:NUM_PEERS is required!\n");
475       return;
476     }
477   }
478
479   mesh_peers = GNUNET_malloc (sizeof (GNUNET_PEER_Id) * (num_peers + 1));
480
481   if (GNUNET_OK !=
482       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "test_mesh_small",
483                                              "wait_time", &temp_wait))
484   {
485     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
486                 "Option test_mesh_small:wait_time is required!\n");
487     return;
488   }
489
490   if (GNUNET_OK !=
491       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
492                                              "topology_output_file",
493                                              &topology_file))
494   {
495     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
496                 "Option test_mesh_small:topology_output_file is required!\n");
497     return;
498   }
499
500   if (GNUNET_OK ==
501       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small",
502                                              "data_output_file",
503                                              &data_filename))
504   {
505     data_file =
506         GNUNET_DISK_file_open (data_filename,
507                                GNUNET_DISK_OPEN_READWRITE |
508                                GNUNET_DISK_OPEN_CREATE,
509                                GNUNET_DISK_PERM_USER_READ |
510                                GNUNET_DISK_PERM_USER_WRITE);
511     if (data_file == NULL)
512     {
513       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
514                   data_filename);
515       GNUNET_free (data_filename);
516     }
517   }
518
519   wait_time =
520       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_wait);
521
522   if (GNUNET_YES ==
523       GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small",
524                                              "output_file", &temp_str))
525   {
526     output_file =
527         GNUNET_DISK_file_open (temp_str,
528                                GNUNET_DISK_OPEN_READWRITE |
529                                GNUNET_DISK_OPEN_CREATE,
530                                GNUNET_DISK_PERM_USER_READ |
531                                GNUNET_DISK_PERM_USER_WRITE);
532     if (output_file == NULL)
533       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
534                   temp_str);
535   }
536   GNUNET_free_non_null (temp_str);
537
538   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
539
540   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
541                                        &connect_cb, &peergroup_ready, NULL,
542                                        hosts);
543   GNUNET_assert (pg != NULL);
544   shutdown_handle =
545       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
546                                     &shutdown_task, NULL);
547 }
548
549
550
551 /**
552  * test_mesh_small command line options
553  */
554 static struct GNUNET_GETOPT_CommandLineOption options[] = {
555   {'V', "verbose", NULL,
556    gettext_noop ("be verbose (print progress information)"),
557    0, &GNUNET_GETOPT_set_one, &verbose},
558   GNUNET_GETOPT_OPTION_END
559 };
560
561
562 /**
563  * Main: start test
564  */
565 int
566 main (int argc, char *argv[])
567 {
568   GNUNET_PROGRAM_run (argc, argv, "test_mesh_small_unicast",
569                       gettext_noop ("Test mesh unicast in a small network."),
570                       options, &run, NULL);
571 #if REMOVE_DIR
572   GNUNET_DISK_directory_remove ("/tmp/test_mesh_small_unicast");
573 #endif
574   if (0 != ok)
575   {
576     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n");
577   }
578   return ok;
579 }
580
581 /* end of test_mesh_small_unicast.c */