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 dht/gnunet-dht-driver.c
22 * @brief Driver for setting up a group of gnunet peers and
23 * then issuing GETS and PUTS on the DHT. Coarse results
24 * are reported, fine grained results (if requested) are
25 * logged to a (mysql) database, or to file.
30 #include "gnunet_testing_lib.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_dht_service.h"
37 #define VERBOSE GNUNET_NO
39 /* Timeout for entire driver to run */
40 #define DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
42 /* Timeout for waiting for (individual) replies to get requests */
43 #define DEFAULT_GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
45 #define DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
47 /* Timeout for waiting for gets to be sent to the service */
48 #define DEFAULT_GET_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
50 /* Timeout for waiting for puts to be sent to the service */
51 #define DEFAULT_PUT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
53 /* Time to allow a find peer request to take */
54 #define DEFAULT_FIND_PEER_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40)
56 /* Time to wait for all peers disconnected due to to churn to actually be removed from system */
57 #define DEFAULT_PEER_DISCONNECT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
59 #define DEFAULT_SECONDS_PER_PEER_START GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 45)
61 #define DEFAULT_TEST_DATA_SIZE 8
63 #define DEFAULT_BUCKET_SIZE 4
65 #define FIND_PEER_THRESHOLD 1
67 /* If more than this many peers are added, slow down sending */
68 #define MAX_FIND_PEER_CUTOFF 2500
70 /* If less than this many peers are added, speed up sending */
71 #define MIN_FIND_PEER_CUTOFF 500
73 #define DEFAULT_MAX_OUTSTANDING_PUTS 10
75 #define DEFAULT_MAX_OUTSTANDING_FIND_PEERS 64
77 #define DEFAULT_FIND_PEER_OFFSET GNUNET_TIME_relative_divide (DEFAULT_FIND_PEER_DELAY, DEFAULT_MAX_OUTSTANDING_FIND_PEERS)
79 #define DEFAULT_MAX_OUTSTANDING_GETS 10
81 #define DEFAULT_CONNECT_TIMEOUT 60
83 #define DEFAULT_TOPOLOGY_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 8)
85 #define DEFAULT_RECONNECT_ATTEMPTS 8
88 * Default frequency for sending malicious get messages
90 #define DEFAULT_MALICIOUS_GET_FREQUENCY 1000 /* Number of milliseconds */
93 * Default frequency for sending malicious put messages
95 #define DEFAULT_MALICIOUS_PUT_FREQUENCY 1000 /* Default is in milliseconds */
99 struct MaliciousContext
102 * Handle to DHT service (via the API)
104 struct GNUNET_DHT_Handle *dht_handle;
107 * Handle to the peer daemon
109 struct GNUNET_TESTING_Daemon *daemon;
112 * Task for disconnecting DHT handles
114 GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
117 * What type of malicious to set this peer to.
124 /* This is a linked list */
125 struct TestFindPeer *next;
127 /* Handle to the bigger context */
128 struct FindPeerContext *find_peer_context;
131 * Handle to the peer's DHT service (via the API)
133 struct GNUNET_DHT_Handle *dht_handle;
136 * Handle to the peer daemon
138 struct GNUNET_TESTING_Daemon *daemon;
141 * Task for disconnecting DHT handles
143 GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
146 struct TestPutContext
148 /* This is a linked list */
149 struct TestPutContext *next;
152 * Handle to the first peers DHT service (via the API)
154 struct GNUNET_DHT_Handle *dht_handle;
157 * Handle to the PUT peer daemon
159 struct GNUNET_TESTING_Daemon *daemon;
162 * Identifier for this PUT
167 * Task for disconnecting DHT handles
169 GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
172 struct TestGetContext
174 /* This is a linked list */
175 struct TestGetContext *next;
178 * Handle to the first peers DHT service (via the API)
180 struct GNUNET_DHT_Handle *dht_handle;
183 * Handle for the DHT get request
185 struct GNUNET_DHT_GetHandle *get_handle;
188 * Handle to the GET peer daemon
190 struct GNUNET_TESTING_Daemon *daemon;
193 * Identifier for this GET
198 * Task for disconnecting DHT handles (and stopping GET)
200 GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
203 * Whether or not this request has been fulfilled already.
209 * Simple struct to keep track of progress, and print a
210 * nice little percentage meter for long running tasks.
220 unsigned int completed;
224 char *startup_string;
228 * Linked list of information for populating statistics
229 * before ending trial.
231 struct StatisticsIteratorContext
233 const struct GNUNET_PeerIdentity *peer;
234 unsigned int stat_routes;
235 unsigned int stat_route_forwards;
236 unsigned int stat_results;
237 unsigned int stat_results_to_client;
238 unsigned int stat_result_forwards;
239 unsigned int stat_gets;
240 unsigned int stat_puts;
241 unsigned int stat_puts_inserted;
242 unsigned int stat_find_peer;
243 unsigned int stat_find_peer_start;
244 unsigned int stat_get_start;
245 unsigned int stat_put_start;
246 unsigned int stat_find_peer_reply;
247 unsigned int stat_get_reply;
248 unsigned int stat_find_peer_answer;
249 unsigned int stat_get_response_start;
253 * Context for getting a topology, logging it, and continuing
254 * on with some next operation.
256 struct TopologyIteratorContext
258 unsigned int total_iterations;
259 unsigned int current_iteration;
260 unsigned int total_connections;
261 unsigned int total_peers;
262 struct GNUNET_CONTAINER_MultiHashMap *peers_seen;
263 struct GNUNET_PeerIdentity *peer;
264 GNUNET_SCHEDULER_Task cont;
266 struct GNUNET_TIME_Relative timeout;
272 /** Node in the heap */
273 struct GNUNET_CONTAINER_HeapNode *heap_node;
275 /** Peer the count refers to */
276 struct GNUNET_PeerIdentity peer_id;
278 /** Count of connections this peer has */
283 * Context for sending out find peer requests.
285 struct FindPeerContext
288 * How long to send find peer requests, once the settle time
289 * is over don't send any more out!
291 * TODO: Add option for settle time and find peer sending time?
293 struct GNUNET_TIME_Absolute endtime;
296 * Number of connections in the current topology
297 * (after this round of find peer requests has ended).
299 unsigned int current_peers;
302 * Number of connections in the current topology
303 * (before this round of find peer requests started).
305 unsigned int previous_peers;
308 * Number of find peer requests we have currently
311 unsigned int outstanding;
314 * Number of find peer requests to send in this round.
319 * Number of find peer requests sent last time around.
321 unsigned int last_sent;
324 * Hashmap of peers in the current topology, value
325 * is a PeerCount, with the number of connections
328 struct GNUNET_CONTAINER_MultiHashMap *peer_hash;
331 * Min heap which orders values in the peer_hash for
334 struct GNUNET_CONTAINER_Heap *peer_min_heap;
337 * Callback for counting the peers in the current topology.
339 GNUNET_TESTING_NotifyTopology count_peers_cb;
345 * Next full round (puts + gets).
350 * Next round of gets.
355 * Next round of puts.
360 * Next round of churn.
370 * Timeout to let all get requests happen.
372 static struct GNUNET_TIME_Relative all_get_timeout;
377 static struct GNUNET_TIME_Relative get_timeout;
379 static struct GNUNET_TIME_Relative get_delay;
381 static struct GNUNET_TIME_Relative put_delay;
383 static struct GNUNET_TIME_Relative find_peer_delay;
385 static struct GNUNET_TIME_Relative find_peer_offset;
387 static struct GNUNET_TIME_Relative seconds_per_peer_start;
389 static unsigned int do_find_peer;
391 static unsigned int in_dht_replication;
393 static unsigned long long test_data_size = DEFAULT_TEST_DATA_SIZE;
395 static unsigned long long max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS;
397 static unsigned long long max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS;
399 static unsigned long long malicious_getters;
401 static unsigned long long max_outstanding_find_peers;
403 static unsigned long long malicious_putters;
405 static unsigned long long round_delay;
407 static unsigned long long malicious_droppers;
409 static unsigned long long malicious_get_frequency;
411 static unsigned long long malicious_put_frequency;
413 static unsigned long long settle_time;
415 static unsigned long long trial_to_run;
417 static struct GNUNET_DHTLOG_Handle *dhtlog_handle;
419 static unsigned long long trialuid;
422 * If GNUNET_YES, insert data at the same peers every time.
423 * Otherwise, choose a new random peer to insert at each time.
425 static unsigned int replicate_same;
428 * Number of rounds for testing (PUTS + GETS)
430 static unsigned long long total_rounds;
433 * Number of rounds already run
435 static unsigned int rounds_finished;
438 * Number of rounds of churn to read from the file (first line, should be a single number).
440 static unsigned int churn_rounds;
443 * Current round we are in for churn, tells us how many peers to connect/disconnect.
445 static unsigned int current_churn_round;
448 * Number of times to churn per round
450 static unsigned long long churns_per_round;
453 * Array of churn values.
455 static unsigned int *churn_array;
458 * Hash map of stats contexts.
460 struct GNUNET_CONTAINER_MultiHashMap *stats_map;
463 * LL of malicious settings.
465 struct MaliciousContext *all_malicious;
468 * List of GETS to perform
470 struct TestGetContext *all_gets;
473 * List of PUTS to perform
475 struct TestPutContext *all_puts;
478 * Directory to store temporary data in, defined in config file
480 static char *test_directory;
483 * Variable used to store the number of connections we should wait for.
485 static unsigned int expected_connections;
488 * Variable used to keep track of how many peers aren't yet started.
490 static unsigned long long peers_left;
493 * Handle to the set of all peers run for this test.
495 static struct GNUNET_TESTING_PeerGroup *pg;
498 * Global scheduler, used for all GNUNET_SCHEDULER_* functions.
500 static struct GNUNET_SCHEDULER_Handle *sched;
503 * Global config handle.
505 const struct GNUNET_CONFIGURATION_Handle *config;
508 * Total number of peers to run, set based on config file.
510 static unsigned long long num_peers;
513 * Total number of items to insert.
515 static unsigned long long num_puts;
518 * How many puts do we currently have in flight?
520 static unsigned long long outstanding_puts;
523 * How many puts are done?
525 static unsigned long long puts_completed;
528 * Total number of items to attempt to get.
530 static unsigned long long num_gets;
533 * How many puts do we currently have in flight?
535 static unsigned long long outstanding_gets;
538 * How many gets are done?
540 static unsigned long long gets_completed;
543 * How many gets failed?
545 static unsigned long long gets_failed;
548 * How many malicious control messages do
549 * we currently have in flight?
551 static unsigned long long outstanding_malicious;
554 * How many set malicious peers are done?
556 static unsigned long long malicious_completed;
559 * Global used to count how many connections we have currently
560 * been notified about (how many times has topology_callback been called
563 static unsigned int total_connections;
566 * Global used to count how many failed connections we have
567 * been notified about (how many times has topology_callback
568 * been called with failure?)
570 static unsigned int failed_connections;
572 /* Task handle to use to schedule shutdown if something goes wrong */
573 GNUNET_SCHEDULER_TaskIdentifier die_task;
575 static char *blacklist_transports;
577 static enum GNUNET_TESTING_Topology topology;
579 static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */
581 static enum GNUNET_TESTING_Topology connect_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */
583 static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL;
585 static double connect_topology_option_modifier = 0.0;
587 static struct ProgressMeter *hostkey_meter;
589 static struct ProgressMeter *peer_start_meter;
591 static struct ProgressMeter *peer_connect_meter;
593 static struct ProgressMeter *put_meter;
595 static struct ProgressMeter *get_meter;
597 static GNUNET_HashCode *known_keys;
599 /* Global return value (0 for success, anything else for failure) */
603 * Create a meter to keep track of the progress of some task.
605 * @param total the total number of items to complete
606 * @param start_string a string to prefix the meter with (if printing)
607 * @param print GNUNET_YES to print the meter, GNUNET_NO to count
610 * @return the progress meter
612 static struct ProgressMeter *
613 create_meter(unsigned int total, char * start_string, int print)
615 struct ProgressMeter *ret;
616 ret = GNUNET_malloc(sizeof(struct ProgressMeter));
619 ret->modnum = total / 4;
620 ret->dotnum = (total / 50) + 1;
621 if (start_string != NULL)
622 ret->startup_string = GNUNET_strdup(start_string);
624 ret->startup_string = GNUNET_strdup("");
630 * Update progress meter (increment by one).
632 * @param meter the meter to update and print info for
634 * @return GNUNET_YES if called the total requested,
635 * GNUNET_NO if more items expected
638 update_meter(struct ProgressMeter *meter)
640 if (meter->print == GNUNET_YES)
642 if (meter->completed % meter->modnum == 0)
644 if (meter->completed == 0)
646 fprintf(stdout, "%sProgress: [0%%", meter->startup_string);
649 fprintf(stdout, "%d%%", (int)(((float)meter->completed / meter->total) * 100));
651 else if (meter->completed % meter->dotnum == 0)
652 fprintf(stdout, ".");
654 if (meter->completed + 1 == meter->total)
655 fprintf(stdout, "%d%%]\n", 100);
660 if (meter->completed == meter->total)
666 * Reset progress meter.
668 * @param meter the meter to reset
670 * @return GNUNET_YES if meter reset,
671 * GNUNET_SYSERR on error
674 reset_meter(struct ProgressMeter *meter)
677 return GNUNET_SYSERR;
679 meter->completed = 0;
684 * Release resources for meter
686 * @param meter the meter to free
689 free_meter(struct ProgressMeter *meter)
691 GNUNET_free_non_null(meter->startup_string);
692 GNUNET_free_non_null(meter);
696 * Check whether peers successfully shut down.
698 void shutdown_callback (void *cls,
709 * Task to release DHT handles for PUT
712 put_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
714 struct TestPutContext *test_put = cls;
715 test_put->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
716 GNUNET_DHT_disconnect(test_put->dht_handle);
717 test_put->dht_handle = NULL;
718 test_put->daemon = GNUNET_TESTING_daemon_get(pg, GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
722 * Function scheduled to be run on the successful completion of this
726 finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
728 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending test normally!\n", (char *)cls);
729 GNUNET_assert (pg != NULL);
730 struct TestPutContext *test_put = all_puts;
731 struct TestGetContext *test_get = all_gets;
733 while (test_put != NULL)
735 if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
736 GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task);
737 if (test_put->dht_handle != NULL)
738 GNUNET_DHT_disconnect(test_put->dht_handle);
739 test_put = test_put->next;
742 while (test_get != NULL)
744 if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
745 GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task);
746 if (test_get->get_handle != NULL)
747 GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL);
748 if (test_get->dht_handle != NULL)
749 GNUNET_DHT_disconnect(test_get->dht_handle);
750 test_get = test_get->next;
753 GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL);
755 if (dhtlog_handle != NULL)
757 fprintf(stderr, "Update trial endtime\n");
758 dhtlog_handle->update_trial (trialuid, gets_completed);
759 GNUNET_DHTLOG_disconnect(dhtlog_handle);
760 dhtlog_handle = NULL;
763 if (hostkey_meter != NULL)
764 free_meter(hostkey_meter);
765 if (peer_start_meter != NULL)
766 free_meter(peer_start_meter);
767 if (peer_connect_meter != NULL)
768 free_meter(peer_connect_meter);
769 if (put_meter != NULL)
770 free_meter(put_meter);
771 if (get_meter != NULL)
772 free_meter(get_meter);
778 * Callback for iterating over all the peer connections of a peer group.
780 void log_topology_cb (void *cls,
781 const struct GNUNET_PeerIdentity *first,
782 const struct GNUNET_PeerIdentity *second,
783 struct GNUNET_TIME_Relative latency,
787 struct TopologyIteratorContext *topo_ctx = cls;
788 if ((first != NULL) && (second != NULL))
790 if ((topo_ctx->peers_seen != NULL) && (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(topo_ctx->peers_seen, &first->hashPubKey)))
792 GNUNET_CONTAINER_multihashmap_put(topo_ctx->peers_seen, &first->hashPubKey, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
793 topo_ctx->total_peers++;
795 topo_ctx->total_connections++;
796 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(config, "dht_testing", "mysql_logging_extended"))
797 dhtlog_handle->insert_extended_topology(first, second);
801 GNUNET_assert(dhtlog_handle != NULL);
802 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Topology iteration (%u/%u) finished (%u connections, %u peers)\n", topo_ctx->current_iteration, topo_ctx->total_iterations, topo_ctx->total_connections, topo_ctx->total_peers);
803 dhtlog_handle->update_topology(topo_ctx->total_connections);
804 if (topo_ctx->cont != NULL)
805 GNUNET_SCHEDULER_add_now (sched, topo_ctx->cont, topo_ctx->cls);
806 if (topo_ctx->peers_seen != NULL)
807 GNUNET_CONTAINER_multihashmap_destroy(topo_ctx->peers_seen);
808 GNUNET_free(topo_ctx);
813 * Iterator over hash map entries.
815 * @param cls closure - always NULL
816 * @param key current key code
817 * @param value value in the hash map, a stats context
818 * @return GNUNET_YES if we should continue to
822 static int stats_iterate (void *cls,
823 const GNUNET_HashCode * key,
826 struct StatisticsIteratorContext *stats_ctx;
830 dhtlog_handle->insert_stat(stats_ctx->peer, stats_ctx->stat_routes, stats_ctx->stat_route_forwards, stats_ctx->stat_results,
831 stats_ctx->stat_results_to_client, stats_ctx->stat_result_forwards, stats_ctx->stat_gets,
832 stats_ctx->stat_puts, stats_ctx->stat_puts_inserted, stats_ctx->stat_find_peer,
833 stats_ctx->stat_find_peer_start, stats_ctx->stat_get_start, stats_ctx->stat_put_start,
834 stats_ctx->stat_find_peer_reply, stats_ctx->stat_get_reply, stats_ctx->stat_find_peer_answer,
835 stats_ctx->stat_get_response_start);
836 GNUNET_free(stats_ctx);
840 static void stats_finished (void *cls, int result)
842 fprintf(stderr, "Finished getting all peers statistics, iterating!\n");
843 GNUNET_CONTAINER_multihashmap_iterate(stats_map, &stats_iterate, NULL);
844 GNUNET_CONTAINER_multihashmap_destroy(stats_map);
845 GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
849 * Callback function to process statistic values.
852 * @param peer the peer the statistics belong to
853 * @param subsystem name of subsystem that created the statistic
854 * @param name the name of the datum
855 * @param value the current value
856 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
857 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
859 static int stats_handle (void *cls,
860 const struct GNUNET_PeerIdentity *peer,
861 const char *subsystem,
866 struct StatisticsIteratorContext *stats_ctx;
868 if (dhtlog_handle != NULL)
869 dhtlog_handle->add_generic_stat(peer, name, subsystem, value);
870 if (GNUNET_CONTAINER_multihashmap_contains(stats_map, &peer->hashPubKey))
872 stats_ctx = GNUNET_CONTAINER_multihashmap_get(stats_map, &peer->hashPubKey);
876 stats_ctx = GNUNET_malloc(sizeof(struct StatisticsIteratorContext));
877 stats_ctx->peer = peer;
878 GNUNET_CONTAINER_multihashmap_put(stats_map, &peer->hashPubKey, stats_ctx, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
880 GNUNET_assert(stats_ctx != NULL);
882 if (strcmp(name, STAT_ROUTES) == 0)
883 stats_ctx->stat_routes = value;
884 else if (strcmp(name, STAT_ROUTE_FORWARDS) == 0)
885 stats_ctx->stat_route_forwards = value;
886 else if (strcmp(name, STAT_RESULTS) == 0)
887 stats_ctx->stat_results = value;
888 else if (strcmp(name, STAT_RESULTS_TO_CLIENT) == 0)
889 stats_ctx->stat_results_to_client = value;
890 else if (strcmp(name, STAT_RESULT_FORWARDS) == 0)
891 stats_ctx->stat_result_forwards = value;
892 else if (strcmp(name, STAT_GETS) == 0)
893 stats_ctx->stat_gets = value;
894 else if (strcmp(name, STAT_PUTS) == 0)
895 stats_ctx->stat_puts = value;
896 else if (strcmp(name, STAT_PUTS_INSERTED) == 0)
897 stats_ctx->stat_puts_inserted = value;
898 else if (strcmp(name, STAT_FIND_PEER) == 0)
899 stats_ctx->stat_find_peer = value;
900 else if (strcmp(name, STAT_FIND_PEER_START) == 0)
901 stats_ctx->stat_find_peer_start = value;
902 else if (strcmp(name, STAT_GET_START) == 0)
903 stats_ctx->stat_get_start = value;
904 else if (strcmp(name, STAT_PUT_START) == 0)
905 stats_ctx->stat_put_start = value;
906 else if (strcmp(name, STAT_FIND_PEER_REPLY) == 0)
907 stats_ctx->stat_find_peer_reply = value;
908 else if (strcmp(name, STAT_GET_REPLY) == 0)
909 stats_ctx->stat_get_reply = value;
910 else if (strcmp(name, STAT_FIND_PEER_ANSWER) == 0)
911 stats_ctx->stat_find_peer_answer = value;
912 else if (strcmp(name, STAT_GET_RESPONSE_START) == 0)
913 stats_ctx->stat_get_response_start = value;
919 * Connect to statistics service for each peer and get the appropriate
920 * dht statistics for safe keeping.
923 log_dht_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
925 stats_map = GNUNET_CONTAINER_multihashmap_create(num_peers);
926 fprintf(stderr, "Starting statistics logging\n");
927 GNUNET_TESTING_get_statistics(pg, &stats_finished, &stats_handle, NULL);
932 * Connect to all peers in the peer group and iterate over their
936 capture_current_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
938 struct TopologyIteratorContext *topo_ctx = cls;
939 dhtlog_handle->insert_topology(0);
940 GNUNET_TESTING_get_topology (pg, &log_topology_cb, topo_ctx);
945 * Check if the get_handle is being used, if so stop the request. Either
946 * way, schedule the end_badly_cont function which actually shuts down the
950 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
952 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failing test with error: `%s'!\n", (char *)cls);
954 struct TestPutContext *test_put = all_puts;
955 struct TestGetContext *test_get = all_gets;
957 while (test_put != NULL)
959 if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
960 GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task);
961 if (test_put->dht_handle != NULL)
962 GNUNET_DHT_disconnect(test_put->dht_handle);
963 test_put = test_put->next;
966 while (test_get != NULL)
968 if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
969 GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task);
970 if (test_get->get_handle != NULL)
971 GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL);
972 if (test_get->dht_handle != NULL)
973 GNUNET_DHT_disconnect(test_get->dht_handle);
974 test_get = test_get->next;
977 GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL);
979 if (dhtlog_handle != NULL)
981 fprintf(stderr, "Update trial endtime\n");
982 dhtlog_handle->update_trial (trialuid, gets_completed);
983 GNUNET_DHTLOG_disconnect(dhtlog_handle);
984 dhtlog_handle = NULL;
987 if (hostkey_meter != NULL)
988 free_meter(hostkey_meter);
989 if (peer_start_meter != NULL)
990 free_meter(peer_start_meter);
991 if (peer_connect_meter != NULL)
992 free_meter(peer_connect_meter);
993 if (put_meter != NULL)
994 free_meter(put_meter);
995 if (get_meter != NULL)
996 free_meter(get_meter);
1002 * Forward declaration.
1005 do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
1008 * Forward declaration.
1011 do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
1014 * Iterator over hash map entries.
1016 * @param cls closure
1017 * @param key current key code
1018 * @param value value in the hash map
1019 * @return GNUNET_YES if we should continue to
1023 static int remove_peer_count (void *cls,
1024 const GNUNET_HashCode * key,
1027 struct FindPeerContext *find_peer_ctx = cls;
1028 struct PeerCount *peer_count = value;
1029 GNUNET_CONTAINER_heap_remove_node(find_peer_ctx->peer_min_heap, peer_count->heap_node);
1030 GNUNET_free(peer_count);
1036 * Connect to all peers in the peer group and iterate over their
1040 count_new_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1042 struct FindPeerContext *find_peer_context = cls;
1043 find_peer_context->previous_peers = find_peer_context->current_peers;
1044 find_peer_context->current_peers = 0;
1045 GNUNET_TESTING_get_topology (pg, find_peer_context->count_peers_cb, find_peer_context);
1049 decrement_find_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1051 struct TestFindPeer *test_find_peer = cls;
1052 GNUNET_assert(test_find_peer->find_peer_context->outstanding > 0);
1053 test_find_peer->find_peer_context->outstanding--;
1054 test_find_peer->find_peer_context->total--;
1055 if ((0 == test_find_peer->find_peer_context->total) &&
1056 (GNUNET_TIME_absolute_get_remaining(test_find_peer->find_peer_context->endtime).value > 0))
1058 GNUNET_SCHEDULER_add_now(sched, &count_new_peers, test_find_peer->find_peer_context);
1060 GNUNET_free(test_find_peer);
1064 * A find peer request has been sent to the server, now we will schedule a task
1065 * to wait the appropriate time to allow the request to go out and back.
1067 * @param cls closure - a TestFindPeer struct
1068 * @param tc context the task is being called with
1071 handle_find_peer_sent (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1073 struct TestFindPeer *test_find_peer = cls;
1075 GNUNET_DHT_disconnect(test_find_peer->dht_handle);
1076 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_divide(find_peer_delay, 2), &decrement_find_peers, test_find_peer);
1081 send_find_peer_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1083 struct TestFindPeer *test_find_peer = cls;
1085 if (test_find_peer->find_peer_context->outstanding > max_outstanding_find_peers)
1087 GNUNET_SCHEDULER_add_delayed(sched, find_peer_offset, &send_find_peer_request, test_find_peer);
1091 test_find_peer->find_peer_context->outstanding++;
1092 if (GNUNET_TIME_absolute_get_remaining(test_find_peer->find_peer_context->endtime).value == 0)
1094 GNUNET_SCHEDULER_add_now(sched, &decrement_find_peers, test_find_peer);
1098 test_find_peer->dht_handle = GNUNET_DHT_connect(sched, test_find_peer->daemon->cfg, 1);
1099 GNUNET_assert(test_find_peer->dht_handle != NULL);
1100 GNUNET_DHT_find_peers (test_find_peer->dht_handle,
1101 &handle_find_peer_sent, test_find_peer);
1106 * Add a connection to the find_peer_context given. This may
1107 * be complete overkill, but allows us to choose the peers with
1108 * the least connections to initiate find peer requests from.
1110 static void add_new_connection(struct FindPeerContext *find_peer_context,
1111 const struct GNUNET_PeerIdentity *first,
1112 const struct GNUNET_PeerIdentity *second)
1114 struct PeerCount *first_count;
1115 struct PeerCount *second_count;
1117 if (GNUNET_CONTAINER_multihashmap_contains(find_peer_context->peer_hash, &first->hashPubKey))
1119 first_count = GNUNET_CONTAINER_multihashmap_get(find_peer_context->peer_hash, &first->hashPubKey);
1120 first_count->count++;
1121 GNUNET_CONTAINER_heap_update_cost(find_peer_context->peer_min_heap, first_count->heap_node, first_count->count);
1125 first_count = GNUNET_malloc(sizeof(struct PeerCount));
1126 first_count->count = 1;
1127 memcpy(&first_count->peer_id, first, sizeof(struct GNUNET_PeerIdentity));
1128 first_count->heap_node = GNUNET_CONTAINER_heap_insert(find_peer_context->peer_min_heap, first_count, first_count->count);
1129 GNUNET_CONTAINER_multihashmap_put(find_peer_context->peer_hash, &first->hashPubKey, first_count, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1132 if (GNUNET_CONTAINER_multihashmap_contains(find_peer_context->peer_hash, &second->hashPubKey))
1134 second_count = GNUNET_CONTAINER_multihashmap_get(find_peer_context->peer_hash, &second->hashPubKey);
1135 second_count->count++;
1136 GNUNET_CONTAINER_heap_update_cost(find_peer_context->peer_min_heap, second_count->heap_node, second_count->count);
1140 second_count = GNUNET_malloc(sizeof(struct PeerCount));
1141 second_count->count = 1;
1142 memcpy(&second_count->peer_id, second, sizeof(struct GNUNET_PeerIdentity));
1143 second_count->heap_node = GNUNET_CONTAINER_heap_insert(find_peer_context->peer_min_heap, second_count, second_count->count);
1144 GNUNET_CONTAINER_multihashmap_put(find_peer_context->peer_hash, &second->hashPubKey, second_count, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1150 * Iterate over min heap of connections per peer. For any
1151 * peer that has 0 connections, attempt to connect them to
1154 * @param cls closure a struct FindPeerContext
1155 * @param node internal node of the heap
1156 * @param element value stored, a struct PeerCount
1157 * @param cost cost associated with the node
1158 * @return GNUNET_YES if we should continue to iterate,
1161 static int iterate_min_heap_peers (void *cls,
1162 struct GNUNET_CONTAINER_HeapNode *node,
1164 GNUNET_CONTAINER_HeapCostType cost)
1166 struct FindPeerContext *find_peer_context = cls;
1167 struct PeerCount *peer_count = element;
1168 struct GNUNET_TESTING_Daemon *d1;
1169 struct GNUNET_TESTING_Daemon *d2;
1170 struct GNUNET_TIME_Relative timeout;
1173 d1 = GNUNET_TESTING_daemon_get_by_id (pg, &peer_count->peer_id);
1175 while ((d2 == d1) || (GNUNET_YES != GNUNET_TESTING_daemon_running(d2)))
1177 d2 = GNUNET_TESTING_daemon_get(pg, GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
1180 /** Just try to connect the peers, don't worry about callbacks, etc. **/
1181 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Peer %s has 0 connections. Trying to connect to %s...\n", GNUNET_i2s(&peer_count->peer_id), d2->shortname);
1182 timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, DEFAULT_CONNECT_TIMEOUT);
1183 if (GNUNET_TIME_relative_to_absolute(timeout).value > find_peer_context->endtime.value)
1185 timeout = GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime);
1187 GNUNET_TESTING_daemons_connect(d1, d2, timeout, DEFAULT_RECONNECT_ATTEMPTS, NULL, NULL);
1189 if (GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime).value > 0)
1196 * Forward declaration.
1199 schedule_churn_find_peer_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
1202 * Callback for iterating over all the peer connections of a peer group.
1203 * Used after we have churned on some peers to find which ones have zero
1204 * connections so we can make them issue find peer requests.
1206 void count_peers_churn_cb (void *cls,
1207 const struct GNUNET_PeerIdentity *first,
1208 const struct GNUNET_PeerIdentity *second,
1209 struct GNUNET_TIME_Relative latency,
1213 struct FindPeerContext *find_peer_context = cls;
1214 struct TopologyIteratorContext *topo_ctx;
1215 struct PeerCount *peer_count;
1217 if ((first != NULL) && (second != NULL))
1219 add_new_connection(find_peer_context, first, second);
1220 find_peer_context->current_peers++;
1224 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Peer count finished (%u connections)\n",
1225 find_peer_context->current_peers);
1226 peer_count = GNUNET_CONTAINER_heap_peek(find_peer_context->peer_min_heap);
1228 /* WAIT. When peers are churned they will come back with their peers (at least in peerinfo), because the HOSTS file doesn't likely get removed. CRAP. */
1229 /* NO they won't, because we have disabled peerinfo writing to disk (remember?) so we WILL have to give them new connections */
1230 /* Best course of action: have DHT automatically try to add peers from peerinfo on startup. This way IF peerinfo writes to file
1231 * then some peers will end up connected.
1233 * Also, find any peers that have zero connections here and set up a task to choose at random another peer in the network to
1234 * connect to. Of course, if they are blacklisted from that peer they won't be able to connect, so we will have to keep trying
1235 * until they get a peer.
1237 /* However, they won't automatically be connected to any of their previous peers... How can we handle that? */
1238 /* So now we have choices: do we want them to come back with all their connections? Probably not, but it solves this mess. */
1240 /* Second problem, which is still a problem, is that a FIND_PEER request won't work when a peer has no connections */
1243 * Okay, so here's how this *should* work now.
1245 * 1. We check the min heap for any peers that have 0 connections.
1246 * a. If any are found, we iterate over the heap and just randomly
1247 * choose another peer and ask testing to please connect the two.
1248 * This takes care of the case that a peer just randomly joins the
1249 * network. However, if there are strict topology restrictions
1250 * (imagine a ring) choosing randomly most likely won't help.
1251 * We make sure the connection attempt doesn't take longer than
1252 * the total timeout, but don't care too much about the result.
1253 * b. After that, we still schedule the find peer requests (concurrently
1254 * with the connect attempts most likely). This handles the case
1255 * that the DHT iterates over peerinfo and just needs to try to send
1256 * a message to get connected. This should handle the case that the
1257 * topology is very strict.
1259 * 2. If all peers have > 0 connections, we still send find peer requests
1260 * as long as possible (until timeout is reached) to help out those
1261 * peers that were newly churned and need more connections. This is because
1262 * once all new peers have established a single connection, they won't be
1265 * 3. Once we reach the timeout, we can do no more. We must schedule the
1266 * next iteration of get requests regardless of connections that peers
1267 * may or may not have.
1269 * Caveat: it would be nice to get peers to take data offline with them and
1270 * come back with it (or not) based on the testing framework. The
1271 * same goes for remembering previous connections, but putting either
1272 * into the general testing churn options seems like overkill because
1273 * these are very specialized cases.
1275 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Out of %u peers, fewest connections is %d\n", GNUNET_CONTAINER_heap_get_size(find_peer_context->peer_min_heap), peer_count->count);
1276 if ((peer_count->count == 0) && (GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime).value > 0))
1278 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Found peer with no connections, will choose some peer(s) at random to connect to!\n");
1279 GNUNET_CONTAINER_heap_iterate (find_peer_context->peer_min_heap, &iterate_min_heap_peers, find_peer_context);
1280 GNUNET_SCHEDULER_add_now(sched, &schedule_churn_find_peer_requests, find_peer_context);
1282 else if ((GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime).value > 0) && (find_peer_context->last_sent != 0))
1284 GNUNET_SCHEDULER_add_now(sched, &schedule_churn_find_peer_requests, find_peer_context);
1288 GNUNET_CONTAINER_multihashmap_iterate(find_peer_context->peer_hash, &remove_peer_count, find_peer_context);
1289 GNUNET_CONTAINER_multihashmap_destroy(find_peer_context->peer_hash);
1290 GNUNET_CONTAINER_heap_destroy(find_peer_context->peer_min_heap);
1291 GNUNET_free(find_peer_context);
1292 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Churn round %u of %llu finished, scheduling next GET round.\n", current_churn_round, churn_rounds);
1293 if (dhtlog_handle != NULL)
1295 topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
1296 topo_ctx->cont = &do_get;
1297 topo_ctx->cls = all_gets;
1298 topo_ctx->timeout = DEFAULT_GET_TIMEOUT;
1299 topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create(num_peers);
1300 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout), DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
1301 &end_badly, "from do gets (count_peers_churn_cb)");
1302 GNUNET_SCHEDULER_add_now(sched, &capture_current_topology, topo_ctx);
1306 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout), DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
1307 &end_badly, "from do gets (count_peers_churn_cb)");
1308 GNUNET_SCHEDULER_add_now(sched, &do_get, all_gets);
1315 * Set up a single find peer request for each peer in the topology. Do this
1316 * until the settle time is over, limited by the number of outstanding requests
1317 * and the time allowed for each one!
1320 schedule_churn_find_peer_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1322 struct FindPeerContext *find_peer_ctx = cls;
1323 struct TestFindPeer *test_find_peer;
1324 struct PeerCount *peer_count;
1327 if (find_peer_ctx->previous_peers == 0) /* First time, go slowly */
1328 find_peer_ctx->total = 1;
1329 else if (find_peer_ctx->current_peers - find_peer_ctx->previous_peers < MIN_FIND_PEER_CUTOFF)
1330 find_peer_ctx->total = find_peer_ctx->total / 2;
1331 else if (find_peer_ctx->current_peers - find_peer_ctx->previous_peers > MAX_FIND_PEER_CUTOFF) /* Found LOTS of peers, still go slowly */
1332 find_peer_ctx->total = find_peer_ctx->last_sent - (find_peer_ctx->last_sent / 8);
1334 find_peer_ctx->total = find_peer_ctx->last_sent * 2;
1336 if (find_peer_ctx->total > max_outstanding_find_peers)
1337 find_peer_ctx->total = max_outstanding_find_peers;
1339 find_peer_ctx->last_sent = find_peer_ctx->total;
1340 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sending %u find peer messages (after churn)\n", find_peer_ctx->total);
1342 if (find_peer_ctx->total > 0)
1343 find_peer_offset = GNUNET_TIME_relative_divide(find_peer_delay, find_peer_ctx->total);
1346 find_peer_ctx->previous_peers = find_peer_ctx->current_peers;
1347 find_peer_ctx->current_peers = 0;
1348 GNUNET_TESTING_get_topology (pg, &count_peers_churn_cb, find_peer_ctx);
1352 for (i = 0; i < find_peer_ctx->total; i++)
1354 test_find_peer = GNUNET_malloc(sizeof(struct TestFindPeer));
1355 /* If we have sent requests, choose peers with a low number of connections to send requests from */
1356 peer_count = GNUNET_CONTAINER_heap_remove_root(find_peer_ctx->peer_min_heap);
1357 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sending find peer request from peer with %u connections\n", peer_count->count);
1358 GNUNET_CONTAINER_multihashmap_remove(find_peer_ctx->peer_hash, &peer_count->peer_id.hashPubKey, peer_count);
1359 test_find_peer->daemon = GNUNET_TESTING_daemon_get_by_id(pg, &peer_count->peer_id);
1360 GNUNET_assert(test_find_peer->daemon != NULL);
1361 test_find_peer->find_peer_context = find_peer_ctx;
1362 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(find_peer_offset, i), &send_find_peer_request, test_find_peer);
1365 if ((find_peer_ctx->peer_hash == NULL) && (find_peer_ctx->peer_min_heap == NULL))
1367 find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create(num_peers);
1368 find_peer_ctx->peer_min_heap = GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
1372 GNUNET_CONTAINER_multihashmap_iterate(find_peer_ctx->peer_hash, &remove_peer_count, find_peer_ctx);
1373 GNUNET_CONTAINER_multihashmap_destroy(find_peer_ctx->peer_hash);
1374 find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create(num_peers);
1377 GNUNET_assert(0 == GNUNET_CONTAINER_multihashmap_size(find_peer_ctx->peer_hash));
1378 GNUNET_assert(0 == GNUNET_CONTAINER_heap_get_size(find_peer_ctx->peer_min_heap));
1381 static void schedule_churn_get_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1383 struct FindPeerContext *find_peer_context = cls;
1384 GNUNET_TESTING_get_topology (pg, &count_peers_churn_cb, find_peer_context);
1388 * Called when churning of the topology has finished.
1390 * @param cls closure unused
1391 * @param emsg NULL on success, or a printable error on failure
1393 static void churn_complete (void *cls, const char *emsg)
1395 struct FindPeerContext *find_peer_context = cls;
1396 struct PeerCount *peer_count;
1398 struct GNUNET_TESTING_Daemon *temp_daemon;
1399 struct TopologyIteratorContext *topo_ctx;
1400 struct GNUNET_TIME_Relative calc_timeout;
1405 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Ending test, churning of peers failed with error `%s'", emsg);
1406 GNUNET_SCHEDULER_add_now(sched, &end_badly, (void *)emsg);
1411 * If we switched any peers on, we have to somehow force connect the new peer to
1412 * SOME bootstrap peer in the network. First schedule a task to find all peers
1413 * with no connections, then choose a random peer for each and connect them.
1415 if (find_peer_context != NULL)
1417 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "We have churned on some peers, so we must schedule find peer requests for them!\n");
1419 for (i = 0; i < num_peers; i ++)
1421 temp_daemon = GNUNET_TESTING_daemon_get(pg, i);
1422 if (GNUNET_YES == GNUNET_TESTING_daemon_running(temp_daemon))
1424 peer_count = GNUNET_malloc (sizeof(struct PeerCount));
1425 memcpy(&peer_count->peer_id, &temp_daemon->id, sizeof(struct GNUNET_PeerIdentity));
1426 GNUNET_assert(peer_count->count == 0);
1427 peer_count->heap_node = GNUNET_CONTAINER_heap_insert(find_peer_context->peer_min_heap, peer_count, peer_count->count);
1428 GNUNET_CONTAINER_multihashmap_put(find_peer_context->peer_hash, &temp_daemon->id.hashPubKey, peer_count, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1432 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Added %d peers to heap, total size %d\n", count_added, GNUNET_CONTAINER_heap_get_size(find_peer_context->peer_min_heap));
1433 GNUNET_SCHEDULER_add_delayed(sched, DEFAULT_PEER_DISCONNECT_TIMEOUT, &schedule_churn_get_topology, find_peer_context);
1434 //GNUNET_TESTING_get_topology (pg, &count_peers_churn_cb, find_peer_context);
1438 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Only churned off peers, no find peer requests, scheduling more gets (after allowing time for peers to disconnect properly!)...\n");
1439 if (dhtlog_handle != NULL)
1441 topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
1442 topo_ctx->cont = &do_get;
1443 topo_ctx->cls = all_gets;
1444 topo_ctx->timeout = DEFAULT_GET_TIMEOUT;
1445 topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create(num_peers);
1446 calc_timeout = GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout);
1447 calc_timeout = GNUNET_TIME_relative_add(calc_timeout, DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT);
1448 calc_timeout = GNUNET_TIME_relative_add(calc_timeout, DEFAULT_PEER_DISCONNECT_TIMEOUT);
1449 die_task = GNUNET_SCHEDULER_add_delayed (sched, calc_timeout,
1450 &end_badly, "from do gets (churn_complete)");
1451 GNUNET_SCHEDULER_add_delayed(sched, DEFAULT_PEER_DISCONNECT_TIMEOUT, &capture_current_topology, topo_ctx);
1455 calc_timeout = GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout);
1456 calc_timeout = GNUNET_TIME_relative_add(calc_timeout, DEFAULT_PEER_DISCONNECT_TIMEOUT);
1457 die_task = GNUNET_SCHEDULER_add_delayed (sched, calc_timeout,
1458 &end_badly, "from do gets (churn_complete)");
1459 if (dhtlog_handle != NULL)
1460 dhtlog_handle->insert_round(DHT_ROUND_GET, rounds_finished);
1461 GNUNET_SCHEDULER_add_delayed(sched, DEFAULT_PEER_DISCONNECT_TIMEOUT, &do_get, all_gets);
1467 * Decide how many peers to turn on or off in this round, make sure the
1468 * numbers actually make sense, then do so. This function sets in motion
1469 * churn, find peer requests for newly joined peers, and issuing get
1470 * requests once the new peers have done so.
1472 * @param cls closure (unused)
1473 * @param cls task context (unused)
1476 churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1478 unsigned int count_running;
1479 unsigned int churn_up;
1480 unsigned int churn_down;
1481 struct GNUNET_TIME_Relative timeout;
1482 struct FindPeerContext *find_peer_context;
1484 churn_up = churn_down = 0;
1485 count_running = GNUNET_TESTING_daemons_running(pg);
1486 if (count_running > churn_array[current_churn_round])
1487 churn_down = count_running - churn_array[current_churn_round];
1488 else if (count_running < churn_array[current_churn_round])
1489 churn_up = churn_array[current_churn_round] - count_running;
1491 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Not churning any peers, topology unchanged.\n");
1493 if (churn_up > num_peers - count_running)
1495 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Churn file specified %u peers (up); only have %u!", churn_array[current_churn_round], num_peers);
1496 churn_up = num_peers - count_running;
1498 else if (churn_down > count_running)
1500 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Churn file specified %u peers (down); only have %u!", churn_array[current_churn_round], count_running);
1501 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "This will leave NO peers running (mistake in churn configuration?)!");
1502 churn_down = count_running;
1504 //timeout = GNUNET_TIME_relative_multiply(seconds_per_peer_start, churn_up > 0 ? churn_up : churn_down);
1505 //timeout = GNUNET_TIME_relative_multiply (seconds_per_peer_start, churn_up > 0 ? churn_up : churn_down);
1506 timeout = GNUNET_TIME_relative_multiply(DEFAULT_TIMEOUT, 2); /* FIXME: Lack of intelligent choice here */
1507 find_peer_context = NULL;
1508 if (churn_up > 0) /* Only need to do find peer requests if we turned new peers on */
1510 find_peer_context = GNUNET_malloc(sizeof(struct FindPeerContext));
1511 find_peer_context->count_peers_cb = &count_peers_churn_cb;
1512 find_peer_context->previous_peers = 0;
1513 find_peer_context->current_peers = 0;
1514 find_peer_context->endtime = GNUNET_TIME_relative_to_absolute(timeout);
1515 find_peer_context->peer_hash = GNUNET_CONTAINER_multihashmap_create(num_peers);
1516 find_peer_context->peer_min_heap = GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
1518 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "churn_peers: want %u total, %u running, starting %u, stopping %u\n",
1519 churn_array[current_churn_round], count_running, churn_up, churn_down);
1520 GNUNET_TESTING_daemons_churn (pg, churn_down, churn_up, timeout, &churn_complete, find_peer_context);
1521 current_churn_round++;
1525 * Task to release DHT handle associated with GET request.
1528 get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1530 struct TestGetContext *test_get = cls;
1531 struct TopologyIteratorContext *topo_ctx;
1533 /* The dht_handle may be null if this get was scheduled from a down peer */
1534 if (test_get->dht_handle != NULL)
1536 GNUNET_DHT_disconnect(test_get->dht_handle);
1537 outstanding_gets--; /* GET is really finished */
1538 test_get->dht_handle = NULL;
1541 /* Reset the uid (which item to search for) and the daemon (which peer to search from) for later get request iterations */
1542 test_get->uid = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_puts);
1543 test_get->daemon = GNUNET_TESTING_daemon_get(pg, GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
1546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d gets succeeded, %d gets failed!\n", gets_completed, gets_failed);
1548 update_meter(get_meter);
1549 if ((gets_completed + gets_failed == num_gets) && (outstanding_gets == 0))
1551 fprintf(stderr, "Canceling die task (get_stop_finished) %llu gets completed, %llu gets failed\n", gets_completed, gets_failed);
1552 GNUNET_SCHEDULER_cancel(sched, die_task);
1553 reset_meter(put_meter);
1554 reset_meter(get_meter);
1557 * 1) Testing is completely finished, call the topology iteration dealy and die
1558 * 2) Testing is not finished, churn the network and do gets again (current_churn_round < churn_rounds)
1559 * 3) Testing is not finished, reschedule all the PUTS *and* GETS again (num_rounds > 1)
1561 if (rounds_finished == total_rounds - 1) /* Everything is finished, end testing */
1563 if (dhtlog_handle != NULL)
1565 topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
1566 topo_ctx->cont = &log_dht_statistics;
1567 topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create(num_peers);
1568 GNUNET_SCHEDULER_add_now(sched, &capture_current_topology, topo_ctx);
1571 GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
1573 else if (current_churn_round < churns_per_round * (rounds_finished + 1)) /* Do next round of churn */
1575 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Current churn round %u, real round %u, scheduling next round of churn.\n", current_churn_round, rounds_finished + 1);
1579 if (dhtlog_handle != NULL)
1580 dhtlog_handle->insert_round(DHT_ROUND_CHURN, rounds_finished);
1582 GNUNET_SCHEDULER_add_now(sched, &churn_peers, NULL);
1584 else if (rounds_finished < total_rounds - 1) /* Start a new complete round */
1589 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Round %u of %llu finished, scheduling next round.\n", rounds_finished, total_rounds);
1591 /** We reset the peer daemon for puts and gets on each disconnect, so all we need to do is start another round! */
1592 if (GNUNET_YES == in_dht_replication) /* Replication done in DHT, don't redo puts! */
1594 if (dhtlog_handle != NULL)
1595 dhtlog_handle->insert_round(DHT_ROUND_GET, rounds_finished);
1597 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(GNUNET_TIME_relative_add(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, round_delay), all_get_timeout), DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
1598 &end_badly, "from do gets (next round)");
1599 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, round_delay), &do_get, all_gets);
1603 if (dhtlog_handle != NULL)
1604 dhtlog_handle->insert_round(DHT_ROUND_NORMAL, rounds_finished);
1605 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, round_delay), GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, num_puts * 2)),
1606 &end_badly, "from do puts");
1607 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, round_delay), &do_put, all_puts);
1614 * Task to release get handle.
1617 get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1619 struct TestGetContext *test_get = cls;
1621 if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT)
1623 GNUNET_assert(test_get->get_handle != NULL);
1624 GNUNET_DHT_get_stop(test_get->get_handle, &get_stop_finished, test_get);
1625 test_get->get_handle = NULL;
1626 test_get->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
1630 * Iterator called if the GET request initiated returns a response.
1632 * @param cls closure
1633 * @param exp when will this value expire
1634 * @param key key of the result
1635 * @param type type of the result
1636 * @param size number of bytes in data
1637 * @param data pointer to the result data
1639 void get_result_iterator (void *cls,
1640 struct GNUNET_TIME_Absolute exp,
1641 const GNUNET_HashCode * key,
1646 struct TestGetContext *test_get = cls;
1648 if (test_get->succeeded == GNUNET_YES)
1649 return; /* Get has already been successful, probably ending now */
1651 if (0 != memcmp(&known_keys[test_get->uid], key, sizeof (GNUNET_HashCode))) /* || (0 != memcmp(original_data, data, sizeof(original_data))))*/
1654 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Key or data is not the same as was inserted!\n");
1659 test_get->succeeded = GNUNET_YES;
1662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n");
1664 GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task);
1665 GNUNET_SCHEDULER_add_continuation(sched, &get_stop_task, test_get, GNUNET_SCHEDULER_REASON_PREREQ_DONE);
1669 * Continuation telling us GET request was sent.
1672 get_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1674 // Is there something to be done here?
1675 if (tc->reason != GNUNET_SCHEDULER_REASON_PREREQ_DONE)
1680 * Set up some data, and call API PUT function
1683 do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1685 struct TestGetContext *test_get = cls;
1689 GNUNET_SCHEDULER_cancel(sched, die_task);
1690 GNUNET_SCHEDULER_add_now(sched, &finish_testing, NULL);
1693 if (test_get == NULL)
1694 return; /* End of the list */
1696 /* Set this here in case we are re-running gets */
1697 test_get->succeeded = GNUNET_NO;
1699 if (GNUNET_YES != GNUNET_TESTING_daemon_running(test_get->daemon)) /* If the peer has been churned off, don't try issuing request from it! */
1701 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer we should issue get request from is down, skipping.\n");
1703 GNUNET_SCHEDULER_add_now (sched, &get_stop_finished, test_get);
1704 GNUNET_SCHEDULER_add_now (sched, &do_get, test_get->next);
1708 /* Check if more gets are outstanding than should be */
1709 if (outstanding_gets > max_outstanding_gets)
1711 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 200), &do_get, test_get);
1715 /* Connect to the first peer's DHT */
1716 test_get->dht_handle = GNUNET_DHT_connect(sched, test_get->daemon->cfg, 10);
1717 GNUNET_assert(test_get->dht_handle != NULL);
1720 /* Insert the data at the first peer */
1721 test_get->get_handle = GNUNET_DHT_get_start(test_get->dht_handle,
1724 &known_keys[test_get->uid],
1725 &get_result_iterator,
1730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting get for uid %u from peer %s\n",
1732 test_get->daemon->shortname);
1734 test_get->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, get_timeout, &get_stop_task, test_get);
1736 /* Schedule the next request in the linked list of get requests */
1737 GNUNET_SCHEDULER_add_now (sched, &do_get, test_get->next);
1741 * Called when the PUT request has been transmitted to the DHT service.
1742 * Schedule the GET request for some time in the future.
1745 put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1747 struct TestPutContext *test_put = cls;
1748 struct TopologyIteratorContext *topo_ctx;
1752 if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT)
1753 fprintf(stderr, "PUT Request failed!\n");
1755 /* Reset the daemon (which peer to insert at) for later put request iterations */
1756 if (replicate_same == GNUNET_NO)
1757 test_put->daemon = GNUNET_TESTING_daemon_get(pg, GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
1759 GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task);
1760 test_put->disconnect_task = GNUNET_SCHEDULER_add_now(sched, &put_disconnect_task, test_put);
1761 if (GNUNET_YES == update_meter(put_meter))
1763 GNUNET_assert(outstanding_puts == 0);
1764 GNUNET_SCHEDULER_cancel (sched, die_task);
1765 if (dhtlog_handle != NULL)
1767 topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
1768 topo_ctx->cont = &do_get;
1769 topo_ctx->cls = all_gets;
1770 topo_ctx->timeout = DEFAULT_GET_TIMEOUT;
1771 topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create(num_peers);
1772 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout), DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
1773 &end_badly, "from do gets (put finished)");
1774 GNUNET_SCHEDULER_add_now(sched, &capture_current_topology, topo_ctx);
1778 fprintf(stderr, "Scheduling die task (put finished)\n");
1779 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout),
1780 &end_badly, "from do gets (put finished)");
1781 GNUNET_SCHEDULER_add_delayed(sched, DEFAULT_GET_TIMEOUT, &do_get, all_gets);
1788 * Set up some data, and call API PUT function
1791 do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1793 struct TestPutContext *test_put = cls;
1794 char data[test_data_size]; /* Made up data to store */
1798 if (test_put == NULL)
1799 return; /* End of list */
1801 if (GNUNET_YES != GNUNET_TESTING_daemon_running(test_put->daemon)) /* If the peer has been churned off, don't try issuing request from it! */
1803 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Peer we should issue put request at is down, skipping.\n");
1804 update_meter(put_meter);
1805 GNUNET_SCHEDULER_add_now (sched, &do_put, test_put->next);
1809 for (i = 0; i < sizeof(data); i++)
1811 memset(&data[i], GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, (uint32_t)-1), 1);
1814 if (outstanding_puts > max_outstanding_puts)
1816 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 200), &do_put, test_put);
1821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting put for uid %u from peer %s\n",
1823 test_put->daemon->shortname);
1825 test_put->dht_handle = GNUNET_DHT_connect(sched, test_put->daemon->cfg, 10);
1827 GNUNET_assert(test_put->dht_handle != NULL);
1829 GNUNET_DHT_put(test_put->dht_handle,
1830 &known_keys[test_put->uid],
1833 GNUNET_TIME_absolute_get_forever(),
1835 &put_finished, test_put);
1836 test_put->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_get_forever(), &put_disconnect_task, test_put);
1837 rand = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 2);
1838 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, rand), &do_put, test_put->next);
1842 schedule_find_peer_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
1845 * Given a number of total peers and a bucket size, estimate the number of
1846 * connections in a perfect kademlia topology.
1848 static unsigned int connection_estimate(unsigned int peer_count, unsigned int bucket_size)
1851 unsigned int filled;
1855 while (i >= bucket_size)
1860 filled++; /* Add one filled bucket to account for one "half full" and some miscellaneous */
1861 return filled * bucket_size * peer_count;
1867 * Callback for iterating over all the peer connections of a peer group.
1869 void count_peers_cb (void *cls,
1870 const struct GNUNET_PeerIdentity *first,
1871 const struct GNUNET_PeerIdentity *second,
1872 struct GNUNET_TIME_Relative latency,
1876 struct FindPeerContext *find_peer_context = cls;
1877 if ((first != NULL) && (second != NULL))
1879 add_new_connection(find_peer_context, first, second);
1880 find_peer_context->current_peers++;
1884 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Peer count finished (%u connections), %u new peers, connection estimate %u (double %u)\n",
1885 find_peer_context->current_peers,
1886 find_peer_context->current_peers - find_peer_context->previous_peers,
1887 connection_estimate(num_peers, DEFAULT_BUCKET_SIZE),
1888 2 * connection_estimate(num_peers, DEFAULT_BUCKET_SIZE));
1890 if ((find_peer_context->current_peers - find_peer_context->previous_peers > FIND_PEER_THRESHOLD) &&
1891 (find_peer_context->current_peers < 2 * connection_estimate(num_peers, DEFAULT_BUCKET_SIZE)) &&
1892 (GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime).value > 0))
1894 GNUNET_SCHEDULER_add_now(sched, &schedule_find_peer_requests, find_peer_context);
1898 GNUNET_CONTAINER_multihashmap_iterate(find_peer_context->peer_hash, &remove_peer_count, find_peer_context);
1899 GNUNET_CONTAINER_multihashmap_destroy(find_peer_context->peer_hash);
1900 GNUNET_CONTAINER_heap_destroy(find_peer_context->peer_min_heap);
1901 GNUNET_free(find_peer_context);
1902 fprintf(stderr, "Not sending any more find peer requests.\n");
1909 * Set up a single find peer request for each peer in the topology. Do this
1910 * until the settle time is over, limited by the number of outstanding requests
1911 * and the time allowed for each one!
1914 schedule_find_peer_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1916 struct FindPeerContext *find_peer_ctx = cls;
1917 struct TestFindPeer *test_find_peer;
1918 struct PeerCount *peer_count;
1922 if (find_peer_ctx->previous_peers == 0) /* First time, go slowly */
1923 find_peer_ctx->total = 1;
1924 else if (find_peer_ctx->current_peers - find_peer_ctx->previous_peers > MAX_FIND_PEER_CUTOFF) /* Found LOTS of peers, still go slowly */
1925 find_peer_ctx->total = find_peer_ctx->last_sent - (find_peer_ctx->last_sent / 8);
1927 else if (find_peer_ctx->current_peers - find_peer_ctx->previous_peers < MIN_FIND_PEER_CUTOFF)
1928 find_peer_ctx->total = find_peer_ctx->last_sent * 2; /* FIXME: always multiply by two (unless above max?) */
1930 find_peer_ctx->total = find_peer_ctx->last_sent;
1933 find_peer_ctx->total = find_peer_ctx->last_sent * 2;
1936 if (find_peer_ctx->total > max_outstanding_find_peers)
1937 find_peer_ctx->total = max_outstanding_find_peers;
1939 find_peer_ctx->last_sent = find_peer_ctx->total;
1940 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Sending %u find peer messages (goal at least %u connections)\n", find_peer_ctx->total, connection_estimate(num_peers, DEFAULT_BUCKET_SIZE));
1942 find_peer_offset = GNUNET_TIME_relative_divide(find_peer_delay, find_peer_ctx->total);
1943 for (i = 0; i < find_peer_ctx->total; i++)
1945 test_find_peer = GNUNET_malloc(sizeof(struct TestFindPeer));
1946 if (find_peer_ctx->previous_peers == 0) /* If we haven't sent any requests, yet choose random peers */
1949 * Attempt to spread find peer requests across even sections of the peer address
1950 * space. Choose basically 1 peer in every num_peers / max_outstanding_requests
1951 * each time, then offset it by a randomish value.
1953 * For instance, if num_peers is 100 and max_outstanding is 10, first chosen peer
1954 * will be between 0 - 10, second between 10 - 20, etc.
1956 random = (num_peers / find_peer_ctx->total) * i;
1957 random = random + GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, (num_peers / find_peer_ctx->total));
1958 if (random >= num_peers)
1960 random = random - num_peers;
1963 random = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1965 test_find_peer->daemon = GNUNET_TESTING_daemon_get(pg, random);
1967 else /* If we have sent requests, choose peers with a low number of connections to send requests from */
1969 peer_count = GNUNET_CONTAINER_heap_remove_root(find_peer_ctx->peer_min_heap);
1970 GNUNET_CONTAINER_multihashmap_remove(find_peer_ctx->peer_hash, &peer_count->peer_id.hashPubKey, peer_count);
1971 test_find_peer->daemon = GNUNET_TESTING_daemon_get_by_id(pg, &peer_count->peer_id);
1972 GNUNET_assert(test_find_peer->daemon != NULL);
1975 test_find_peer->find_peer_context = find_peer_ctx;
1976 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(find_peer_offset, i), &send_find_peer_request, test_find_peer);
1979 if ((find_peer_ctx->peer_hash == NULL) && (find_peer_ctx->peer_min_heap == NULL))
1981 find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create(num_peers);
1982 find_peer_ctx->peer_min_heap = GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
1986 GNUNET_CONTAINER_multihashmap_iterate(find_peer_ctx->peer_hash, &remove_peer_count, find_peer_ctx);
1987 GNUNET_CONTAINER_multihashmap_destroy(find_peer_ctx->peer_hash);
1988 find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create(num_peers);
1991 GNUNET_assert(0 == GNUNET_CONTAINER_multihashmap_size(find_peer_ctx->peer_hash));
1992 GNUNET_assert(0 == GNUNET_CONTAINER_heap_get_size(find_peer_ctx->peer_min_heap));
1997 * Set up some all of the put and get operations we want
1998 * to do. Allocate data structure for each, add to list,
1999 * then call actual insert functions.
2002 setup_puts_and_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
2005 uint32_t temp_daemon;
2006 struct TestPutContext *test_put;
2007 struct TestGetContext *test_get;
2009 int remember[num_puts][num_peers];
2010 memset(&remember, 0, sizeof(int) * num_puts * num_peers);
2012 known_keys = GNUNET_malloc(sizeof(GNUNET_HashCode) * num_puts);
2013 for (i = 0; i < num_puts; i++)
2015 test_put = GNUNET_malloc(sizeof(struct TestPutContext));
2017 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &known_keys[i]);
2018 temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2019 test_put->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
2020 test_put->next = all_puts;
2021 all_puts = test_put;
2024 for (i = 0; i < num_gets; i++)
2026 test_get = GNUNET_malloc(sizeof(struct TestGetContext));
2027 test_get->uid = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_puts);
2029 while (remember[test_get->uid][temp_daemon] == 1)
2030 temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2031 remember[test_get->uid][temp_daemon] = 1;
2033 test_get->daemon = GNUNET_TESTING_daemon_get(pg, GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
2034 test_get->next = all_gets;
2035 all_gets = test_get;
2038 /*GNUNET_SCHEDULER_cancel (sched, die_task);*/
2039 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, num_puts * 2),
2040 &end_badly, "from do puts");
2041 GNUNET_SCHEDULER_add_now (sched, &do_put, all_puts);
2042 if (dhtlog_handle != NULL)
2043 dhtlog_handle->insert_round(DHT_ROUND_NORMAL, rounds_finished);
2047 * Set up some all of the put and get operations we want
2048 * to do. Allocate data structure for each, add to list,
2049 * then call actual insert functions.
2052 continue_puts_and_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
2056 struct TopologyIteratorContext *topo_ctx;
2057 struct FindPeerContext *find_peer_context;
2058 if (dhtlog_handle != NULL)
2060 if (settle_time >= 180 * 2)
2061 max = (settle_time / 180) - 2;
2064 for (i = 1; i < max; i++)
2066 topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
2067 topo_ctx->current_iteration = i;
2068 topo_ctx->total_iterations = max;
2069 topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create(num_peers);
2070 //fprintf(stderr, "scheduled topology iteration in %d minutes\n", i);
2071 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, i * 3), &capture_current_topology, topo_ctx);
2073 topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
2074 topo_ctx->cont = &setup_puts_and_gets;
2075 topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create(num_peers);
2076 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time), &capture_current_topology, topo_ctx);
2079 GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time), &setup_puts_and_gets, NULL);
2081 if (GNUNET_YES == do_find_peer)
2083 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling find peer requests during \"settle\" time.\n");
2084 find_peer_context = GNUNET_malloc(sizeof(struct FindPeerContext));
2085 find_peer_context->count_peers_cb = &count_peers_cb;
2086 find_peer_context->endtime = GNUNET_TIME_relative_to_absolute(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time));
2087 GNUNET_SCHEDULER_add_now(sched, &schedule_find_peer_requests, find_peer_context);
2091 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Assuming automatic DHT find peer requests.\n");
2096 * Task to release DHT handles
2099 malicious_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
2101 struct MaliciousContext *ctx = cls;
2102 outstanding_malicious--;
2103 malicious_completed++;
2104 ctx->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
2105 GNUNET_DHT_disconnect(ctx->dht_handle);
2106 ctx->dht_handle = NULL;
2109 if (malicious_completed == malicious_getters + malicious_putters + malicious_droppers)
2111 GNUNET_SCHEDULER_cancel(sched, die_task);
2112 fprintf(stderr, "Finished setting all malicious peers up, calling continuation!\n");
2113 if (dhtlog_handle != NULL)
2114 GNUNET_SCHEDULER_add_now (sched,
2115 &continue_puts_and_gets, NULL);
2117 GNUNET_SCHEDULER_add_delayed (sched,
2118 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time),
2119 &continue_puts_and_gets, NULL);
2125 * Task to release DHT handles
2128 malicious_done_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
2130 struct MaliciousContext *ctx = cls;
2131 GNUNET_SCHEDULER_cancel(sched, ctx->disconnect_task);
2132 GNUNET_SCHEDULER_add_now(sched, &malicious_disconnect_task, ctx);
2136 * Set up some data, and call API PUT function
2139 set_malicious (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
2141 struct MaliciousContext *ctx = cls;
2144 if (outstanding_malicious > DEFAULT_MAX_OUTSTANDING_GETS)
2146 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &set_malicious, ctx);
2150 if (ctx->dht_handle == NULL)
2152 ctx->dht_handle = GNUNET_DHT_connect(sched, ctx->daemon->cfg, 1);
2153 outstanding_malicious++;
2156 GNUNET_assert(ctx->dht_handle != NULL);
2160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting peer %s malicious type %d\n",
2161 ctx->daemon->shortname, ctx->malicious_type);
2165 switch (ctx->malicious_type)
2167 case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_GET:
2168 ret = GNUNET_DHT_set_malicious_getter(ctx->dht_handle, malicious_get_frequency, &malicious_done_task, ctx);
2170 case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_PUT:
2171 ret = GNUNET_DHT_set_malicious_putter(ctx->dht_handle, malicious_put_frequency, &malicious_done_task, ctx);
2173 case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_DROP:
2174 ret = GNUNET_DHT_set_malicious_dropper(ctx->dht_handle, &malicious_done_task, ctx);
2180 if (ret == GNUNET_NO)
2182 GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &set_malicious, ctx);
2185 ctx->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_get_forever(), &malicious_disconnect_task, ctx);
2189 * Select randomly from set of known peers,
2190 * set the desired number of peers to the
2191 * proper malicious types.
2194 setup_malicious_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
2196 struct MaliciousContext *ctx;
2198 uint32_t temp_daemon;
2200 for (i = 0; i < malicious_getters; i++)
2202 ctx = GNUNET_malloc(sizeof(struct MaliciousContext));
2203 temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2204 ctx->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
2205 ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_GET;
2206 GNUNET_SCHEDULER_add_now (sched, &set_malicious, ctx);
2210 for (i = 0; i < malicious_putters; i++)
2212 ctx = GNUNET_malloc(sizeof(struct MaliciousContext));
2213 temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2214 ctx->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
2215 ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_PUT;
2216 GNUNET_SCHEDULER_add_now (sched, &set_malicious, ctx);
2220 for (i = 0; i < malicious_droppers; i++)
2222 ctx = GNUNET_malloc(sizeof(struct MaliciousContext));
2223 temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2224 ctx->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
2225 ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_DROP;
2226 GNUNET_SCHEDULER_add_now (sched, &set_malicious, ctx);
2230 * If we have any malicious peers to set up,
2231 * the malicious callback should call continue_gets_and_puts
2233 if (malicious_getters + malicious_putters + malicious_droppers > 0)
2235 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Giving malicious set tasks some time before starting testing!\n");
2236 die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, (malicious_getters + malicious_putters + malicious_droppers) * 2),
2237 &end_badly, "from set malicious");
2239 else /* Otherwise, continue testing */
2241 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Scheduling continue_puts_and_gets now!\n");
2242 GNUNET_SCHEDULER_add_now (sched,
2243 &continue_puts_and_gets, NULL);
2248 * This function is called whenever a connection attempt is finished between two of
2249 * the started peers (started with GNUNET_TESTING_daemons_start). The total
2250 * number of times this function is called should equal the number returned
2251 * from the GNUNET_TESTING_connect_topology call.
2253 * The emsg variable is NULL on success (peers connected), and non-NULL on
2254 * failure (peers failed to connect).
2257 topology_callback (void *cls,
2258 const struct GNUNET_PeerIdentity *first,
2259 const struct GNUNET_PeerIdentity *second,
2261 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
2262 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
2263 struct GNUNET_TESTING_Daemon *first_daemon,
2264 struct GNUNET_TESTING_Daemon *second_daemon,
2267 struct TopologyIteratorContext *topo_ctx;
2270 total_connections++;
2272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
2273 first_daemon->shortname,
2274 second_daemon->shortname,
2280 failed_connections++;
2282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
2283 first_daemon->shortname,
2284 second_daemon->shortname, emsg);
2288 GNUNET_assert(peer_connect_meter != NULL);
2289 if (GNUNET_YES == update_meter(peer_connect_meter))
2292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2293 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
2296 if (dhtlog_handle != NULL)
2298 dhtlog_handle->update_connections (trialuid, total_connections);
2299 dhtlog_handle->insert_topology(expected_connections);
2302 GNUNET_SCHEDULER_cancel (sched, die_task);
2303 /*die_task = GNUNET_SCHEDULER_add_delayed (sched, DEFAULT_TIMEOUT,
2304 &end_badly, "from setup puts/gets");*/
2305 if ((dhtlog_handle != NULL) && (settle_time > 0))
2307 topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
2308 topo_ctx->cont = &setup_malicious_peers;
2309 topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create(num_peers);
2310 //topo_ctx->cont = &continue_puts_and_gets;
2311 GNUNET_SCHEDULER_add_now(sched, &capture_current_topology, topo_ctx);
2315 GNUNET_SCHEDULER_add_now(sched, &setup_malicious_peers, NULL);
2316 /*GNUNET_SCHEDULER_add_delayed (sched,
2317 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time),
2318 &continue_puts_and_gets, NULL);*/
2321 else if (total_connections + failed_connections == expected_connections)
2323 GNUNET_SCHEDULER_cancel (sched, die_task);
2324 die_task = GNUNET_SCHEDULER_add_now (sched,
2325 &end_badly, "from topology_callback (too many failed connections)");
2330 peers_started_callback (void *cls,
2331 const struct GNUNET_PeerIdentity *id,
2332 const struct GNUNET_CONFIGURATION_Handle *cfg,
2333 struct GNUNET_TESTING_Daemon *d, const char *emsg)
2337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n",
2341 GNUNET_assert (id != NULL);
2344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
2345 (num_peers - peers_left) + 1, num_peers);
2350 if (GNUNET_YES == update_meter(peer_start_meter))
2353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2354 "All %d daemons started, now connecting peers!\n",
2357 GNUNET_SCHEDULER_cancel (sched, die_task);
2359 expected_connections = -1;
2360 if ((pg != NULL) && (peers_left == 0))
2362 expected_connections = GNUNET_TESTING_connect_topology (pg, connect_topology, connect_topology_option, connect_topology_option_modifier);
2364 peer_connect_meter = create_meter(expected_connections, "Peer connection ", GNUNET_YES);
2365 fprintf(stderr, "Have %d expected connections\n", expected_connections);
2368 if (expected_connections == GNUNET_SYSERR)
2370 die_task = GNUNET_SCHEDULER_add_now (sched,
2371 &end_badly, "from connect topology (bad return)");
2374 die_task = GNUNET_SCHEDULER_add_delayed (sched,
2375 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, DEFAULT_CONNECT_TIMEOUT * expected_connections),
2376 &end_badly, "from connect topology (timeout)");
2385 peers_left = num_peers; /* Reset counter */
2386 if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR)
2389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2390 "Topology set up, now starting peers!\n");
2392 GNUNET_TESTING_daemons_continue_startup(pg);
2396 GNUNET_SCHEDULER_cancel (sched, die_task);
2397 die_task = GNUNET_SCHEDULER_add_now (sched,
2398 &end_badly, "from create topology (bad return)");
2400 GNUNET_free_non_null(blacklist_transports);
2401 GNUNET_SCHEDULER_cancel (sched, die_task);
2402 die_task = GNUNET_SCHEDULER_add_delayed (sched,
2403 GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers),
2404 &end_badly, "from continue startup (timeout)");
2408 * Callback indicating that the hostkey was created for a peer.
2411 * @param id the peer identity
2412 * @param d the daemon handle (pretty useless at this point, remove?)
2413 * @param emsg non-null on failure
2415 void hostkey_callback (void *cls,
2416 const struct GNUNET_PeerIdentity *id,
2417 struct GNUNET_TESTING_Daemon *d,
2422 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg);
2426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2427 "Hostkey (%d/%d) created for peer `%s'\n",
2428 num_peers - peers_left, num_peers, GNUNET_i2s(id));
2432 if (GNUNET_YES == update_meter(hostkey_meter))
2435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2436 "All %d hostkeys created, now creating topology!\n",
2439 GNUNET_SCHEDULER_cancel (sched, die_task);
2440 /* Set up task in case topology creation doesn't finish
2441 * within a reasonable amount of time */
2442 die_task = GNUNET_SCHEDULER_add_delayed (sched,
2443 DEFAULT_TOPOLOGY_TIMEOUT,
2444 &end_badly, "from create_topology");
2445 GNUNET_SCHEDULER_add_now(sched, &create_topology, NULL);
2453 struct GNUNET_SCHEDULER_Handle *s,
2455 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
2458 struct GNUNET_DHTLOG_TrialInfo trial_info;
2459 struct GNUNET_TESTING_Host *hosts;
2460 struct GNUNET_TESTING_Host *temphost;
2461 struct GNUNET_TESTING_Host *tempnext;
2463 char *connect_topology_str;
2464 char *blacklist_topology_str;
2465 char *connect_topology_option_str;
2466 char *connect_topology_option_modifier_string;
2468 char *topology_percentage_str;
2469 float topology_percentage;
2470 char *topology_probability_str;
2472 float topology_probability;
2473 unsigned long long temp_config_number;
2476 int strict_kademlia;
2480 char *churn_filename;
2483 unsigned int line_number;
2487 rounds_finished = 0;
2488 memset(&trial_info, 0, sizeof(struct GNUNET_DHTLOG_TrialInfo));
2489 /* Get path from configuration file */
2490 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
2497 * Get DHT specific testing options.
2499 if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging")) ||
2500 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging_extended")))
2502 dhtlog_handle = GNUNET_DHTLOG_connect(cfg);
2503 if (dhtlog_handle == NULL)
2505 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2506 "Could not connect to mysql server for logging, will NOT log dht operations!");
2512 stop_closest = GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht", "stop_on_closest");
2513 if (stop_closest == GNUNET_SYSERR)
2514 stop_closest = GNUNET_NO;
2516 stop_found = GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht", "stop_found");
2517 if (stop_found == GNUNET_SYSERR)
2518 stop_found = GNUNET_NO;
2520 strict_kademlia = GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht", "strict_kademlia");
2521 if (strict_kademlia == GNUNET_SYSERR)
2522 strict_kademlia = GNUNET_NO;
2525 GNUNET_CONFIGURATION_get_value_string (cfg, "dht_testing", "comment",
2527 trialmessage = NULL;
2530 /** Check for a churn file to do churny simulation */
2532 GNUNET_CONFIGURATION_get_value_string(cfg, "dht_testing", "churn_file",
2535 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Reading churn data from %s\n", churn_filename);
2536 if (GNUNET_OK != GNUNET_DISK_file_test (churn_filename))
2538 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Error reading churn file!\n");
2541 if ((0 != STAT (churn_filename, &frstat)) || (frstat.st_size == 0))
2543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2544 "Could not open file specified for churn data, ending test!");
2546 GNUNET_free_non_null(trialmessage);
2547 GNUNET_free(churn_filename);
2551 churn_data = GNUNET_malloc_large (frstat.st_size);
2552 GNUNET_assert(churn_data != NULL);
2553 if (frstat.st_size !=
2554 GNUNET_DISK_fn_read (churn_filename, churn_data, frstat.st_size))
2556 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2557 "Could not read file %s specified for churn, ending test!", churn_filename);
2558 GNUNET_free (churn_filename);
2559 GNUNET_free (churn_data);
2560 GNUNET_free_non_null(trialmessage);
2564 GNUNET_free_non_null(churn_filename);
2568 /* Read the first line */
2569 while (count < frstat.st_size)
2572 if (((churn_data[count] == '\n')) && (buf != &churn_data[count]))
2574 churn_data[count] = '\0';
2575 if (1 != sscanf(buf, "%u", &churn_rounds))
2577 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to read number of rounds from %s, ending test!\n", churn_filename);
2578 GNUNET_free_non_null(trialmessage);
2579 GNUNET_free(churn_filename);
2583 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read %u rounds from churn file\n", churn_rounds);
2584 buf = &churn_data[count + 1];
2585 churn_array = GNUNET_malloc(sizeof(unsigned int) * churn_rounds);
2586 break; /* Done with this part */
2590 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number(cfg, "dht_testing", "churns_per_round", &churns_per_round))
2592 churns_per_round = (unsigned long long)churn_rounds;
2596 while ((count < frstat.st_size) && (line_number < churn_rounds))
2599 if (((churn_data[count] == '\n')) && (buf != &churn_data[count]))
2601 churn_data[count] = '\0';
2603 ret = sscanf(buf, "%u", &churn_array[line_number]);
2606 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read %u peers in round %u\n", churn_array[line_number], line_number);
2611 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Error reading line `%s' in hostfile\n", buf);
2612 buf = &churn_data[count + 1];
2615 buf = &churn_data[count + 1];
2617 else if (churn_data[count] == '\n') /* Blank line */
2618 buf = &churn_data[count + 1];
2621 GNUNET_free_non_null(churn_data);
2623 /** Check for a hostfile containing user@host:port triples */
2625 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile",
2631 if (hostfile != NULL)
2633 if (GNUNET_OK != GNUNET_DISK_file_test (hostfile))
2634 GNUNET_DISK_fn_write (hostfile, NULL, 0, GNUNET_DISK_PERM_USER_READ
2635 | GNUNET_DISK_PERM_USER_WRITE);
2636 if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0))
2638 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2639 "Could not open file specified for host list, ending test!");
2641 GNUNET_free_non_null(trialmessage);
2642 GNUNET_free(hostfile);
2646 data = GNUNET_malloc_large (frstat.st_size);
2647 GNUNET_assert(data != NULL);
2648 if (frstat.st_size !=
2649 GNUNET_DISK_fn_read (hostfile, data, frstat.st_size))
2651 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2652 "Could not read file %s specified for host list, ending test!", hostfile);
2653 GNUNET_free (hostfile);
2655 GNUNET_free_non_null(trialmessage);
2659 GNUNET_free_non_null(hostfile);
2663 while (count < frstat.st_size)
2666 /* if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count]))*/
2667 if (((data[count] == '\n')) && (buf != &data[count]))
2670 temphost = GNUNET_malloc(sizeof(struct GNUNET_TESTING_Host));
2671 ret = sscanf(buf, "%a[a-zA-Z0-9]@%a[a-zA-Z0-9.]:%hd", &temphost->username, &temphost->hostname, &temphost->port);
2674 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Successfully read host %s, port %d and user %s from file\n", temphost->hostname, temphost->port, temphost->username);
2678 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Error reading line `%s' in hostfile\n", buf);
2679 GNUNET_free(temphost);
2680 buf = &data[count + 1];
2683 /* temphost->hostname = buf; */
2684 temphost->next = hosts;
2686 buf = &data[count + 1];
2688 else if ((data[count] == '\n') || (data[count] == '\0'))
2689 buf = &data[count + 1];
2694 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_getters",
2695 &malicious_getters))
2696 malicious_getters = 0;
2699 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_putters",
2700 &malicious_putters))
2701 malicious_putters = 0;
2704 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_droppers",
2705 &malicious_droppers))
2706 malicious_droppers = 0;
2709 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "settle_time",
2713 if (GNUNET_SYSERR ==
2714 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_puts",
2716 num_puts = num_peers;
2718 if (GNUNET_SYSERR ==
2719 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_gets",
2721 num_gets = num_peers;
2724 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "find_peer_delay",
2725 &temp_config_number))
2726 find_peer_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
2728 find_peer_delay = DEFAULT_FIND_PEER_DELAY;
2731 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_find_peers",
2732 &temp_config_number))
2733 max_outstanding_find_peers = temp_config_number;
2735 max_outstanding_find_peers = DEFAULT_MAX_OUTSTANDING_FIND_PEERS;
2738 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_timeout",
2739 &temp_config_number))
2740 get_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
2742 get_timeout = DEFAULT_GET_TIMEOUT;
2745 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_puts",
2746 &temp_config_number))
2747 max_outstanding_puts = temp_config_number;
2749 max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS;
2752 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_gets",
2753 &temp_config_number))
2754 max_outstanding_gets = temp_config_number;
2756 max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS;
2759 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "timeout",
2760 &temp_config_number))
2761 all_get_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
2763 all_get_timeout.value = get_timeout.value * num_gets;
2766 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_delay",
2767 &temp_config_number))
2768 get_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
2770 get_delay = DEFAULT_GET_DELAY;
2773 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "put_delay",
2774 &temp_config_number))
2775 put_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
2777 put_delay = DEFAULT_PUT_DELAY;
2780 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "peer_start_timeout",
2781 &temp_config_number))
2782 seconds_per_peer_start = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
2784 seconds_per_peer_start = DEFAULT_SECONDS_PER_PEER_START;
2787 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "data_size",
2788 &temp_config_number))
2789 test_data_size = temp_config_number;
2791 test_data_size = DEFAULT_TEST_DATA_SIZE;
2794 * Get testing related options.
2796 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "DHT_TESTING", "REPLICATE_SAME"))
2798 replicate_same = GNUNET_YES;
2801 if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
2802 "MALICIOUS_GET_FREQUENCY",
2803 &malicious_get_frequency))
2804 malicious_get_frequency = DEFAULT_MALICIOUS_GET_FREQUENCY;
2807 if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
2808 "MALICIOUS_PUT_FREQUENCY",
2809 &malicious_put_frequency))
2810 malicious_put_frequency = DEFAULT_MALICIOUS_PUT_FREQUENCY;
2813 /* The normal behavior of the DHT is to do find peer requests
2814 * on its own. Only if this is explicitly turned off should
2815 * the testing driver issue find peer requests (even though
2816 * this is likely the default when testing).
2819 GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht",
2822 do_find_peer = GNUNET_YES;
2826 GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht",
2829 in_dht_replication = GNUNET_YES;
2832 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
2839 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
2841 &temp_config_number))
2843 find_peer_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
2846 find_peer_delay = DEFAULT_FIND_PEER_DELAY;
2848 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_number(cfg, "DHT_TESTING", "ROUND_DELAY", &round_delay))
2851 if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
2852 "OUTSTANDING_FIND_PEERS",
2853 &max_outstanding_find_peers))
2854 max_outstanding_find_peers = DEFAULT_MAX_OUTSTANDING_FIND_PEERS;
2856 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht", "strict_kademlia"))
2857 max_outstanding_find_peers = max_outstanding_find_peers * 1;
2859 find_peer_offset = GNUNET_TIME_relative_divide (find_peer_delay, max_outstanding_find_peers);
2861 if (GNUNET_SYSERR ==
2862 GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_rounds",
2868 topology_str = NULL;
2870 GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "topology",
2871 &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&topology, topology_str)))
2873 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2874 "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY");
2875 topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
2879 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
2880 &topology_percentage_str))
2881 topology_percentage = 0.5;
2884 topology_percentage = atof (topology_percentage_str);
2885 GNUNET_free(topology_percentage_str);
2889 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
2890 &topology_probability_str))
2891 topology_probability = 0.5;
2894 topology_probability = atof (topology_probability_str);
2895 GNUNET_free(topology_probability_str);
2899 GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology",
2900 &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&connect_topology, connect_topology_str)))
2902 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2903 "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY");
2905 GNUNET_free_non_null(connect_topology_str);
2908 GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology_option",
2909 &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get(&connect_topology_option, connect_topology_option_str)))
2911 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2912 "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION");
2913 connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
2915 GNUNET_free_non_null(connect_topology_option_str);
2918 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier",
2919 &connect_topology_option_modifier_string))
2921 if (sscanf(connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1)
2923 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2924 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
2925 connect_topology_option_modifier_string,
2926 "connect_topology_option_modifier",
2929 GNUNET_free (connect_topology_option_modifier_string);
2932 if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports",
2933 &blacklist_transports))
2934 blacklist_transports = NULL;
2937 GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "blacklist_topology",
2938 &blacklist_topology_str)) &&
2939 (GNUNET_NO == GNUNET_TESTING_topology_get(&blacklist_topology, blacklist_topology_str)))
2941 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2942 "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY");
2944 GNUNET_free_non_null(topology_str);
2945 GNUNET_free_non_null(blacklist_topology_str);
2947 /* Get number of peers to start from configuration */
2948 if (GNUNET_SYSERR ==
2949 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
2952 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2953 "Number of peers must be specified in section %s option %s\n", topology_str, "TESTING", "NUM_PEERS");
2955 GNUNET_assert(num_peers > 0 && num_peers < (unsigned long long)-1);
2956 /* Set peers_left so we know when all peers started */
2957 peers_left = num_peers;
2960 /* Set up a task to end testing if peer start fails */
2961 die_task = GNUNET_SCHEDULER_add_delayed (sched,
2962 GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers),
2963 &end_badly, "didn't generate all hostkeys within allowed startup time!");
2965 if (dhtlog_handle == NULL)
2966 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2967 "dhtlog_handle is NULL!");
2969 trial_info.other_identifier = (unsigned int)trial_to_run;
2970 trial_info.num_nodes = peers_left;
2971 trial_info.topology = topology;
2972 trial_info.blacklist_topology = blacklist_topology;
2973 trial_info.connect_topology = connect_topology;
2974 trial_info.connect_topology_option = connect_topology_option;
2975 trial_info.connect_topology_option_modifier = connect_topology_option_modifier;
2976 trial_info.topology_percentage = topology_percentage;
2977 trial_info.topology_probability = topology_probability;
2978 trial_info.puts = num_puts;
2979 trial_info.gets = num_gets;
2980 trial_info.concurrent = max_outstanding_gets;
2981 trial_info.settle_time = settle_time;
2982 trial_info.num_rounds = 1;
2983 trial_info.malicious_getters = malicious_getters;
2984 trial_info.malicious_putters = malicious_putters;
2985 trial_info.malicious_droppers = malicious_droppers;
2986 trial_info.malicious_get_frequency = malicious_get_frequency;
2987 trial_info.malicious_put_frequency = malicious_put_frequency;
2988 trial_info.stop_closest = stop_closest;
2989 trial_info.stop_found = stop_found;
2990 trial_info.strict_kademlia = strict_kademlia;
2992 if (trialmessage != NULL)
2993 trial_info.message = trialmessage;
2995 trial_info.message = "";
2997 if (dhtlog_handle != NULL)
2998 dhtlog_handle->insert_trial(&trial_info);
3000 GNUNET_free_non_null(trialmessage);
3002 hostkey_meter = create_meter(peers_left, "Hostkeys created ", GNUNET_YES);
3003 peer_start_meter = create_meter(peers_left, "Peers started ", GNUNET_YES);
3005 put_meter = create_meter(num_puts, "Puts completed ", GNUNET_YES);
3006 get_meter = create_meter(num_gets, "Gets completed ", GNUNET_YES);
3007 pg = GNUNET_TESTING_daemons_start (sched, cfg,
3009 GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers),
3010 &hostkey_callback, NULL,
3011 &peers_started_callback, NULL,
3012 &topology_callback, NULL,
3015 while (temphost != NULL)
3017 tempnext = temphost->next;
3018 GNUNET_free (temphost->username);
3019 GNUNET_free (temphost->hostname);
3020 GNUNET_free (temphost);
3021 temphost = tempnext;
3027 main (int argc, char *argv[])
3030 struct GNUNET_GETOPT_CommandLineOption options[] = {
3031 GNUNET_GETOPT_OPTION_END
3034 ret = GNUNET_PROGRAM_run (argc,
3035 argv, "gnunet-dht-driver", "nohelp",
3036 options, &run, &ok);
3038 if (ret != GNUNET_OK)
3040 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`gnunet-dht-driver': Failed with error code %d\n", ret);
3044 * Need to remove base directory, subdirectories taken care
3045 * of by the testing framework.
3047 if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
3049 GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
3054 /* end of gnunet-dht-driver.c */