-fix 2447
[oweals/gnunet.git] / src / gns / test_gns_dht_threepeer.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 gns/test_gns_dht_threepeer.c
22  * @brief tests dht lookup over 3 peers
23  *
24  * topology:
25  * alice <----> bob <-----> dave
26  *
27  * alice queries for www.buddy.bob.gnunet
28  *
29  */
30 #include "platform.h"
31 #include "gnunet_disk_lib.h"
32 #include "gnunet_testing_lib.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_dht_service.h"
35 #include "block_dns.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_namestore_service.h"
38 #include "gnunet_dnsparser_lib.h"
39 #include "gnunet_gns_service.h"
40
41 /* DEFINES */
42 #define VERBOSE GNUNET_YES
43
44 /* Timeout for entire testcase */
45 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 180)
46 #define ZONE_PUT_WAIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
47
48 /* If number of peers not in config file, use this number */
49 #define DEFAULT_NUM_PEERS 2
50
51 #define TEST_DOMAIN "www.buddy.bob.gnunet"
52 #define TEST_IP "1.1.1.1"
53 #define TEST_DAVE_PSEU "hagbard"
54 #define TEST_NUM_PEERS 3
55 #define TEST_NUM_CON 3
56
57 /* Globals */
58
59 /**
60  * Directory to store temp data in, defined in config file
61  */
62 static char *test_directory;
63
64 /**
65  * Variable used to store the number of connections we should wait for.
66  */
67 static unsigned int expected_connections;
68
69 /**
70  * Variable used to keep track of how many peers aren't yet started.
71  */
72 static unsigned long long peers_left;
73
74 struct GNUNET_TESTING_Daemon *d1;
75 struct GNUNET_TESTING_Daemon *d2;
76 struct GNUNET_TESTING_Daemon *d3;
77
78
79 /**
80  * Total number of peers to run, set based on config file.
81  */
82 static unsigned long long num_peers;
83
84 /**
85  * Global used to count how many connections we have currently
86  * been notified about (how many times has topology_callback been called
87  * with success?)
88  */
89 static unsigned int total_connections;
90
91 /**
92  * Global used to count how many failed connections we have
93  * been notified about (how many times has topology_callback
94  * been called with failure?)
95  */
96 static unsigned int failed_connections;
97
98 /* Task handle to use to schedule test failure */
99 GNUNET_SCHEDULER_TaskIdentifier die_task;
100
101 GNUNET_SCHEDULER_TaskIdentifier bob_task;
102
103 /* Global return value (0 for success, anything else for failure) */
104 static int ok;
105
106 int bob_online, alice_online, dave_online;
107
108 const struct GNUNET_CONFIGURATION_Handle *alice_cfg;
109 struct GNUNET_CONFIGURATION_Handle *cfg_bob;
110 struct GNUNET_CONFIGURATION_Handle *cfg_dave;
111
112 struct GNUNET_CRYPTO_ShortHashCode bob_hash;
113 struct GNUNET_CRYPTO_ShortHashCode dave_hash;
114 struct GNUNET_TESTING_Daemon *alice_daemon;
115 struct GNUNET_TESTING_Daemon *bob_daemon;
116 struct GNUNET_TESTING_Daemon *dave_daemon;
117
118 struct GNUNET_TESTING_PeerGroup *pg;
119 struct GNUNET_GNS_Handle *gh;
120
121 /**
122  * Function scheduled to be run on the successful completion of this
123  * testcase.  Specifically, called when our get request completes.
124  */
125 static void
126 finish_testing (void *cls, const char *emsg)
127 {
128   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test finished! (ret=%d)\n", ok);
129 }
130
131 /**
132  * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut
133  * down the peers without freeing memory associated with GET request.
134  */
135 static void
136 end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
137 {
138   die_task = GNUNET_SCHEDULER_NO_TASK;
139   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &finish_testing, NULL);
140 }
141
142 /**
143  * Check if the get_handle is being used, if so stop the request.  Either
144  * way, schedule the end_badly_cont function which actually shuts down the
145  * test.
146  */
147 static void
148 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
149 {
150   die_task = GNUNET_SCHEDULER_NO_TASK;
151   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failing test with error: `%s'!\n",
152               (char *) cls);
153   die_task = GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL);
154   ok = 1;
155 }
156
157
158 static void
159 on_lookup_result(void *cls, uint32_t rd_count,
160                  const struct GNUNET_NAMESTORE_RecordData *rd)
161 {
162   int i;
163   char* string_val;
164   const char* typename;
165
166   if (rd_count == 0)
167   {
168     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169                 "Lookup failed!\n");
170     ok = 2;
171   }
172   else
173   {
174     ok = 1;
175     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "name: %s\n", (char*)cls);
176     for (i=0; i<rd_count; i++)
177     {
178       typename = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
179       string_val = GNUNET_NAMESTORE_value_to_string(rd[i].record_type,
180                                                     rd[i].data,
181                                                     rd[i].data_size);
182       if (0 == strcmp(string_val, TEST_IP))
183       {
184         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
185                     "%s correctly resolved to %s!\n", TEST_DOMAIN, string_val);
186         ok = 0;
187       }
188     }
189   }
190   GNUNET_GNS_disconnect(gh);
191   GNUNET_SCHEDULER_cancel(die_task);
192   die_task = GNUNET_SCHEDULER_NO_TASK;
193   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &finish_testing, NULL);
194   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down!\n");
195
196 }
197
198 static void
199 commence_testing(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
200 {
201   
202   gh = GNUNET_GNS_connect(alice_cfg);
203
204   GNUNET_GNS_lookup(gh, TEST_DOMAIN, GNUNET_GNS_RECORD_A,
205                     GNUNET_NO,
206                     NULL,
207                     &on_lookup_result, TEST_DOMAIN);
208   die_task =
209     GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from lookup");
210 }
211
212
213 /**
214  * This function is called whenever a connection attempt is finished between two of
215  * the started peers (started with GNUNET_TESTING_daemons_start).  The total
216  * number of times this function is called should equal the number returned
217  * from the GNUNET_TESTING_connect_topology call.
218  *
219  * The emsg variable is NULL on success (peers connected), and non-NULL on
220  * failure (peers failed to connect).
221  */
222 void
223 daemon_connected (void *cls, const struct GNUNET_PeerIdentity *first,
224                    const struct GNUNET_PeerIdentity *second, uint32_t distance,
225                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
226                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
227                    struct GNUNET_TESTING_Daemon *first_daemon,
228                    struct GNUNET_TESTING_Daemon *second_daemon,
229                    const char *emsg)
230 {
231   if (emsg == NULL)
232   {
233     total_connections++;
234 #if VERBOSE
235     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236                 "connected peer %s to peer %s, distance %u\n",
237                 first_daemon->shortname, second_daemon->shortname, distance);
238 #endif
239   }
240 #if VERBOSE
241   else
242   {
243     failed_connections++;
244     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
245                 "Failed to connect peer %s to peer %s with error :\n%s\n",
246                 first_daemon->shortname, second_daemon->shortname, emsg);
247   }
248 #endif
249
250   if (total_connections == expected_connections)
251   {
252 #if VERBOSE
253     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
254                 "Created %d total connections, which is our target number!  Starting next phase of testing.\n",
255                 total_connections);
256 #endif
257     GNUNET_SCHEDULER_cancel (die_task);
258     die_task = GNUNET_SCHEDULER_NO_TASK;
259     //die_task =
260     //    GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect");
261    
262     //commence_testing();
263     
264   }
265   else if (total_connections + failed_connections == expected_connections)
266   {
267     GNUNET_SCHEDULER_cancel (die_task);
268     die_task =
269         GNUNET_SCHEDULER_add_now (&end_badly,
270                                   "from topology_callback (too many failed connections)");
271   }
272 }
273
274 void
275 all_connected(void *cls, const char *emsg)
276 {
277   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
278               "Created all connections!  Starting next phase of testing.\n");
279   GNUNET_SCHEDULER_add_delayed (ZONE_PUT_WAIT_TIME, &commence_testing, NULL);
280 }
281
282 static void
283 disconnect_ns (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
284 {
285   GNUNET_NAMESTORE_disconnect (cls);
286 }
287
288 static void
289 cont_ns (void* cls, int32_t s, const char* emsg)
290 {
291   GNUNET_SCHEDULER_add_now (&disconnect_ns, cls);
292 }
293
294 static void
295 daemon_started (void *cls, const struct GNUNET_PeerIdentity *id,
296                 const struct GNUNET_CONFIGURATION_Handle *cfg,
297                 struct GNUNET_TESTING_Daemon *d, const char *emsg)
298 {
299   struct GNUNET_NAMESTORE_Handle *ns;
300   char* keyfile;
301   struct GNUNET_CRYPTO_RsaPrivateKey *key;
302   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
303   struct in_addr *web;
304   struct GNUNET_NAMESTORE_RecordData rd;
305
306   rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY | GNUNET_NAMESTORE_RF_NONE;
307   rd.expiration_time = UINT64_MAX;
308   
309   if (NULL == dave_daemon)
310   {
311     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
312                                                               "ZONEKEY",
313                                                               &keyfile))
314     {
315       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
316       ok = -1;
317       return;
318     }
319     dave_daemon = d;
320
321     key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
322
323     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now dave\n");
324     ns = GNUNET_NAMESTORE_connect(cfg);
325     
326     GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
327     GNUNET_CRYPTO_short_hash(&pkey, sizeof(pkey), &dave_hash);
328     
329     web = GNUNET_malloc(sizeof(struct in_addr));
330     GNUNET_assert(1 == inet_pton (AF_INET, TEST_IP, web));
331     rd.data_size = sizeof(struct in_addr);
332     rd.data = web;
333     rd.record_type = GNUNET_GNS_RECORD_A;
334     rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
335
336     GNUNET_NAMESTORE_record_create (ns, key, "www", &rd, NULL, NULL);
337
338     rd.data_size = strlen(TEST_DAVE_PSEU);
339     rd.data = TEST_DAVE_PSEU;
340     rd.record_type = GNUNET_GNS_RECORD_PSEU;
341
342     GNUNET_NAMESTORE_record_create (ns, key, "+", &rd, &cont_ns, ns);
343
344     GNUNET_CRYPTO_rsa_key_free(key);
345     GNUNET_free(keyfile);
346     GNUNET_free(web);
347
348     return;
349   }
350   
351   
352   if (NULL == bob_daemon)
353   {
354     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
355                                                               "ZONEKEY",
356                                                               &keyfile))
357     {
358       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
359       ok = -1;
360       return;
361     }
362     bob_daemon = d;
363
364     key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
365
366     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now bob\n");
367     ns = GNUNET_NAMESTORE_connect(cfg);
368     
369     GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
370     GNUNET_CRYPTO_short_hash(&pkey, sizeof(pkey), &bob_hash);
371     
372     rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
373     rd.data = &dave_hash;
374     rd.record_type = GNUNET_GNS_RECORD_PKEY;
375     rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
376
377     GNUNET_NAMESTORE_record_create (ns, key, "buddy", &rd, &cont_ns, ns);
378
379     GNUNET_CRYPTO_rsa_key_free(key);
380     GNUNET_free(keyfile);
381
382     return;
383   }
384
385   
386   
387   if (NULL == alice_daemon)
388   {
389
390     if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
391                                                               "ZONEKEY",
392                                                               &keyfile))
393     {
394       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
395       ok = -1;
396       return;
397     }
398     alice_daemon = d;
399     alice_cfg = cfg;
400
401     key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
402
403     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is now alice\n");
404     ns = GNUNET_NAMESTORE_connect(cfg);
405     
406     rd.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
407     rd.data = &bob_hash;
408     rd.record_type = GNUNET_GNS_RECORD_PKEY;
409     rd.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
410
411     GNUNET_NAMESTORE_record_create (ns, key, "bob", &rd, &cont_ns, ns);
412
413     GNUNET_CRYPTO_rsa_key_free(key);
414     GNUNET_free(keyfile);
415
416     GNUNET_TESTING_connect_topology (pg, GNUNET_TESTING_TOPOLOGY_CLIQUE,
417                                      GNUNET_TESTING_TOPOLOGY_OPTION_ALL,
418                                      0,
419                                      TIMEOUT,
420                                      3,
421                                      &all_connected, NULL);
422     return;
423
424   }
425
426   
427
428   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This is a random guy\n");
429 }
430
431 static void
432 run (void *cls, char *const *args, const char *cfgfile,
433      const struct GNUNET_CONFIGURATION_Handle *cfg)
434 {
435
436   /* Get path from configuration file */
437   if (GNUNET_YES !=
438       GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome",
439                                              &test_directory))
440   {
441     ok = 404;
442     return;
443   }
444
445   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "starting\n");
446
447   /* Get number of peers to start from configuration (should be two) */
448   if (GNUNET_SYSERR ==
449       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
450                                              &num_peers))
451     num_peers = DEFAULT_NUM_PEERS;
452
453   /* Set peers_left so we know when all peers started */
454   peers_left = num_peers;
455   
456   bob_daemon = NULL;
457   dave_daemon = NULL;
458   alice_daemon = NULL;
459
460   pg = GNUNET_TESTING_daemons_start (cfg, TEST_NUM_PEERS, TEST_NUM_CON,
461                                 TEST_NUM_CON, TIMEOUT, NULL, NULL, &daemon_started, NULL,
462                                 &daemon_connected, NULL, NULL);
463   
464   /* Set up a task to end testing if peer start fails */
465   die_task =
466       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly,
467                                     "didn't start all daemons in reasonable amount of time!!!");
468   
469   alice_online = 0;
470   bob_online = 0;
471   dave_online = 0;
472   expected_connections = 2;
473   
474   /* Start alice */
475   //d1 = GNUNET_TESTING_daemon_start(cfg_alice, TIMEOUT, GNUNET_NO, NULL, NULL, 0,
476   //                                 NULL, NULL, NULL, &alice_started, NULL);
477   
478   
479
480
481 }
482
483 static int
484 check ()
485 {
486   int ret;
487
488   /* Arguments for GNUNET_PROGRAM_run */
489   char *const argv[] = { "test-gns-twopeer",    /* Name to give running binary */
490     "-c",
491     "test_gns_dht_default.conf",       /* Config file to use */
492 #if VERBOSE
493     "-L", "DEBUG",
494 #endif
495     NULL
496   };
497   struct GNUNET_GETOPT_CommandLineOption options[] = {
498     GNUNET_GETOPT_OPTION_END
499   };
500   /* Run the run function as a new program */
501   ret =
502       GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
503                           "test-gns-threepeer", "nohelp", options, &run,
504                           &ok);
505   if (ret != GNUNET_OK)
506   {
507     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
508                 "`test-gns-threepeer': Failed with error code %d\n", ret);
509   }
510   return ok;
511 }
512
513 int
514 main (int argc, char *argv[])
515 {
516   int ret;
517
518   GNUNET_log_setup ("test-gns-threepeer",
519 #if VERBOSE
520                     "DEBUG",
521 #else
522                     "WARNING",
523 #endif
524                     NULL);
525   ret = check ();
526   /**
527    * Need to remove base directory, subdirectories taken care
528    * of by the testing framework.
529    */
530   return ret;
531 }
532
533 /* end of test_gns_threepeer.c */