2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @file gns/test_gns_dht_threepeer.c
22 * @brief tests dht lookup over 3 peers
25 * alice <----> bob <-----> dave
27 * alice queries for www.buddy.bob.gnunet
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"
42 #define VERBOSE GNUNET_YES
44 /* Timeout for entire testcase */
45 #define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 80)
47 /* If number of peers not in config file, use this number */
48 #define DEFAULT_NUM_PEERS 2
50 #define TEST_DOMAIN "www.buddy.bob.gnunet"
51 #define TEST_IP "1.1.1.1"
56 * Directory to store temp data in, defined in config file
58 static char *test_directory;
61 * Variable used to store the number of connections we should wait for.
63 static unsigned int expected_connections;
66 * Variable used to keep track of how many peers aren't yet started.
68 static unsigned long long peers_left;
70 struct GNUNET_TESTING_Daemon *d1;
71 struct GNUNET_TESTING_Daemon *d2;
72 struct GNUNET_TESTING_Daemon *d3;
76 * Total number of peers to run, set based on config file.
78 static unsigned long long num_peers;
81 * Global used to count how many connections we have currently
82 * been notified about (how many times has topology_callback been called
85 static unsigned int total_connections;
88 * Global used to count how many failed connections we have
89 * been notified about (how many times has topology_callback
90 * been called with failure?)
92 static unsigned int failed_connections;
94 /* Task handle to use to schedule test failure */
95 GNUNET_SCHEDULER_TaskIdentifier die_task;
97 GNUNET_SCHEDULER_TaskIdentifier bob_task;
99 /* Global return value (0 for success, anything else for failure) */
102 int bob_online, alice_online, dave_online;
104 struct GNUNET_CONFIGURATION_Handle *cfg_alice;
105 struct GNUNET_CONFIGURATION_Handle *cfg_bob;
106 struct GNUNET_CONFIGURATION_Handle *cfg_dave;
109 * Check whether peers successfully shut down.
112 shutdown_callback (void *cls, const char *emsg)
122 * Function scheduled to be run on the successful completion of this
123 * testcase. Specifically, called when our get request completes.
126 finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
129 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down alice!\n");
130 GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL,
131 GNUNET_YES, GNUNET_NO);
132 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down bob!\n");
133 GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &shutdown_callback, NULL,
134 GNUNET_YES, GNUNET_NO);
135 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down dave\n");
136 GNUNET_TESTING_daemon_stop (d3, TIMEOUT, &shutdown_callback, NULL,
137 GNUNET_YES, GNUNET_NO);
138 GNUNET_DISK_file_copy ("testdb/sqlite-alice.db.bak",
139 "testdb/sqlite-alice.db.bak");
140 GNUNET_SCHEDULER_cancel(die_task);
144 * Continuation for the GNUNET_DHT_get_stop call, so that we don't shut
145 * down the peers without freeing memory associated with GET request.
148 end_badly_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
151 GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &shutdown_callback, NULL,
152 GNUNET_YES, GNUNET_NO);
154 GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &shutdown_callback, NULL,
155 GNUNET_YES, GNUNET_NO);
158 GNUNET_TESTING_daemon_stop (d3, TIMEOUT, &shutdown_callback, NULL,
159 GNUNET_YES, GNUNET_NO);
163 * Check if the get_handle is being used, if so stop the request. Either
164 * way, schedule the end_badly_cont function which actually shuts down the
168 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
170 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Failing test with error: `%s'!\n",
172 GNUNET_SCHEDULER_add_now (&end_badly_cont, NULL);
177 commence_testing(void)
183 he = gethostbyname (TEST_DOMAIN);
187 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "name: %s\n", he->h_name);
188 while (*he->h_addr_list)
190 bcopy(*he->h_addr_list++, (char *) &a, sizeof(a));
192 GNUNET_log(GNUNET_ERROR_TYPE_INFO, "address: %s\n", addr);
193 if (strcmp(addr, TEST_IP) == 0)
200 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
201 (GNUNET_TIME_UNIT_SECONDS, 30),
202 &finish_testing, NULL);
207 * This function is called whenever a connection attempt is finished between two of
208 * the started peers (started with GNUNET_TESTING_daemons_start). The total
209 * number of times this function is called should equal the number returned
210 * from the GNUNET_TESTING_connect_topology call.
212 * The emsg variable is NULL on success (peers connected), and non-NULL on
213 * failure (peers failed to connect).
216 notify_connect (void *cls, const struct GNUNET_PeerIdentity *first,
217 const struct GNUNET_PeerIdentity *second, uint32_t distance,
218 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
219 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
220 struct GNUNET_TESTING_Daemon *first_daemon,
221 struct GNUNET_TESTING_Daemon *second_daemon,
228 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
229 "connected peer %s to peer %s, distance %u\n",
230 first_daemon->shortname, second_daemon->shortname, distance);
236 failed_connections++;
237 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
238 "Failed to connect peer %s to peer %s with error :\n%s\n",
239 first_daemon->shortname, second_daemon->shortname, emsg);
243 if (total_connections == expected_connections)
246 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
247 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
250 GNUNET_SCHEDULER_cancel (die_task);
252 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, "from connect");
256 else if (total_connections + failed_connections == expected_connections)
258 GNUNET_SCHEDULER_cancel (die_task);
260 GNUNET_SCHEDULER_add_now (&end_badly,
261 "from topology_callback (too many failed connections)");
265 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting peers dave, bob\n");
266 GNUNET_TESTING_daemons_connect (d3, d2, TIMEOUT, 5, 1,
267 ¬ify_connect, NULL);
272 * Set up some data, and call API PUT function
275 connect_ab (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
278 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting peers alice, bob\n");
279 GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, 5, 1,
280 ¬ify_connect, NULL);
285 dave_started (void *cls, const struct GNUNET_PeerIdentity *id,
286 const struct GNUNET_CONFIGURATION_Handle *cfg,
287 struct GNUNET_TESTING_Daemon *d, const char *emsg)
291 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
292 "Failed to start daemon with error: `%s'\n", emsg);
295 GNUNET_assert (id != NULL);
297 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
298 (GNUNET_TIME_UNIT_SECONDS, 2),
305 bob_started (void *cls, const struct GNUNET_PeerIdentity *id,
306 const struct GNUNET_CONFIGURATION_Handle *cfg,
307 struct GNUNET_TESTING_Daemon *d, const char *emsg)
311 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
312 "Failed to start daemon with error: `%s'\n", emsg);
315 GNUNET_assert (id != NULL);
318 d3 = GNUNET_TESTING_daemon_start(cfg_dave, TIMEOUT, GNUNET_NO, NULL, NULL, 0,
319 NULL, NULL, NULL, &dave_started, NULL);
326 * Callback which is called whenever a peer is started (as a result of the
327 * GNUNET_TESTING_daemons_start call.
329 * @param cls closure argument given to GNUNET_TESTING_daemons_start
330 * @param id the GNUNET_PeerIdentity of the started peer
331 * @param cfg the configuration for this specific peer (needed to connect
333 * @param d the handle to the daemon started
334 * @param emsg NULL if peer started, non-NULL on error
337 alice_started (void *cls, const struct GNUNET_PeerIdentity *id,
338 const struct GNUNET_CONFIGURATION_Handle *cfg,
339 struct GNUNET_TESTING_Daemon *d, const char *emsg)
343 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
344 "Failed to start daemon with error: `%s'\n", emsg);
347 GNUNET_assert (id != NULL);
350 d2 = GNUNET_TESTING_daemon_start(cfg_bob, TIMEOUT, GNUNET_NO, NULL, NULL, 0,
351 NULL, NULL, NULL, &bob_started, NULL);
356 run (void *cls, char *const *args, const char *cfgfile,
357 const struct GNUNET_CONFIGURATION_Handle *cfg)
360 /* Get path from configuration file */
362 GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome",
369 /* Get number of peers to start from configuration (should be two) */
371 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
373 num_peers = DEFAULT_NUM_PEERS;
375 /* Set peers_left so we know when all peers started */
376 peers_left = num_peers;
379 * Modify some config options for peers
381 cfg_alice = GNUNET_CONFIGURATION_create();
382 GNUNET_CONFIGURATION_load (cfg_alice, "test_gns_dht_alice.conf");
384 cfg_bob = GNUNET_CONFIGURATION_create();
385 GNUNET_CONFIGURATION_load (cfg_bob, "test_gns_dht_bob.conf");
387 cfg_dave = GNUNET_CONFIGURATION_create();
388 GNUNET_CONFIGURATION_load (cfg_dave, "test_gns_dht_dave.conf");
390 GNUNET_CONFIGURATION_load (cfg_alice, "test_gns_dht_alice.conf");
391 GNUNET_CONFIGURATION_load (cfg_bob, "test_gns_dht_bob.conf");
392 GNUNET_CONFIGURATION_load (cfg_dave, "test_gns_dht_dave.conf");
394 /* Set up a task to end testing if peer start fails */
396 GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly,
397 "didn't start all daemons in reasonable amount of time!!!");
402 expected_connections = 2;
405 d1 = GNUNET_TESTING_daemon_start(cfg_alice, TIMEOUT, GNUNET_NO, NULL, NULL, 0,
406 NULL, NULL, NULL, &alice_started, NULL);
418 /* Arguments for GNUNET_PROGRAM_run */
419 char *const argv[] = { "test-gns-twopeer", /* Name to give running binary */
421 "test_gns_twopeer.conf", /* Config file to use */
427 struct GNUNET_GETOPT_CommandLineOption options[] = {
428 GNUNET_GETOPT_OPTION_END
430 /* Run the run function as a new program */
432 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
433 "test-gns-twopeer", "nohelp", options, &run,
435 if (ret != GNUNET_OK)
437 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
438 "`test-gns-twopeer': Failed with error code %d\n", ret);
444 main (int argc, char *argv[])
448 GNUNET_log_setup ("test-gns-twopeer",
457 * Need to remove base directory, subdirectories taken care
458 * of by the testing framework.
463 /* end of test_gns_twopeer.c */