naming
[oweals/gnunet.git] / src / dht / test_dht_2dtorus.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 dht/test_dht_2dtorus.c
22  *
23  * @brief Test for the dht service: store and retrieve in a 2d_torus.
24  * Each peer stores it own ID in the DHT and then a different peer tries to
25  * retrieve that key from it. The GET starts after a first round of PUTS has
26  * been made. Periodically, each peer stores its ID into the DHT. If after
27  * a timeout no result has been returned, the test fails.
28  */
29 #include "platform.h"
30 #include "gnunet_testing_lib.h"
31 #include "gnunet_dht_service.h"
32
33 #define VERBOSE GNUNET_YES
34 #define REMOVE_DIR GNUNET_YES
35
36
37 /**
38  * How long until we give up on connecting the peers?
39  */
40 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
41
42 static int ok;
43
44 /**
45  * Be verbose
46  */
47 static int verbose;
48
49 /**
50  * Total number of peers in the test.
51  */
52 static unsigned long long num_peers;
53
54 /**
55  * Global configuration file
56  */
57 static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
58
59 /**
60  * Total number of currently running peers.
61  */
62 static unsigned long long peers_running;
63
64 /**
65  * Total number of connections in the whole network.
66  */
67 static unsigned int total_connections;
68
69 /**
70  * The currently running peer group.
71  */
72 static struct GNUNET_TESTING_PeerGroup *pg;
73
74 /**
75  * File to report results to.
76  */
77 static struct GNUNET_DISK_FileHandle *output_file;
78
79 /**
80  * File to log connection info, statistics to.
81  */
82 static struct GNUNET_DISK_FileHandle *data_file;
83
84 /**
85  * Task called to disconnect peers.
86  */
87 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
88
89 /**
90  * Task To perform tests
91  */
92 static GNUNET_SCHEDULER_TaskIdentifier test_task;
93
94 /**
95  * Task to do DHT_puts
96  */
97 static GNUNET_SCHEDULER_TaskIdentifier put_task;
98
99 /**
100  * Task called to shutdown test.
101  */
102 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
103
104 static char *topology_file;
105
106 static char *data_filename;
107
108 struct GNUNET_TESTING_Daemon *d1;
109
110 struct GNUNET_TESTING_Daemon *d2;
111
112 struct GNUNET_DHT_Handle **hs;
113
114 struct GNUNET_DHT_GetHandle *get_h;
115
116 /**
117  * Check whether peers successfully shut down.
118  */
119 static void
120 shutdown_callback (void *cls, const char *emsg)
121 {
122   if (emsg != NULL)
123   {
124 #if VERBOSE
125     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n");
126 #endif
127     ok++;
128   }
129   else
130   {
131 #if VERBOSE
132     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: All peers successfully shut down!\n");
133 #endif
134   }
135 }
136
137
138 static void
139 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
140 {
141 #if VERBOSE
142   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n");
143 #endif
144
145   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
146   {
147     GNUNET_SCHEDULER_cancel (disconnect_task);
148     disconnect_task = GNUNET_SCHEDULER_NO_TASK;
149   }
150
151   if (data_file != NULL)
152     GNUNET_DISK_file_close (data_file);
153   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
154   GNUNET_CONFIGURATION_destroy (testing_cfg);
155 }
156
157
158 static void
159 disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
160 {
161   unsigned int i;
162
163   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164               "test: disconnecting peers\n");
165   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
166   GNUNET_SCHEDULER_cancel (put_task);
167   if (NULL != get_h)
168     GNUNET_DHT_get_stop(get_h);
169   for (i = 0; i < num_peers;  i++)
170   {
171     GNUNET_DHT_disconnect(hs[i]);
172   }
173   GNUNET_SCHEDULER_cancel (shutdown_handle);
174   shutdown_handle = GNUNET_SCHEDULER_add_now(&shutdown_task, NULL);
175 }
176
177 static void
178 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
179                     const GNUNET_HashCode * key,
180                     const struct GNUNET_PeerIdentity *get_path,
181                     unsigned int get_path_length,
182                     const struct GNUNET_PeerIdentity *put_path,
183                     unsigned int put_path_length,
184                     enum GNUNET_BLOCK_Type type, size_t size, const void *data)
185 {
186     ok = 0;
187     
188     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189               "test: ************* FOUND!!! ***********\n");
190     if (sizeof(GNUNET_HashCode) == size)
191     {
192       const GNUNET_HashCode *h = data;
193       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194                   "test:   Contents: %s\n",
195                   GNUNET_h2s_full (h));
196
197     }
198     GNUNET_SCHEDULER_cancel(disconnect_task);
199     disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL);
200 }
201
202 static void
203 do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
204 {
205   struct GNUNET_TESTING_Daemon *d;
206   struct GNUNET_TESTING_Daemon *o;
207
208   d = GNUNET_TESTING_daemon_get (pg, 2);
209   o = GNUNET_TESTING_daemon_get (pg, 0);
210   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: test_task\n");
211   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212               "test: looking for [2] %s\n",
213               GNUNET_h2s_full (&d->id.hashPubKey));
214   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
215               "test: from        [0] %s\n",
216               GNUNET_h2s_full (&o->id.hashPubKey));
217   get_h = GNUNET_DHT_get_start (hs[0],
218                                 GNUNET_TIME_UNIT_FOREVER_REL, /* timeout */
219                                 GNUNET_BLOCK_TYPE_TEST,   /* type */
220                                 &d->id.hashPubKey,   /*key to search */
221                                 4U,        /* replication level */
222                                 GNUNET_DHT_RO_RECORD_ROUTE |
223                                   GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
224                                 NULL,     /* xquery */
225                                 0,        /* xquery bits */
226                                 &dht_get_id_handler,
227                                 NULL);
228   GNUNET_SCHEDULER_cancel (disconnect_task);
229   disconnect_task = GNUNET_SCHEDULER_add_delayed(
230           GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30),
231                                &disconnect_peers, NULL);
232 }
233
234
235 static void
236 put_id (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
237 {
238   struct GNUNET_TESTING_Daemon *d;
239   unsigned int i;
240
241   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: putting id's in DHT\n");
242   for (i = 0; i < num_peers;  i++)
243   {
244     d = GNUNET_TESTING_daemon_get (pg, i);
245     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
246                 "test:    putting into DHT: %s\n",
247                 GNUNET_h2s_full (&d->id.hashPubKey));
248     GNUNET_DHT_put(hs[i],
249                    &d->id.hashPubKey,
250                    10U,
251                    GNUNET_DHT_RO_RECORD_ROUTE |
252                      GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
253                     GNUNET_BLOCK_TYPE_TEST,
254                    sizeof(struct GNUNET_PeerIdentity),
255                    (const char *) &d->id,
256                    GNUNET_TIME_UNIT_FOREVER_ABS,
257                    GNUNET_TIME_UNIT_FOREVER_REL,
258                    NULL,
259                    NULL);
260
261   }
262   put_task = GNUNET_SCHEDULER_add_delayed(
263                 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5),
264                                &put_id, NULL);
265 }
266
267
268 /**
269  * peergroup_ready: start test when all peers are connected
270  * @param cls closure
271  * @param emsg error message
272  */
273 static void
274 peergroup_ready (void *cls, const char *emsg)
275 {
276   struct GNUNET_TESTING_Daemon *d;
277   char *buf;
278   int buf_len;
279   unsigned int i;
280
281   if (emsg != NULL)
282   {
283     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284                 "test: Peergroup callback called with error, aborting test!\n");
285     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286                 "test: Error from testing: `%s'\n", emsg);
287     ok++;
288     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
289     return;
290   }
291 #if VERBOSE
292   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293               "************************************************************\n");
294   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295               "test: Peer Group started successfully!\n");
296   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
297               "test: Have %u connections\n",
298               total_connections);
299 #endif
300
301   if (data_file != NULL)
302   {
303     buf = NULL;
304     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
305     if (buf_len > 0)
306       GNUNET_DISK_file_write (data_file, buf, buf_len);
307     GNUNET_free (buf);
308   }
309   peers_running = GNUNET_TESTING_daemons_running (pg);
310   
311   GNUNET_assert (peers_running == num_peers);
312   hs = GNUNET_malloc (num_peers * sizeof(struct GNUNET_DHT_Handle *));
313   for (i = 0; i < num_peers;  i++)
314   {
315     d = GNUNET_TESTING_daemon_get (pg, i);
316     hs[i] = GNUNET_DHT_connect(d->cfg, 32);
317   }
318
319   put_task = GNUNET_SCHEDULER_add_now(&put_id, NULL);
320   test_task =
321       GNUNET_SCHEDULER_add_delayed(
322           GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 2),
323           &do_test, NULL);
324   disconnect_task =
325       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
326                                         GNUNET_TIME_UNIT_SECONDS,
327                                         30),
328                                     &disconnect_peers,
329                                     NULL);
330
331 }
332
333
334 /**
335  * Function that will be called whenever two daemons are connected by
336  * the testing library.
337  *
338  * @param cls closure
339  * @param first peer id for first daemon
340  * @param second peer id for the second daemon
341  * @param distance distance between the connected peers
342  * @param first_cfg config for the first daemon
343  * @param second_cfg config for the second daemon
344  * @param first_daemon handle for the first daemon
345  * @param second_daemon handle for the second daemon
346  * @param emsg error message (NULL on success)
347  */
348 static void
349 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
350             const struct GNUNET_PeerIdentity *second, uint32_t distance,
351             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
352             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
353             struct GNUNET_TESTING_Daemon *first_daemon,
354             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
355 {
356 //   GNUNET_PEER_Id f;
357 //   GNUNET_PEER_Id s;
358
359   if (emsg == NULL)
360   {
361     total_connections++;
362     /*f = */GNUNET_PEER_intern(first);
363     /*s = */GNUNET_PEER_intern(second);
364 //   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: New connection!\n");
365 //   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
366 //               "test:     %s (%u)\n",
367 //               GNUNET_h2s(&first->hashPubKey),
368 //               f);
369 //   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 //               "test:     %s (%u)\n",
371 //               GNUNET_h2s(&second->hashPubKey),
372 //               s);
373   }
374   else
375   {
376     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377                 "test: Problem with new connection (%s)\n",
378                 emsg);
379   }
380
381 }
382
383
384 /**
385  * run: load configuration options and schedule test to run (start peergroup)
386  * @param cls closure
387  * @param args argv
388  * @param cfgfile configuration file name (can be NULL)
389  * @param cfg configuration handle
390  */
391 static void
392 run (void *cls, char *const *args, const char *cfgfile,
393      const struct GNUNET_CONFIGURATION_Handle *cfg)
394 {
395   char *temp_str;
396   struct GNUNET_TESTING_Host *hosts;
397
398   ok = 1;
399   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
400
401   GNUNET_log_setup ("test_dht_2dtorus",
402 #if VERBOSE
403                     "DEBUG",
404 #else
405                     "WARNING",
406 #endif
407                     NULL);
408
409 #if VERBOSE
410   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n");
411   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
412                                          "use_progressbars", "YES");
413 #endif
414
415   if (GNUNET_OK !=
416       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
417                                              "num_peers", &num_peers))
418   {
419     GNUNET_assert (GNUNET_OK ==
420                    GNUNET_CONFIGURATION_load (testing_cfg,
421                                               "test_dht_2dtorus.conf"));
422     if (GNUNET_OK !=
423         GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
424                                                "num_peers", &num_peers))
425     {
426       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427                   "Option TESTING:NUM_PEERS is required!\n");
428       return;
429     }
430   }
431
432   if (GNUNET_OK !=
433       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
434                                              "topology_output_file",
435                                              &topology_file))
436   {
437     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
438                 "Option test_dht_2d:topology_output_file is required!\n");
439     return;
440   }
441
442   if (GNUNET_OK !=
443       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_dht_2dtorus",
444                                              "data_output_file",
445                                              &data_filename))
446   {
447     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
448                 "Option test_dht_2d:data_output_file is required!\n");
449     return;
450   }
451
452   data_file =
453       GNUNET_DISK_file_open (data_filename,
454                              GNUNET_DISK_OPEN_READWRITE |
455                              GNUNET_DISK_OPEN_CREATE,
456                              GNUNET_DISK_PERM_USER_READ |
457                              GNUNET_DISK_PERM_USER_WRITE);
458   if (data_file == NULL)
459   {
460     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
461                 data_filename);
462     GNUNET_free (data_filename);
463   }
464
465   if (GNUNET_YES ==
466       GNUNET_CONFIGURATION_get_value_string (cfg, "test_dht_2dtorus",
467                                              "output_file", &temp_str))
468   {
469     output_file =
470         GNUNET_DISK_file_open (temp_str,
471                                GNUNET_DISK_OPEN_READWRITE |
472                                GNUNET_DISK_OPEN_CREATE,
473                                GNUNET_DISK_PERM_USER_READ |
474                                GNUNET_DISK_PERM_USER_WRITE);
475     if (output_file == NULL)
476       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
477                   temp_str);
478   }
479   GNUNET_free_non_null (temp_str);
480
481   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
482
483   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
484                                        &connect_cb, &peergroup_ready, NULL,
485                                        hosts);
486   GNUNET_assert (pg != NULL);
487   shutdown_handle =
488       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
489                                     &shutdown_task, NULL);
490 }
491
492
493
494 /**
495  * test_dht_2d command line options
496  */
497 static struct GNUNET_GETOPT_CommandLineOption options[] = {
498   {'V', "verbose", NULL,
499    gettext_noop ("be verbose (print progress information)"),
500    0, &GNUNET_GETOPT_set_one, &verbose},
501   GNUNET_GETOPT_OPTION_END
502 };
503
504
505 /**
506  * Main: start test
507  */
508 int
509 main (int argc, char *argv[])
510 {
511   GNUNET_PROGRAM_run (argc, argv, "test_dht_2dtorus",
512                       gettext_noop ("Test dht in a small 2D torus."), options,
513                       &run, NULL);
514 #if REMOVE_DIR
515   GNUNET_DISK_directory_remove ("/tmp/test_dht_2dtorus");
516 #endif
517   if (0 != ok)
518   {
519     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n");
520   }
521   return ok;
522 }
523
524 /* end of test_dht_2dtorus.c */