even nicer indentation, thanks to LRN's indent patch
[oweals/gnunet.git] / src / dht / gnunet-dht-driver.c
1 /*
2  This file is part of GNUnet.
3  (C) 2009 Christian Grothoff (and other contributing authors)
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  option) any later version.
9
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file 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.
26  * @author Nathan Evans (who to blame)
27  */
28 #include "platform.h"
29 #ifndef HAVE_MALICIOUS
30 #error foo
31 #endif
32 #include "gnunet_testing_lib.h"
33 #include "gnunet_core_service.h"
34 #include "gnunet_dht_service.h"
35 #include "dhtlog.h"
36 #include "dht.h"
37 #include "gauger.h"
38
39 /* Specific DEBUG hack, do not use normally (may leak memory, segfault, or eat children.) */
40 #define ONLY_TESTING GNUNET_NO
41
42 /* DEFINES */
43 #define VERBOSE GNUNET_NO
44
45 /* Timeout for entire driver to run */
46 #define DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
47
48 /* Timeout for waiting for (individual) replies to get requests */
49 #define DEFAULT_GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
50
51 #define DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
52
53 /* Timeout for waiting for gets to be sent to the service */
54 #define DEFAULT_GET_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
55
56 /* Timeout for waiting for puts to be sent to the service */
57 #define DEFAULT_PUT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
58
59 /* Time to allow a find peer request to take */
60 #define DEFAULT_FIND_PEER_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40)
61
62 /* Time to wait for all peers disconnected due to to churn to actually be removed from system */
63 #define DEFAULT_PEER_DISCONNECT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
64
65 #define DEFAULT_SECONDS_PER_PEER_START GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 45)
66
67 #define DEFAULT_TEST_DATA_SIZE 8
68
69 #define DEFAULT_BUCKET_SIZE 4
70
71 /* If more than this many peers are added, slow down sending */
72 #define MAX_FIND_PEER_CUTOFF 2000
73
74 /* If less than this many peers are added, speed up sending */
75 #define MIN_FIND_PEER_CUTOFF 500
76
77 /* How often (in seconds) to print out connection information */
78 #define CONN_UPDATE_DURATION 10
79
80 #define DEFAULT_MAX_OUTSTANDING_PUTS 10
81
82 #define DEFAULT_MAX_OUTSTANDING_FIND_PEERS 64
83
84 #define DEFAULT_FIND_PEER_OFFSET GNUNET_TIME_relative_divide (DEFAULT_FIND_PEER_DELAY, DEFAULT_MAX_OUTSTANDING_FIND_PEERS)
85
86 #define DEFAULT_MAX_OUTSTANDING_GETS 10
87
88 #define DEFAULT_CONNECT_TIMEOUT 60
89
90 #define DEFAULT_TOPOLOGY_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 8)
91
92 #define DEFAULT_RECONNECT_ATTEMPTS 8
93
94 /*
95  * Default frequency for sending malicious get messages
96  */
97 #define DEFAULT_MALICIOUS_GET_FREQUENCY GNUNET_TIME_UNIT_SECONDS
98
99 /*
100  * Default frequency for sending malicious put messages
101  */
102 #define DEFAULT_MALICIOUS_PUT_FREQUENCY GNUNET_TIME_UNIT_SECONDS
103
104 /* Structs */
105
106 struct MaliciousContext
107 {
108   /**
109    * Handle to DHT service (via the API)
110    */
111   struct GNUNET_DHT_Handle *dht_handle;
112
113   /**
114    *  Handle to the peer daemon
115    */
116   struct GNUNET_TESTING_Daemon *daemon;
117
118   /**
119    * Task for disconnecting DHT handles
120    */
121   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
122
123   /**
124    * What type of malicious to set this peer to.
125    */
126   int malicious_type;
127 };
128
129 struct TestFindPeer
130 {
131   /* This is a linked list */
132   struct TestFindPeer *next;
133
134   /* Handle to the bigger context */
135   struct FindPeerContext *find_peer_context;
136
137   /**
138    * Handle to the peer's DHT service (via the API)
139    */
140   struct GNUNET_DHT_Handle *dht_handle;
141
142   /**
143    *  Handle to the peer daemon
144    */
145   struct GNUNET_TESTING_Daemon *daemon;
146
147   /**
148    * Task for disconnecting DHT handles
149    */
150   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
151 };
152
153 struct TestPutContext
154 {
155   /* This is a linked list */
156   struct TestPutContext *next;
157
158   /**
159    * Handle to the first peers DHT service (via the API)
160    */
161   struct GNUNET_DHT_Handle *dht_handle;
162
163   /**
164    *  Handle to the PUT peer daemon
165    */
166   struct GNUNET_TESTING_Daemon *daemon;
167
168   /**
169    *  Identifier for this PUT
170    */
171   uint32_t uid;
172
173   /**
174    * Task for disconnecting DHT handles
175    */
176   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
177 };
178
179 struct TestGetContext
180 {
181   /* This is a linked list */
182   struct TestGetContext *next;
183
184   /**
185    * Handle to the first peers DHT service (via the API)
186    */
187   struct GNUNET_DHT_Handle *dht_handle;
188
189   /**
190    * Handle for the DHT get request
191    */
192   struct GNUNET_DHT_GetHandle *get_handle;
193
194   /**
195    *  Handle to the GET peer daemon
196    */
197   struct GNUNET_TESTING_Daemon *daemon;
198
199   /**
200    *  Identifier for this GET
201    */
202   uint32_t uid;
203
204   /**
205    * Task for disconnecting DHT handles (and stopping GET)
206    */
207   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
208
209   /**
210    * Whether or not this request has been fulfilled already.
211    */
212   int succeeded;
213 };
214
215 /**
216  * Simple struct to keep track of progress, and print a
217  * nice little percentage meter for long running tasks.
218  */
219 struct ProgressMeter
220 {
221   unsigned int total;
222
223   unsigned int modnum;
224
225   unsigned int dotnum;
226
227   unsigned int completed;
228
229   int print;
230
231   char *startup_string;
232 };
233
234 /**
235  * Linked list of information for populating statistics
236  * before ending trial.
237  */
238 struct StatisticsIteratorContext
239 {
240   const struct GNUNET_PeerIdentity *peer;
241   unsigned int stat_routes;
242   unsigned int stat_route_forwards;
243   unsigned int stat_results;
244   unsigned int stat_results_to_client;
245   unsigned int stat_result_forwards;
246   unsigned int stat_gets;
247   unsigned int stat_puts;
248   unsigned int stat_puts_inserted;
249   unsigned int stat_find_peer;
250   unsigned int stat_find_peer_start;
251   unsigned int stat_get_start;
252   unsigned int stat_put_start;
253   unsigned int stat_find_peer_reply;
254   unsigned int stat_get_reply;
255   unsigned int stat_find_peer_answer;
256   unsigned int stat_get_response_start;
257 };
258
259 /**
260  * Context for getting a topology, logging it, and continuing
261  * on with some next operation.
262  */
263 struct TopologyIteratorContext
264 {
265   unsigned int total_iterations;
266   unsigned int current_iteration;
267   unsigned int total_connections;
268   unsigned int total_peers;
269   struct GNUNET_CONTAINER_MultiHashMap *peers_seen;
270   struct GNUNET_PeerIdentity *peer;
271   GNUNET_SCHEDULER_Task cont;
272   void *cls;
273   struct GNUNET_TIME_Relative timeout;
274 };
275
276 struct PeerCount
277 {
278   /** Node in the heap */
279   struct GNUNET_CONTAINER_HeapNode *heap_node;
280
281   /** Peer the count refers to */
282   struct GNUNET_PeerIdentity peer_id;
283
284   /** Count of connections this peer has */
285   unsigned int count;
286 };
287
288 /**
289  * Context for sending out find peer requests.
290  */
291 struct FindPeerContext
292 {
293   /**
294    * How long to send find peer requests, once the settle time
295    * is over don't send any more out!
296    */
297   struct GNUNET_TIME_Absolute endtime;
298
299   /**
300    * Number of connections in the current topology
301    * (after this round of find peer requests has ended).
302    */
303   unsigned int current_peers;
304
305   /**
306    * Number of connections in the current topology
307    * (before this round of find peer requests started).
308    */
309   unsigned int previous_peers;
310
311   /**
312    * Number of find peer requests we have currently
313    * outstanding.
314    */
315   unsigned int outstanding;
316
317   /**
318    * Number of find peer requests to send in this round.
319    */
320   unsigned int total;
321
322   /**
323    * Number of find peer requests sent last time around.
324    */
325   unsigned int last_sent;
326
327   /**
328    * Hashmap of peers in the current topology, value
329    * is a PeerCount, with the number of connections
330    * this peer has.
331    */
332   struct GNUNET_CONTAINER_MultiHashMap *peer_hash;
333
334   /**
335    * Min heap which orders values in the peer_hash for
336    * easy lookup.
337    */
338   struct GNUNET_CONTAINER_Heap *peer_min_heap;
339
340   /**
341    * Callback for counting the peers in the current topology.
342    */
343   GNUNET_TESTING_NotifyTopology count_peers_cb;
344 };
345
346 enum DHT_ROUND_TYPES
347 {
348   /**
349    * Next full round (puts + gets).
350    */
351   DHT_ROUND_NORMAL,
352
353   /**
354    * Next round of gets.
355    */
356   DHT_ROUND_GET,
357
358   /**
359    * Next round of puts.
360    */
361   DHT_ROUND_PUT,
362
363   /**
364    * Next round of churn.
365    */
366   DHT_ROUND_CHURN
367 };
368
369 /* Globals */
370
371 /**
372  * How long to try to connect two peers.
373  */
374 struct GNUNET_TIME_Relative connect_timeout;
375
376 /**
377  * How many times to re-attempt connecting two peers.
378  */
379 static unsigned long long connect_attempts;
380
381 /**
382  * Timeout to let all GET requests happen.
383  */
384 static struct GNUNET_TIME_Relative all_get_timeout;
385
386 /**
387  * Per get timeout
388  */
389 static struct GNUNET_TIME_Relative get_timeout;
390
391 /**
392  * Time to allow for GET requests to be sent to service.
393  */
394 static struct GNUNET_TIME_Relative get_delay;
395
396 /**
397  * Time to allow for PUT requests to be sent to service.
398  */
399 static struct GNUNET_TIME_Relative put_delay;
400
401 /**
402  * Delay between sending find peer requests (if
403  * handled by the driver, no effect if sent by service).
404  */
405 static struct GNUNET_TIME_Relative find_peer_delay;
406
407 /**
408  * Time between find peer requests
409  * (find_peer_delay / max_outstanding_find_peer)
410  */
411 static struct GNUNET_TIME_Relative find_peer_offset;
412
413 /**
414  * How many seconds to allow each peer to start.
415  */
416 static struct GNUNET_TIME_Relative seconds_per_peer_start;
417
418 /**
419  * At what time did we start the connection process.
420  */
421 static struct GNUNET_TIME_Absolute connect_start_time;
422
423 /**
424  * What was the last time we updated connection/second information.
425  */
426 static struct GNUNET_TIME_Absolute connect_last_time;
427
428 /**
429  * At what time did we start the hostkey creation process.
430  */
431 static struct GNUNET_TIME_Absolute hostkey_start_time;
432
433 /**
434  * At what time did we start the peer startup process.
435  */
436 static struct GNUNET_TIME_Absolute peer_start_time;
437
438 /**
439  * Boolean value, should the driver issue find peer requests
440  * (GNUNET_YES) or should it be left to the service (GNUNET_NO)
441  */
442 static unsigned int do_find_peer;
443
444 /**
445  * Whether or not to insert gauger data.
446  */
447 static unsigned int insert_gauger_data;
448
449 #if ONLY_TESTING
450 /**
451  * Are we currently trying to connect two peers repeatedly?
452  */
453 static unsigned int repeat_connect_mode;
454
455 /**
456  * Task for repeating connects.
457  */
458 GNUNET_SCHEDULER_TaskIdentifier repeat_connect_task;
459
460 struct GNUNET_TESTING_Daemon *repeat_connect_peer1;
461 struct GNUNET_TESTING_Daemon *repeat_connect_peer2;
462 #endif
463
464 /**
465  * Boolean value, should replication be done by the dht
466  * service (GNUNET_YES) or by the driver (GNUNET_NO)
467  */
468 static unsigned int in_dht_replication;
469
470 /**
471  * Size of test data to insert/retrieve during testing.
472  */
473 static unsigned long long test_data_size = DEFAULT_TEST_DATA_SIZE;
474
475 /**
476  * Maximum number of concurrent connections to peers.
477  */
478 static unsigned long long max_outstanding_connections;
479
480 /**
481  * Maximum number of concurrent ssh instances to peers.
482  */
483 static unsigned long long max_concurrent_ssh;
484
485 /**
486  * Maximum number of concurrent PUT requests.
487  */
488 static unsigned long long max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS;
489
490 /**
491  * Maximum number of concurrent GET requests.
492  */
493 static unsigned long long max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS;
494
495 /**
496  * Number of nodes issuing malicious GET messages.
497  */
498 static unsigned long long malicious_getters;
499
500 /**
501  * Maximum number of concurrent find peer messages being sent.
502  */
503 static unsigned long long max_outstanding_find_peers;
504
505 /**
506  * Number of nodes issuing malicious PUT messages.
507  */
508 static unsigned long long malicious_putters;
509
510 /**
511  * Time (in seconds) to delay between rounds.
512  */
513 static unsigned long long round_delay;
514
515 /**
516  * The identifier for this trial (if we have one)
517  * for external data collection.
518  */
519 static unsigned long long trial_to_run;
520
521 /**
522  * How many malicious droppers to seed in the network.
523  */
524 static unsigned long long malicious_droppers;
525
526 /**
527  * Bloom filter to restrict malicious nodes chosen.
528  */
529 struct GNUNET_CONTAINER_BloomFilter *malicious_bloom;
530
531 /**
532  * Whether malicious droppers should be chosen based on proximity to a key.
533  */
534 static int malicious_sybil;
535
536 /**
537  * Target for the malicious sybil nodes (choose the closest to this key).
538  */
539 static GNUNET_HashCode sybil_target;
540
541 /**
542  * How often to send malicious GET messages.
543  */
544 static struct GNUNET_TIME_Relative malicious_get_frequency;
545
546 /**
547  * How often to send malicious PUT messages.
548  */
549 static struct GNUNET_TIME_Relative malicious_put_frequency;
550
551 /**
552  * How long to send find peer requests.
553  */
554 static unsigned long long settle_time;
555
556 /**
557  * Handle to the dhtlog service.
558  */
559 static struct GNUNET_DHTLOG_Handle *dhtlog_handle;
560
561 /**
562  * Replication value for GET requests.
563  */
564 static unsigned long long get_replication;
565
566 /**
567  * Replication value for PUT requests.
568  */
569 static unsigned long long put_replication;
570
571 /**
572  * If GNUNET_YES, insert data at the same peers every time.
573  * Otherwise, choose a new random peer to insert at each time.
574  */
575 static unsigned int replicate_same;
576
577 /**
578  * If GNUNET_YES, issue GET requests at the same peers every time.
579  * Otherwise, choose a new random peer/data combination to search
580  * each time.
581  */
582 static unsigned int get_from_same;
583
584 /**
585  * Should malicious peers be set after allowing for settle time?
586  * Default is to set them malicious after initial connection setup.
587  */
588 static unsigned int malicious_after_settle;
589
590 /**
591  * Number of rounds for testing (PUTS + GETS)
592  */
593 static unsigned long long total_rounds;
594
595 /**
596  * Target number of connections (will stop sending find peer
597  * messages when this number is exceeded)
598  */
599 static unsigned long long target_total_connections;
600
601 /**
602  * Number of rounds already run
603  */
604 static unsigned int rounds_finished;
605
606 /**
607  * Number of rounds of churn to read from the file (first line, should be a single number).
608  */
609 static unsigned int churn_rounds;
610
611 /**
612  * Current round we are in for churn, tells us how many peers to connect/disconnect.
613  */
614 static unsigned int current_churn_round;
615
616 /**
617  * Number of times to churn per round
618  */
619 static unsigned long long churns_per_round;
620
621 /**
622  * Array of churn values.
623  */
624 static unsigned int *churn_array;
625
626 /**
627  * Hash map of stats contexts.
628  */
629 static struct GNUNET_CONTAINER_MultiHashMap *stats_map;
630
631 /**
632  * LL of malicious settings.
633  */
634 struct MaliciousContext *all_malicious;
635
636 /**
637  * List of GETS to perform
638  */
639 struct TestGetContext *all_gets;
640
641 /**
642  * List of PUTS to perform
643  */
644 struct TestPutContext *all_puts;
645
646 /**
647  * Directory to store temporary data in, defined in config file
648  */
649 static char *test_directory;
650
651 /**
652  * Variable used to store the number of connections we should wait for.
653  */
654 static unsigned int expected_connections;
655
656 /**
657  * Variable used to keep track of how many peers aren't yet started.
658  */
659 static unsigned long long peers_left;
660
661 /**
662  * Handle to the set of all peers run for this test.
663  */
664 static struct GNUNET_TESTING_PeerGroup *pg;
665
666 /**
667  * Global config handle.
668  */
669 static const struct GNUNET_CONFIGURATION_Handle *config;
670
671 /**
672  * Total number of peers to run, set based on config file.
673  */
674 static unsigned long long num_peers;
675
676 /**
677  * Total number of items to insert.
678  */
679 static unsigned long long num_puts;
680
681 /**
682  * How many puts do we currently have in flight?
683  */
684 static unsigned long long outstanding_puts;
685
686 /**
687  * How many puts are done?
688  */
689 static unsigned long long puts_completed;
690
691 /**
692  * Total number of items to attempt to get.
693  */
694 static unsigned long long num_gets;
695
696 /**
697  * How many puts do we currently have in flight?
698  */
699 static unsigned long long outstanding_gets;
700
701 /**
702  * How many gets are done?
703  */
704 static unsigned long long gets_completed;
705
706 /**
707  * If non-zero, end testing if this many GETs
708  * complete in a single round.
709  */
710 static unsigned long long target_completions;
711
712 /**
713  * Total number of items to attempt to get.
714  */
715 static unsigned long long cumulative_num_gets;
716
717 /**
718  * How many gets are done?
719  */
720 static unsigned long long cumulative_successful_gets;
721
722 /**
723  * How many gets failed?
724  */
725 static unsigned long long gets_failed;
726
727 /**
728  * How many malicious control messages do
729  * we currently have in flight?
730  */
731 static unsigned long long outstanding_malicious;
732
733 /**
734  * How many set malicious peers are done?
735  */
736 static unsigned int malicious_completed;
737
738 /**
739  * For gauger logging, what specific identifier (svn revision)
740  * should be used?
741  */
742 static unsigned long long revision;
743
744 /**
745  * Global used to count how many connections we have currently
746  * been notified about (how many times has topology_callback been called
747  * with success?)
748  */
749 static uint64_t total_connections;
750
751 /**
752  * Previous connections, for counting new connections during some duration.
753  */
754 static uint64_t previous_connections;
755
756 /**
757  * For counting failed connections during some duration.
758  */
759 static uint64_t previous_failed_connections;
760
761 /**
762  * Global used to count how many failed connections we have
763  * been notified about (how many times has topology_callback
764  * been called with failure?)
765  */
766 static uint64_t failed_connections;
767
768 /**
769  * If GNUNET_YES, only log PUT/GET round data to mysql, otherwise
770  * log everything (including each dht service logging).
771  */
772 static unsigned int dhtlog_minimal;
773
774 /* Task handle to use to schedule shutdown if something goes wrong */
775 GNUNET_SCHEDULER_TaskIdentifier die_task;
776
777 static char *blacklist_transports;
778
779 static enum GNUNET_TESTING_Topology topology;
780
781 static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE;  /* Don't do any blacklisting */
782
783 static enum GNUNET_TESTING_Topology connect_topology = GNUNET_TESTING_TOPOLOGY_NONE;    /* NONE actually means connect all allowed peers */
784
785 static enum GNUNET_TESTING_TopologyOption connect_topology_option =
786     GNUNET_TESTING_TOPOLOGY_OPTION_ALL;
787
788 static double connect_topology_option_modifier = 0.0;
789
790 static struct ProgressMeter *hostkey_meter;
791
792 static struct ProgressMeter *peer_start_meter;
793
794 static struct ProgressMeter *peer_connect_meter;
795
796 static struct ProgressMeter *put_meter;
797
798 static struct ProgressMeter *get_meter;
799
800 static GNUNET_HashCode *known_keys;
801
802 /* Global return value (0 for success, anything else for failure) */
803 static int ok;
804
805 /**
806  * Create a meter to keep track of the progress of some task.
807  *
808  * @param total the total number of items to complete
809  * @param start_string a string to prefix the meter with (if printing)
810  * @param print GNUNET_YES to print the meter, GNUNET_NO to count
811  *              internally only
812  *
813  * @return the progress meter
814  */
815 static struct ProgressMeter *
816 create_meter (unsigned int total, char *start_string, int print)
817 {
818   struct ProgressMeter *ret;
819
820   ret = GNUNET_malloc (sizeof (struct ProgressMeter));
821   ret->print = print;
822   ret->total = total;
823   ret->modnum = total / 4;
824   ret->dotnum = (total / 50) + 1;
825   if (start_string != NULL)
826     ret->startup_string = GNUNET_strdup (start_string);
827   else
828     ret->startup_string = GNUNET_strdup ("");
829
830   return ret;
831 }
832
833 /**
834  * Update progress meter (increment by one).
835  *
836  * @param meter the meter to update and print info for
837  *
838  * @return GNUNET_YES if called the total requested,
839  *         GNUNET_NO if more items expected
840  */
841 static int
842 update_meter (struct ProgressMeter *meter)
843 {
844   if (meter->print == GNUNET_YES)
845   {
846     if (meter->completed % meter->modnum == 0)
847     {
848       if (meter->completed == 0)
849       {
850         fprintf (stdout, "%sProgress: [0%%", meter->startup_string);
851       }
852       else
853         fprintf (stdout, "%d%%",
854                  (int) (((float) meter->completed / meter->total) * 100));
855     }
856     else if (meter->completed % meter->dotnum == 0)
857       fprintf (stdout, ".");
858
859     if (meter->completed + 1 == meter->total)
860       fprintf (stdout, "%d%%]\n", 100);
861     fflush (stdout);
862   }
863   meter->completed++;
864
865   if (meter->completed == meter->total)
866     return GNUNET_YES;
867   return GNUNET_NO;
868 }
869
870 /**
871  * Reset progress meter.
872  *
873  * @param meter the meter to reset
874  *
875  * @return GNUNET_YES if meter reset,
876  *         GNUNET_SYSERR on error
877  */
878 static int
879 reset_meter (struct ProgressMeter *meter)
880 {
881   if (meter == NULL)
882     return GNUNET_SYSERR;
883
884   meter->completed = 0;
885   return GNUNET_YES;
886 }
887
888 /**
889  * Release resources for meter
890  *
891  * @param meter the meter to free
892  */
893 static void
894 free_meter (struct ProgressMeter *meter)
895 {
896   GNUNET_free_non_null (meter->startup_string);
897   GNUNET_free (meter);
898 }
899
900 /**
901  * Check whether peers successfully shut down.
902  */
903 static void
904 shutdown_callback (void *cls, const char *emsg)
905 {
906   if (emsg != NULL)
907   {
908     if (ok == 0)
909       ok = 2;
910   }
911 }
912
913 /**
914  * Task to release DHT handles for PUT
915  */
916 static void
917 put_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
918 {
919   struct TestPutContext *test_put = cls;
920
921   test_put->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
922   GNUNET_DHT_disconnect (test_put->dht_handle);
923   test_put->dht_handle = NULL;
924   if (replicate_same == GNUNET_NO)
925     test_put->daemon =
926         GNUNET_TESTING_daemon_get (pg,
927                                    GNUNET_CRYPTO_random_u32
928                                    (GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
929 }
930
931 /**
932  * Function scheduled to be run on the successful completion of this
933  * testcase.
934  */
935 static void
936 finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
937 {
938   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending test normally!\n",
939               (char *) cls);
940   GNUNET_assert (pg != NULL);
941   struct TestPutContext *test_put = all_puts;
942   struct TestGetContext *test_get = all_gets;
943   char *temp_get_string;
944   char *revision_str;
945
946   while (test_put != NULL)
947   {
948     if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
949       GNUNET_SCHEDULER_cancel (test_put->disconnect_task);
950     if (test_put->dht_handle != NULL)
951       GNUNET_DHT_disconnect (test_put->dht_handle);
952     test_put = test_put->next;
953   }
954
955   while (test_get != NULL)
956   {
957     if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
958       GNUNET_SCHEDULER_cancel (test_get->disconnect_task);
959     if (test_get->get_handle != NULL)
960       GNUNET_DHT_get_stop (test_get->get_handle);
961     if (test_get->dht_handle != NULL)
962       GNUNET_DHT_disconnect (test_get->dht_handle);
963     test_get = test_get->next;
964   }
965
966   GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL);
967
968   if (dhtlog_handle != NULL)
969   {
970     fprintf (stderr, "Update trial endtime\n");
971     dhtlog_handle->update_trial (cumulative_successful_gets);
972     GNUNET_DHTLOG_disconnect (dhtlog_handle);
973     dhtlog_handle = NULL;
974   }
975
976   if (hostkey_meter != NULL)
977     free_meter (hostkey_meter);
978   if (peer_start_meter != NULL)
979     free_meter (peer_start_meter);
980   if (peer_connect_meter != NULL)
981     free_meter (peer_connect_meter);
982   if (put_meter != NULL)
983     free_meter (put_meter);
984   if (get_meter != NULL)
985     free_meter (get_meter);
986
987   GNUNET_asprintf (&temp_get_string, "DHT Successful GETs", trial_to_run);
988   GNUNET_asprintf (&revision_str, "%llu", revision);
989   if (GNUNET_YES == insert_gauger_data)
990     GAUGER_ID ("DHT_TESTING", temp_get_string,
991                cumulative_successful_gets / (double) cumulative_num_gets,
992                "percent successful", revision_str);
993   fprintf (stderr,
994            "Finished trial, had %llu successful gets out of %llu total, %.2f percent succeeded\n",
995            cumulative_successful_gets, cumulative_num_gets,
996            cumulative_successful_gets / (double) cumulative_num_gets);
997   GNUNET_free (temp_get_string);
998
999   ok = 0;
1000 }
1001
1002 /**
1003  * Callback for iterating over all the peer connections of a peer group.
1004  */
1005 static void
1006 log_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first,
1007                  const struct GNUNET_PeerIdentity *second, const char *emsg)
1008 {
1009   struct TopologyIteratorContext *topo_ctx = cls;
1010
1011   if ((first != NULL) && (second != NULL))
1012   {
1013     if ((topo_ctx->peers_seen != NULL) &&
1014         (GNUNET_NO ==
1015          GNUNET_CONTAINER_multihashmap_contains (topo_ctx->peers_seen,
1016                                                  &first->hashPubKey)))
1017     {
1018       GNUNET_CONTAINER_multihashmap_put (topo_ctx->peers_seen,
1019                                          &first->hashPubKey, NULL,
1020                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1021       topo_ctx->total_peers++;
1022     }
1023     topo_ctx->total_connections++;
1024     if ((GNUNET_NO == dhtlog_minimal) && (dhtlog_handle != NULL))
1025       dhtlog_handle->insert_extended_topology (first, second);
1026   }
1027   else
1028   {
1029     GNUNET_assert (dhtlog_handle != NULL);
1030     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1031                 "Topology iteration (%u/%u) finished (%u connections, %u peers)\n",
1032                 topo_ctx->current_iteration, topo_ctx->total_iterations,
1033                 topo_ctx->total_connections, topo_ctx->total_peers);
1034     dhtlog_handle->update_topology (topo_ctx->total_connections);
1035     if (topo_ctx->cont != NULL)
1036       GNUNET_SCHEDULER_add_now (topo_ctx->cont, topo_ctx->cls);
1037     if (topo_ctx->peers_seen != NULL)
1038       GNUNET_CONTAINER_multihashmap_destroy (topo_ctx->peers_seen);
1039     GNUNET_free (topo_ctx);
1040   }
1041 }
1042
1043 /**
1044  * Iterator over hash map entries.
1045  *
1046  * @param cls closure - always NULL
1047  * @param key current key code
1048  * @param value value in the hash map, a stats context
1049  * @return GNUNET_YES if we should continue to
1050  *         iterate,
1051  *         GNUNET_NO if not.
1052  */
1053 static int
1054 stats_iterate (void *cls, const GNUNET_HashCode * key, void *value)
1055 {
1056   struct StatisticsIteratorContext *stats_ctx;
1057
1058   if (value == NULL)
1059     return GNUNET_NO;
1060   stats_ctx = value;
1061   dhtlog_handle->insert_stat (stats_ctx->peer, stats_ctx->stat_routes,
1062                               stats_ctx->stat_route_forwards,
1063                               stats_ctx->stat_results,
1064                               stats_ctx->stat_results_to_client,
1065                               stats_ctx->stat_result_forwards,
1066                               stats_ctx->stat_gets, stats_ctx->stat_puts,
1067                               stats_ctx->stat_puts_inserted,
1068                               stats_ctx->stat_find_peer,
1069                               stats_ctx->stat_find_peer_start,
1070                               stats_ctx->stat_get_start,
1071                               stats_ctx->stat_put_start,
1072                               stats_ctx->stat_find_peer_reply,
1073                               stats_ctx->stat_get_reply,
1074                               stats_ctx->stat_find_peer_answer,
1075                               stats_ctx->stat_get_response_start);
1076   GNUNET_free (stats_ctx);
1077   return GNUNET_YES;
1078 }
1079
1080 static void
1081 stats_finished (void *cls, int result)
1082 {
1083   fprintf (stderr, "Finished getting all peers statistics, iterating!\n");
1084   GNUNET_CONTAINER_multihashmap_iterate (stats_map, &stats_iterate, NULL);
1085   GNUNET_CONTAINER_multihashmap_destroy (stats_map);
1086   GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
1087 }
1088
1089 /**
1090  * Callback function to process statistic values.
1091  *
1092  * @param cls closure
1093  * @param peer the peer the statistics belong to
1094  * @param subsystem name of subsystem that created the statistic
1095  * @param name the name of the datum
1096  * @param value the current value
1097  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
1098  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
1099  */
1100 static int
1101 stats_handle (void *cls, const struct GNUNET_PeerIdentity *peer,
1102               const char *subsystem, const char *name, uint64_t value,
1103               int is_persistent)
1104 {
1105   struct StatisticsIteratorContext *stats_ctx;
1106
1107   if (dhtlog_handle != NULL)
1108     dhtlog_handle->add_generic_stat (peer, name, subsystem, value);
1109   if (GNUNET_CONTAINER_multihashmap_contains (stats_map, &peer->hashPubKey))
1110   {
1111     stats_ctx =
1112         GNUNET_CONTAINER_multihashmap_get (stats_map, &peer->hashPubKey);
1113   }
1114   else
1115   {
1116     stats_ctx = GNUNET_malloc (sizeof (struct StatisticsIteratorContext));
1117     stats_ctx->peer = peer;
1118     GNUNET_CONTAINER_multihashmap_put (stats_map, &peer->hashPubKey, stats_ctx,
1119                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1120   }
1121   GNUNET_assert (stats_ctx != NULL);
1122
1123   if (strcmp (name, STAT_ROUTES) == 0)
1124     stats_ctx->stat_routes = value;
1125   else if (strcmp (name, STAT_ROUTE_FORWARDS) == 0)
1126     stats_ctx->stat_route_forwards = value;
1127   else if (strcmp (name, STAT_RESULTS) == 0)
1128     stats_ctx->stat_results = value;
1129   else if (strcmp (name, STAT_RESULTS_TO_CLIENT) == 0)
1130     stats_ctx->stat_results_to_client = value;
1131   else if (strcmp (name, STAT_RESULT_FORWARDS) == 0)
1132     stats_ctx->stat_result_forwards = value;
1133   else if (strcmp (name, STAT_GETS) == 0)
1134     stats_ctx->stat_gets = value;
1135   else if (strcmp (name, STAT_PUTS) == 0)
1136     stats_ctx->stat_puts = value;
1137   else if (strcmp (name, STAT_PUTS_INSERTED) == 0)
1138     stats_ctx->stat_puts_inserted = value;
1139   else if (strcmp (name, STAT_FIND_PEER) == 0)
1140     stats_ctx->stat_find_peer = value;
1141   else if (strcmp (name, STAT_FIND_PEER_START) == 0)
1142     stats_ctx->stat_find_peer_start = value;
1143   else if (strcmp (name, STAT_GET_START) == 0)
1144     stats_ctx->stat_get_start = value;
1145   else if (strcmp (name, STAT_PUT_START) == 0)
1146     stats_ctx->stat_put_start = value;
1147   else if (strcmp (name, STAT_FIND_PEER_REPLY) == 0)
1148     stats_ctx->stat_find_peer_reply = value;
1149   else if (strcmp (name, STAT_GET_REPLY) == 0)
1150     stats_ctx->stat_get_reply = value;
1151   else if (strcmp (name, STAT_FIND_PEER_ANSWER) == 0)
1152     stats_ctx->stat_find_peer_answer = value;
1153   else if (strcmp (name, STAT_GET_RESPONSE_START) == 0)
1154     stats_ctx->stat_get_response_start = value;
1155
1156   return GNUNET_OK;
1157 }
1158
1159 /**
1160  * Connect to statistics service for each peer and get the appropriate
1161  * dht statistics for safe keeping.
1162  */
1163 static void
1164 log_dht_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1165 {
1166   stats_map = GNUNET_CONTAINER_multihashmap_create (num_peers);
1167   fprintf (stderr, "Starting statistics logging\n");
1168   GNUNET_TESTING_get_statistics (pg, &stats_finished, &stats_handle, NULL);
1169 }
1170
1171 /**
1172  * Connect to all peers in the peer group and iterate over their
1173  * connections.
1174  */
1175 static void
1176 capture_current_topology (void *cls,
1177                           const struct GNUNET_SCHEDULER_TaskContext *tc)
1178 {
1179   struct TopologyIteratorContext *topo_ctx = cls;
1180
1181   dhtlog_handle->insert_topology (0);
1182   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Called capture_current_topology\n");
1183   GNUNET_TESTING_get_topology (pg, &log_topology_cb, topo_ctx);
1184 }
1185
1186 /**
1187  * Check if the get_handle is being used, if so stop the request.  Either
1188  * way, schedule the end_badly_cont function which actually shuts down the
1189  * test.
1190  */
1191 static void
1192 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1193 {
1194   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failing test with error: `%s'!\n",
1195               (char *) cls);
1196
1197   struct TestPutContext *test_put = all_puts;
1198   struct TestGetContext *test_get = all_gets;
1199
1200   while (test_put != NULL)
1201   {
1202     if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
1203       GNUNET_SCHEDULER_cancel (test_put->disconnect_task);
1204     if (test_put->dht_handle != NULL)
1205       GNUNET_DHT_disconnect (test_put->dht_handle);
1206     test_put = test_put->next;
1207   }
1208
1209   while (test_get != NULL)
1210   {
1211     if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
1212       GNUNET_SCHEDULER_cancel (test_get->disconnect_task);
1213     if (test_get->get_handle != NULL)
1214       GNUNET_DHT_get_stop (test_get->get_handle);
1215     if (test_get->dht_handle != NULL)
1216       GNUNET_DHT_disconnect (test_get->dht_handle);
1217     test_get = test_get->next;
1218   }
1219
1220   GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL);
1221
1222   if (dhtlog_handle != NULL)
1223   {
1224     fprintf (stderr, "Update trial endtime\n");
1225     dhtlog_handle->update_trial (gets_completed);
1226     GNUNET_DHTLOG_disconnect (dhtlog_handle);
1227     dhtlog_handle = NULL;
1228   }
1229
1230   if (hostkey_meter != NULL)
1231     free_meter (hostkey_meter);
1232   if (peer_start_meter != NULL)
1233     free_meter (peer_start_meter);
1234   if (peer_connect_meter != NULL)
1235     free_meter (peer_connect_meter);
1236   if (put_meter != NULL)
1237     free_meter (put_meter);
1238   if (get_meter != NULL)
1239     free_meter (get_meter);
1240
1241   ok = 1;
1242 }
1243
1244 /**
1245  * Forward declaration.
1246  */
1247 static void
1248 do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1249
1250 /**
1251  * Forward declaration.
1252  */
1253 static void
1254 do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1255
1256 /**
1257  * Iterator over hash map entries.
1258  *
1259  * @param cls closure
1260  * @param key current key code
1261  * @param value value in the hash map
1262  * @return GNUNET_YES if we should continue to
1263  *         iterate,
1264  *         GNUNET_NO if not.
1265  */
1266 static int
1267 remove_peer_count (void *cls, const GNUNET_HashCode * key, void *value)
1268 {
1269   struct PeerCount *peer_count = value;
1270
1271   GNUNET_CONTAINER_heap_remove_node (peer_count->heap_node);
1272   GNUNET_free (peer_count);
1273
1274   return GNUNET_YES;
1275 }
1276
1277 /**
1278  * Connect to all peers in the peer group and iterate over their
1279  * connections.
1280  */
1281 static void
1282 count_new_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1283 {
1284   struct FindPeerContext *find_peer_context = cls;
1285
1286   find_peer_context->previous_peers = find_peer_context->current_peers;
1287   find_peer_context->current_peers = 0;
1288   GNUNET_TESTING_get_topology (pg, find_peer_context->count_peers_cb,
1289                                find_peer_context);
1290 }
1291
1292 static void
1293 decrement_find_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1294 {
1295   struct TestFindPeer *test_find_peer = cls;
1296
1297   GNUNET_assert (test_find_peer->find_peer_context->outstanding > 0);
1298   test_find_peer->find_peer_context->outstanding--;
1299   test_find_peer->find_peer_context->total--;
1300   if (0 == test_find_peer->find_peer_context->total)
1301   {
1302     GNUNET_SCHEDULER_add_now (&count_new_peers,
1303                               test_find_peer->find_peer_context);
1304   }
1305   GNUNET_free (test_find_peer);
1306 }
1307
1308 /**
1309  * A find peer request has been sent to the server, now we will schedule a task
1310  * to wait the appropriate time to allow the request to go out and back.
1311  *
1312  * @param cls closure - a TestFindPeer struct
1313  * @param tc context the task is being called with
1314  */
1315 static void
1316 handle_find_peer_sent (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1317 {
1318   struct TestFindPeer *test_find_peer = cls;
1319
1320   GNUNET_DHT_disconnect (test_find_peer->dht_handle);
1321   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
1322                                 (find_peer_delay, 2), &decrement_find_peers,
1323                                 test_find_peer);
1324 }
1325
1326 static void
1327 send_find_peer_request (void *cls,
1328                         const struct GNUNET_SCHEDULER_TaskContext *tc)
1329 {
1330   struct TestFindPeer *test_find_peer = cls;
1331
1332   if (test_find_peer->find_peer_context->outstanding >
1333       max_outstanding_find_peers)
1334   {
1335     GNUNET_SCHEDULER_add_delayed (find_peer_offset, &send_find_peer_request,
1336                                   test_find_peer);
1337     return;
1338   }
1339
1340   test_find_peer->find_peer_context->outstanding++;
1341   if (GNUNET_TIME_absolute_get_remaining
1342       (test_find_peer->find_peer_context->endtime).rel_value == 0)
1343   {
1344     GNUNET_SCHEDULER_add_now (&decrement_find_peers, test_find_peer);
1345     return;
1346   }
1347
1348   test_find_peer->dht_handle =
1349       GNUNET_DHT_connect (test_find_peer->daemon->cfg, 1);
1350   GNUNET_assert (test_find_peer->dht_handle != NULL);
1351   GNUNET_DHT_find_peers (test_find_peer->dht_handle, &handle_find_peer_sent,
1352                          test_find_peer);
1353 }
1354
1355 /**
1356  * Add a connection to the find_peer_context given.  This may
1357  * be complete overkill, but allows us to choose the peers with
1358  * the least connections to initiate find peer requests from.
1359  */
1360 static void
1361 add_new_connection (struct FindPeerContext *find_peer_context,
1362                     const struct GNUNET_PeerIdentity *first,
1363                     const struct GNUNET_PeerIdentity *second)
1364 {
1365   struct PeerCount *first_count;
1366   struct PeerCount *second_count;
1367
1368   if (GNUNET_CONTAINER_multihashmap_contains
1369       (find_peer_context->peer_hash, &first->hashPubKey))
1370   {
1371     first_count =
1372         GNUNET_CONTAINER_multihashmap_get (find_peer_context->peer_hash,
1373                                            &first->hashPubKey);
1374     GNUNET_assert (first_count != NULL);
1375     first_count->count++;
1376     GNUNET_CONTAINER_heap_update_cost (find_peer_context->peer_min_heap,
1377                                        first_count->heap_node,
1378                                        first_count->count);
1379   }
1380   else
1381   {
1382     first_count = GNUNET_malloc (sizeof (struct PeerCount));
1383     first_count->count = 1;
1384     memcpy (&first_count->peer_id, first, sizeof (struct GNUNET_PeerIdentity));
1385     first_count->heap_node =
1386         GNUNET_CONTAINER_heap_insert (find_peer_context->peer_min_heap,
1387                                       first_count, first_count->count);
1388     GNUNET_CONTAINER_multihashmap_put (find_peer_context->peer_hash,
1389                                        &first->hashPubKey, first_count,
1390                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1391   }
1392
1393   if (GNUNET_CONTAINER_multihashmap_contains
1394       (find_peer_context->peer_hash, &second->hashPubKey))
1395   {
1396     second_count =
1397         GNUNET_CONTAINER_multihashmap_get (find_peer_context->peer_hash,
1398                                            &second->hashPubKey);
1399     GNUNET_assert (second_count != NULL);
1400     second_count->count++;
1401     GNUNET_CONTAINER_heap_update_cost (find_peer_context->peer_min_heap,
1402                                        second_count->heap_node,
1403                                        second_count->count);
1404   }
1405   else
1406   {
1407     second_count = GNUNET_malloc (sizeof (struct PeerCount));
1408     second_count->count = 1;
1409     memcpy (&second_count->peer_id, second,
1410             sizeof (struct GNUNET_PeerIdentity));
1411     second_count->heap_node =
1412         GNUNET_CONTAINER_heap_insert (find_peer_context->peer_min_heap,
1413                                       second_count, second_count->count);
1414     GNUNET_CONTAINER_multihashmap_put (find_peer_context->peer_hash,
1415                                        &second->hashPubKey, second_count,
1416                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1417   }
1418 }
1419
1420 /**
1421  * Iterate over min heap of connections per peer.  For any
1422  * peer that has 0 connections, attempt to connect them to
1423  * some random peer.
1424  *
1425  * @param cls closure a struct FindPeerContext
1426  * @param node internal node of the heap
1427  * @param element value stored, a struct PeerCount
1428  * @param cost cost associated with the node
1429  * @return GNUNET_YES if we should continue to iterate,
1430  *         GNUNET_NO if not.
1431  */
1432 static int
1433 iterate_min_heap_peers (void *cls, struct GNUNET_CONTAINER_HeapNode *node,
1434                         void *element, GNUNET_CONTAINER_HeapCostType cost)
1435 {
1436   struct FindPeerContext *find_peer_context = cls;
1437   struct PeerCount *peer_count = element;
1438   struct GNUNET_TESTING_Daemon *d1;
1439   struct GNUNET_TESTING_Daemon *d2;
1440   struct GNUNET_TIME_Relative timeout;
1441
1442   if (cost == 0)
1443   {
1444     d1 = GNUNET_TESTING_daemon_get_by_id (pg, &peer_count->peer_id);
1445     GNUNET_assert (d1 != NULL);
1446     d2 = d1;
1447     while ((d2 == d1) || (GNUNET_YES != GNUNET_TESTING_daemon_running (d2)))
1448     {
1449       d2 = GNUNET_TESTING_daemon_get (pg,
1450                                       GNUNET_CRYPTO_random_u32
1451                                       (GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
1452       GNUNET_assert (d2 != NULL);
1453     }
1454
1455       /** Just try to connect the peers, don't worry about callbacks, etc. **/
1456     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1457                 "Peer %s has 0 connections.  Trying to connect to %s...\n",
1458                 GNUNET_i2s (&peer_count->peer_id), d2->shortname);
1459     timeout =
1460         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1461                                        DEFAULT_CONNECT_TIMEOUT);
1462     if (GNUNET_TIME_relative_to_absolute (timeout).abs_value >
1463         find_peer_context->endtime.abs_value)
1464     {
1465       timeout = GNUNET_TIME_absolute_get_remaining (find_peer_context->endtime);
1466     }
1467     GNUNET_TESTING_daemons_connect (d1, d2, timeout, DEFAULT_RECONNECT_ATTEMPTS,
1468                                     GNUNET_YES, NULL, NULL);
1469   }
1470   if (GNUNET_TIME_absolute_get_remaining (find_peer_context->endtime).rel_value
1471       > 0)
1472     return GNUNET_YES;
1473   else
1474     return GNUNET_NO;
1475 }
1476
1477 /**
1478  * Forward declaration.
1479  */
1480 static void
1481 schedule_churn_find_peer_requests (void *cls,
1482                                    const struct GNUNET_SCHEDULER_TaskContext
1483                                    *tc);
1484
1485 /**
1486  * Callback for iterating over all the peer connections of a peer group.
1487  * Used after we have churned on some peers to find which ones have zero
1488  * connections so we can make them issue find peer requests.
1489  */
1490 static void
1491 count_peers_churn_cb (void *cls, const struct GNUNET_PeerIdentity *first,
1492                       const struct GNUNET_PeerIdentity *second,
1493                       const char *emsg)
1494 {
1495   struct FindPeerContext *find_peer_context = cls;
1496   struct TopologyIteratorContext *topo_ctx;
1497   struct PeerCount *peer_count;
1498
1499   if ((first != NULL) && (second != NULL))
1500   {
1501     add_new_connection (find_peer_context, first, second);
1502     find_peer_context->current_peers++;
1503   }
1504   else
1505   {
1506     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1507                 "Peer count finished (%u connections)\n",
1508                 find_peer_context->current_peers);
1509     peer_count = GNUNET_CONTAINER_heap_peek (find_peer_context->peer_min_heap);
1510     GNUNET_assert (peer_count != NULL);
1511     /* 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. */
1512     /* NO they won't, because we have disabled peerinfo writing to disk (remember?) so we WILL have to give them new connections */
1513     /* Best course of action: have DHT automatically try to add peers from peerinfo on startup. This way IF peerinfo writes to file
1514      * then some peers will end up connected.
1515      *
1516      * Also, find any peers that have zero connections here and set up a task to choose at random another peer in the network to
1517      * 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
1518      * until they get a peer.
1519      */
1520     /* However, they won't automatically be connected to any of their previous peers... How can we handle that? */
1521     /* So now we have choices: do we want them to come back with all their connections?  Probably not, but it solves this mess. */
1522
1523     /* Second problem, which is still a problem, is that a FIND_PEER request won't work when a peer has no connections */
1524
1525       /**
1526        * Okay, so here's how this *should* work now.
1527        *
1528        * 1. We check the min heap for any peers that have 0 connections.
1529        *    a. If any are found, we iterate over the heap and just randomly
1530        *       choose another peer and ask testing to please connect the two.
1531        *       This takes care of the case that a peer just randomly joins the
1532        *       network.  However, if there are strict topology restrictions
1533        *       (imagine a ring) choosing randomly most likely won't help.
1534        *       We make sure the connection attempt doesn't take longer than
1535        *       the total timeout, but don't care too much about the result.
1536        *    b. After that, we still schedule the find peer requests (concurrently
1537        *       with the connect attempts most likely).  This handles the case
1538        *       that the DHT iterates over peerinfo and just needs to try to send
1539        *       a message to get connected.  This should handle the case that the
1540        *       topology is very strict.
1541        *
1542        * 2. If all peers have > 0 connections, we still send find peer requests
1543        *    as long as possible (until timeout is reached) to help out those
1544        *    peers that were newly churned and need more connections.  This is because
1545        *    once all new peers have established a single connection, they won't be
1546        *    well connected.
1547        *
1548        * 3. Once we reach the timeout, we can do no more.  We must schedule the
1549        *    next iteration of get requests regardless of connections that peers
1550        *    may or may not have.
1551        *
1552        * Caveat: it would be nice to get peers to take data offline with them and
1553        *         come back with it (or not) based on the testing framework.  The
1554        *         same goes for remembering previous connections, but putting either
1555        *         into the general testing churn options seems like overkill because
1556        *         these are very specialized cases.
1557        */
1558     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1559                 "Out of %u peers, fewest connections is %d\n",
1560                 GNUNET_CONTAINER_heap_get_size
1561                 (find_peer_context->peer_min_heap), peer_count->count);
1562     if ((peer_count->count == 0) &&
1563         (GNUNET_TIME_absolute_get_remaining
1564          (find_peer_context->endtime).rel_value > 0))
1565     {
1566       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1567                   "Found peer with no connections, will choose some peer(s) at random to connect to!\n");
1568       GNUNET_CONTAINER_heap_iterate (find_peer_context->peer_min_heap,
1569                                      &iterate_min_heap_peers,
1570                                      find_peer_context);
1571       GNUNET_SCHEDULER_add_now (&schedule_churn_find_peer_requests,
1572                                 find_peer_context);
1573     }
1574     else if ((GNUNET_TIME_absolute_get_remaining
1575               (find_peer_context->endtime).rel_value > 0) &&
1576              (find_peer_context->last_sent != 0))
1577     {
1578       GNUNET_SCHEDULER_add_now (&schedule_churn_find_peer_requests,
1579                                 find_peer_context);
1580     }
1581     else
1582     {
1583       GNUNET_CONTAINER_multihashmap_iterate (find_peer_context->peer_hash,
1584                                              &remove_peer_count,
1585                                              find_peer_context);
1586       GNUNET_CONTAINER_multihashmap_destroy (find_peer_context->peer_hash);
1587       GNUNET_CONTAINER_heap_destroy (find_peer_context->peer_min_heap);
1588       GNUNET_free (find_peer_context);
1589       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1590                   "Churn round %u of %llu finished, scheduling next GET round.\n",
1591                   current_churn_round, churn_rounds);
1592       if (dhtlog_handle != NULL)
1593       {
1594         topo_ctx = GNUNET_malloc (sizeof (struct TopologyIteratorContext));
1595         topo_ctx->cont = &do_get;
1596         topo_ctx->cls = all_gets;
1597         topo_ctx->timeout = DEFAULT_GET_TIMEOUT;
1598         topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create (num_peers);
1599         die_task =
1600             GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_add
1601                                           (GNUNET_TIME_relative_add
1602                                            (DEFAULT_GET_TIMEOUT,
1603                                             all_get_timeout),
1604                                            DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
1605                                           &end_badly,
1606                                           "from do gets (count_peers_churn_cb)");
1607         GNUNET_SCHEDULER_add_now (&capture_current_topology, topo_ctx);
1608       }
1609       else
1610       {
1611         die_task =
1612             GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_add
1613                                           (GNUNET_TIME_relative_add
1614                                            (DEFAULT_GET_TIMEOUT,
1615                                             all_get_timeout),
1616                                            DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
1617                                           &end_badly,
1618                                           "from do gets (count_peers_churn_cb)");
1619         GNUNET_SCHEDULER_add_now (&do_get, all_gets);
1620       }
1621     }
1622   }
1623 }
1624
1625 /**
1626  * Set up a single find peer request for each peer in the topology.  Do this
1627  * until the settle time is over, limited by the number of outstanding requests
1628  * and the time allowed for each one!
1629  */
1630 static void
1631 schedule_churn_find_peer_requests (void *cls,
1632                                    const struct GNUNET_SCHEDULER_TaskContext
1633                                    *tc)
1634 {
1635   struct FindPeerContext *find_peer_ctx = cls;
1636   struct TestFindPeer *test_find_peer;
1637   struct PeerCount *peer_count;
1638   uint32_t i;
1639
1640   if (find_peer_ctx->previous_peers == 0)       /* First time, go slowly */
1641     find_peer_ctx->total = 1;
1642   else if (find_peer_ctx->current_peers - find_peer_ctx->previous_peers <
1643            MIN_FIND_PEER_CUTOFF)
1644     find_peer_ctx->total = find_peer_ctx->total / 2;
1645   else if (find_peer_ctx->current_peers - find_peer_ctx->previous_peers > MAX_FIND_PEER_CUTOFF) /* Found LOTS of peers, still go slowly */
1646     find_peer_ctx->total =
1647         find_peer_ctx->last_sent - (find_peer_ctx->last_sent / 4);
1648   else
1649     find_peer_ctx->total = find_peer_ctx->last_sent * 4;
1650
1651   if (find_peer_ctx->total > max_outstanding_find_peers)
1652     find_peer_ctx->total = max_outstanding_find_peers;
1653
1654   find_peer_ctx->last_sent = find_peer_ctx->total;
1655   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1656               "Sending %u find peer messages (after churn)\n",
1657               find_peer_ctx->total);
1658
1659   if (find_peer_ctx->total > 0)
1660     find_peer_offset =
1661         GNUNET_TIME_relative_divide (find_peer_delay, find_peer_ctx->total);
1662   else
1663   {
1664     find_peer_ctx->previous_peers = find_peer_ctx->current_peers;
1665     find_peer_ctx->current_peers = 0;
1666     GNUNET_TESTING_get_topology (pg, &count_peers_churn_cb, find_peer_ctx);
1667   }
1668
1669   for (i = 0; i < find_peer_ctx->total; i++)
1670   {
1671     test_find_peer = GNUNET_malloc (sizeof (struct TestFindPeer));
1672     /* If we have sent requests, choose peers with a low number of connections to send requests from */
1673     peer_count =
1674         GNUNET_CONTAINER_heap_remove_root (find_peer_ctx->peer_min_heap);
1675     GNUNET_assert (peer_count != NULL);
1676     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1677                 "Sending find peer request from peer with %u connections\n",
1678                 peer_count->count);
1679     GNUNET_CONTAINER_multihashmap_remove (find_peer_ctx->peer_hash,
1680                                           &peer_count->peer_id.hashPubKey,
1681                                           peer_count);
1682     test_find_peer->daemon =
1683         GNUNET_TESTING_daemon_get_by_id (pg, &peer_count->peer_id);
1684     GNUNET_assert (test_find_peer->daemon != NULL);
1685     test_find_peer->find_peer_context = find_peer_ctx;
1686     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1687                                   (find_peer_offset, i),
1688                                   &send_find_peer_request, test_find_peer);
1689   }
1690
1691   if ((find_peer_ctx->peer_hash == NULL) &&
1692       (find_peer_ctx->peer_min_heap == NULL))
1693   {
1694     find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create (num_peers);
1695     find_peer_ctx->peer_min_heap =
1696         GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1697   }
1698   else
1699   {
1700     GNUNET_CONTAINER_multihashmap_iterate (find_peer_ctx->peer_hash,
1701                                            &remove_peer_count, find_peer_ctx);
1702     GNUNET_CONTAINER_multihashmap_destroy (find_peer_ctx->peer_hash);
1703     find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create (num_peers);
1704   }
1705
1706   GNUNET_assert (0 ==
1707                  GNUNET_CONTAINER_multihashmap_size (find_peer_ctx->peer_hash));
1708   GNUNET_assert (0 ==
1709                  GNUNET_CONTAINER_heap_get_size (find_peer_ctx->peer_min_heap));
1710 }
1711
1712 static void
1713 schedule_churn_get_topology (void *cls,
1714                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1715 {
1716   struct FindPeerContext *find_peer_context = cls;
1717
1718   GNUNET_TESTING_get_topology (pg, &count_peers_churn_cb, find_peer_context);
1719 }
1720
1721 /**
1722  * Called when churning of the topology has finished.
1723  *
1724  * @param cls closure unused
1725  * @param emsg NULL on success, or a printable error on failure
1726  */
1727 static void
1728 churn_complete (void *cls, const char *emsg)
1729 {
1730   struct FindPeerContext *find_peer_context = cls;
1731   struct PeerCount *peer_count;
1732   unsigned int i;
1733   struct GNUNET_TESTING_Daemon *temp_daemon;
1734   struct TopologyIteratorContext *topo_ctx;
1735   struct GNUNET_TIME_Relative calc_timeout;
1736   int count_added;
1737
1738   if (emsg != NULL)
1739   {
1740     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1741                 "Ending test, churning of peers failed with error `%s'", emsg);
1742     GNUNET_SCHEDULER_add_now (&end_badly, (void *) emsg);
1743     return;
1744   }
1745
1746   /**
1747    * If we switched any peers on, we have to somehow force connect the new peer to
1748    * SOME bootstrap peer in the network.  First schedule a task to find all peers
1749    * with no connections, then choose a random peer for each and connect them.
1750    */
1751   if (find_peer_context != NULL)
1752   {
1753     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1754                 "We have churned on some peers, so we must schedule find peer requests for them!\n");
1755     count_added = 0;
1756     for (i = 0; i < num_peers; i++)
1757     {
1758       temp_daemon = GNUNET_TESTING_daemon_get (pg, i);
1759       if (GNUNET_YES == GNUNET_TESTING_daemon_running (temp_daemon))
1760       {
1761         peer_count = GNUNET_malloc (sizeof (struct PeerCount));
1762         memcpy (&peer_count->peer_id, &temp_daemon->id,
1763                 sizeof (struct GNUNET_PeerIdentity));
1764         GNUNET_assert (peer_count->count == 0);
1765         peer_count->heap_node =
1766             GNUNET_CONTAINER_heap_insert (find_peer_context->peer_min_heap,
1767                                           peer_count, peer_count->count);
1768         GNUNET_CONTAINER_multihashmap_put (find_peer_context->peer_hash,
1769                                            &temp_daemon->id.hashPubKey,
1770                                            peer_count,
1771                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1772         count_added++;
1773       }
1774     }
1775     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1776                 "Added %d peers to heap, total size %d\n", count_added,
1777                 GNUNET_CONTAINER_heap_get_size
1778                 (find_peer_context->peer_min_heap));
1779     GNUNET_SCHEDULER_add_delayed (DEFAULT_PEER_DISCONNECT_TIMEOUT,
1780                                   &schedule_churn_get_topology,
1781                                   find_peer_context);
1782   }
1783   else
1784   {
1785     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1786                 "Only churned off peers, no find peer requests, scheduling more gets (after allowing time for peers to disconnect properly!)...\n");
1787     if (dhtlog_handle != NULL)
1788     {
1789       topo_ctx = GNUNET_malloc (sizeof (struct TopologyIteratorContext));
1790       topo_ctx->cont = &do_get;
1791       topo_ctx->cls = all_gets;
1792       topo_ctx->timeout = DEFAULT_GET_TIMEOUT;
1793       topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create (num_peers);
1794       calc_timeout =
1795           GNUNET_TIME_relative_add (DEFAULT_GET_TIMEOUT, all_get_timeout);
1796       calc_timeout =
1797           GNUNET_TIME_relative_add (calc_timeout,
1798                                     DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT);
1799       calc_timeout =
1800           GNUNET_TIME_relative_add (calc_timeout,
1801                                     DEFAULT_PEER_DISCONNECT_TIMEOUT);
1802       die_task =
1803           GNUNET_SCHEDULER_add_delayed (calc_timeout, &end_badly,
1804                                         "from do gets (churn_complete)");
1805       GNUNET_SCHEDULER_add_delayed (DEFAULT_PEER_DISCONNECT_TIMEOUT,
1806                                     &capture_current_topology, topo_ctx);
1807       dhtlog_handle->insert_round (DHT_ROUND_GET, rounds_finished);
1808     }
1809     else
1810     {
1811       calc_timeout =
1812           GNUNET_TIME_relative_add (DEFAULT_GET_TIMEOUT, all_get_timeout);
1813       calc_timeout =
1814           GNUNET_TIME_relative_add (calc_timeout,
1815                                     DEFAULT_PEER_DISCONNECT_TIMEOUT);
1816       die_task =
1817           GNUNET_SCHEDULER_add_delayed (calc_timeout, &end_badly,
1818                                         "from do gets (churn_complete)");
1819       GNUNET_SCHEDULER_add_delayed (DEFAULT_PEER_DISCONNECT_TIMEOUT, &do_get,
1820                                     all_gets);
1821     }
1822   }
1823 }
1824
1825 /**
1826  * Decide how many peers to turn on or off in this round, make sure the
1827  * numbers actually make sense, then do so.  This function sets in motion
1828  * churn, find peer requests for newly joined peers, and issuing get
1829  * requests once the new peers have done so.
1830  *
1831  * @param cls closure (unused)
1832  * @param tc task context (unused)
1833  */
1834 static void
1835 churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1836 {
1837   unsigned int count_running;
1838   unsigned int churn_up;
1839   unsigned int churn_down;
1840   struct GNUNET_TIME_Relative timeout;
1841   struct FindPeerContext *find_peer_context;
1842
1843   churn_up = churn_down = 0;
1844   count_running = GNUNET_TESTING_daemons_running (pg);
1845   if (count_running > churn_array[current_churn_round])
1846     churn_down = count_running - churn_array[current_churn_round];
1847   else if (count_running < churn_array[current_churn_round])
1848     churn_up = churn_array[current_churn_round] - count_running;
1849   else
1850     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1851                 "Not churning any peers, topology unchanged.\n");
1852
1853   if (churn_up > num_peers - count_running)
1854   {
1855     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1856                 "Churn file specified %u peers (up); only have %u!",
1857                 churn_array[current_churn_round], num_peers);
1858     churn_up = num_peers - count_running;
1859   }
1860   else if (churn_down > count_running)
1861   {
1862     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1863                 "Churn file specified %u peers (down); only have %u!",
1864                 churn_array[current_churn_round], count_running);
1865     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1866                 "This will leave NO peers running (mistake in churn configuration?)!");
1867     churn_down = count_running;
1868   }
1869   //timeout = GNUNET_TIME_relative_multiply(seconds_per_peer_start, churn_up > 0 ? churn_up : churn_down);
1870   //timeout = GNUNET_TIME_relative_multiply (seconds_per_peer_start, churn_up > 0 ? churn_up : churn_down);
1871   timeout = GNUNET_TIME_relative_multiply (DEFAULT_TIMEOUT, 2); /* FIXME: Lack of intelligent choice here */
1872   find_peer_context = NULL;
1873   if (churn_up > 0)             /* Only need to do find peer requests if we turned new peers on */
1874   {
1875     find_peer_context = GNUNET_malloc (sizeof (struct FindPeerContext));
1876     find_peer_context->count_peers_cb = &count_peers_churn_cb;
1877     find_peer_context->previous_peers = 0;
1878     find_peer_context->current_peers = 0;
1879     find_peer_context->endtime = GNUNET_TIME_relative_to_absolute (timeout);
1880     find_peer_context->peer_hash =
1881         GNUNET_CONTAINER_multihashmap_create (num_peers);
1882     find_peer_context->peer_min_heap =
1883         GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1884   }
1885   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1886               "churn_peers: want %u total, %u running, starting %u, stopping %u\n",
1887               churn_array[current_churn_round], count_running, churn_up,
1888               churn_down);
1889   GNUNET_TESTING_daemons_churn (pg, NULL, churn_down, churn_up, timeout,
1890                                 &churn_complete, find_peer_context);
1891   current_churn_round++;
1892 }
1893
1894 /**
1895  * Task to release DHT handle associated with GET request.
1896  */
1897 static void
1898 get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1899 {
1900   struct TestGetContext *test_get = cls;
1901   struct TopologyIteratorContext *topo_ctx;
1902
1903   /* The dht_handle may be null if this get was scheduled from a down peer */
1904   if (test_get->dht_handle != NULL)
1905   {
1906     GNUNET_DHT_disconnect (test_get->dht_handle);
1907     outstanding_gets--;         /* GET is really finished */
1908     test_get->dht_handle = NULL;
1909   }
1910
1911   /* Reset the uid (which item to search for) and the daemon (which peer to search from) for later get request iterations */
1912   if (get_from_same == GNUNET_NO)
1913   {
1914     test_get->uid =
1915         GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_puts);
1916     test_get->daemon =
1917         GNUNET_TESTING_daemon_get (pg,
1918                                    GNUNET_CRYPTO_random_u32
1919                                    (GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
1920   }
1921
1922 #if VERBOSE > 1
1923   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d gets succeeded, %d gets failed!\n",
1924               gets_completed, gets_failed);
1925 #endif
1926   update_meter (get_meter);
1927   if ((gets_completed + gets_failed == num_gets) && (outstanding_gets == 0))
1928   {
1929     fprintf (stderr,
1930              "Canceling die task (get_stop_finished) %llu gets completed, %llu gets failed\n",
1931              gets_completed, gets_failed);
1932     if ((GNUNET_YES == dhtlog_minimal) && (NULL != dhtlog_handle))
1933       dhtlog_handle->insert_round_details (DHT_ROUND_GET, rounds_finished,
1934                                            num_gets, gets_completed);
1935     GNUNET_SCHEDULER_cancel (die_task);
1936     reset_meter (put_meter);
1937     reset_meter (get_meter);
1938     if ((target_completions > 0) && (gets_completed > target_completions))
1939       fprintf (stderr, "Ending test early due to GET success!\n");
1940       /**
1941        *  Handle all cases:
1942        *    1) Testing is completely finished, call the topology iteration dealy and die
1943        *    2) Testing is not finished, churn the network and do gets again (current_churn_round < churn_rounds)
1944        *    3) Testing is not finished, reschedule all the PUTS *and* GETS again (num_rounds > 1)
1945        */
1946     if ((rounds_finished == total_rounds - 1) || ((target_completions > 0) && (gets_completed > target_completions)))   /* Everything is finished, end testing */
1947     {
1948       if ((dhtlog_handle != NULL) && (GNUNET_NO == dhtlog_minimal))
1949       {
1950         topo_ctx = GNUNET_malloc (sizeof (struct TopologyIteratorContext));
1951         topo_ctx->cont = &log_dht_statistics;
1952         topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create (num_peers);
1953         GNUNET_SCHEDULER_add_now (&capture_current_topology, topo_ctx);
1954       }
1955       else
1956         GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
1957     }
1958     else if (current_churn_round < churns_per_round * (rounds_finished + 1))    /* Do next round of churn */
1959     {
1960       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1961                   "Current churn round %u, real round %u, scheduling next round of churn.\n",
1962                   current_churn_round, rounds_finished + 1);
1963       gets_completed = 0;
1964       gets_failed = 0;
1965
1966       if (dhtlog_handle != NULL)
1967         dhtlog_handle->insert_round (DHT_ROUND_CHURN, rounds_finished);
1968
1969       GNUNET_SCHEDULER_add_now (&churn_peers, NULL);
1970     }
1971     else if (rounds_finished < total_rounds - 1)        /* Start a new complete round */
1972     {
1973       rounds_finished++;
1974       gets_completed = 0;
1975       gets_failed = 0;
1976       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1977                   "Round %u of %llu finished, scheduling next round.\n",
1978                   rounds_finished, total_rounds);
1979
1980           /** We reset the peer daemon for puts and gets on each disconnect, so all we need to do is start another round! */
1981       if (GNUNET_YES == in_dht_replication)     /* Replication done in DHT, don't redo puts! */
1982       {
1983         if (dhtlog_handle != NULL)
1984           dhtlog_handle->insert_round (DHT_ROUND_GET, rounds_finished);
1985
1986         die_task =
1987             GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_add
1988                                           (GNUNET_TIME_relative_add
1989                                            (GNUNET_TIME_relative_multiply
1990                                             (GNUNET_TIME_UNIT_SECONDS,
1991                                              round_delay), all_get_timeout),
1992                                            DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
1993                                           &end_badly,
1994                                           "from do gets (next round)");
1995         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1996                                       (GNUNET_TIME_UNIT_SECONDS, round_delay),
1997                                       &do_get, all_gets);
1998       }
1999       else
2000       {
2001         if (dhtlog_handle != NULL)
2002           dhtlog_handle->insert_round (DHT_ROUND_NORMAL, rounds_finished);
2003         die_task =
2004             GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_add
2005                                           (GNUNET_TIME_relative_multiply
2006                                            (GNUNET_TIME_UNIT_SECONDS,
2007                                             round_delay),
2008                                            GNUNET_TIME_relative_multiply
2009                                            (GNUNET_TIME_UNIT_SECONDS,
2010                                             num_puts * 2)), &end_badly,
2011                                           "from do puts");
2012         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2013                                       (GNUNET_TIME_UNIT_SECONDS, round_delay),
2014                                       &do_put, all_puts);
2015       }
2016     }
2017   }
2018 }
2019
2020 /**
2021  * Task to release get handle.
2022  */
2023 static void
2024 get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2025 {
2026   struct TestGetContext *test_get = cls;
2027
2028   if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0)
2029     gets_failed++;
2030   else
2031     cumulative_successful_gets++;
2032
2033   GNUNET_assert (test_get->get_handle != NULL);
2034   GNUNET_DHT_get_stop (test_get->get_handle);
2035   test_get->get_handle = NULL;
2036   test_get->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
2037   GNUNET_SCHEDULER_add_now (&get_stop_finished, test_get);
2038 }
2039
2040 /**
2041  * Iterator called if the GET request initiated returns a response.
2042  *
2043  * @param cls closure
2044  * @param exp when will this value expire
2045  * @param key key of the result
2046  * @param get_path NULL-terminated array of pointers
2047  *                 to the peers on reverse GET path (or NULL if not recorded)
2048  * @param put_path NULL-terminated array of pointers
2049  *                 to the peers on the PUT path (or NULL if not recorded)
2050  * @param type type of the result
2051  * @param size number of bytes in data
2052  * @param data pointer to the result data
2053  */
2054 static void
2055 get_result_iterator (void *cls, struct GNUNET_TIME_Absolute exp,
2056                      const GNUNET_HashCode * key,
2057                      const struct GNUNET_PeerIdentity *const *get_path,
2058                      const struct GNUNET_PeerIdentity *const *put_path,
2059                      enum GNUNET_BLOCK_Type type, size_t size, const void *data)
2060 {
2061   struct TestGetContext *test_get = cls;
2062
2063   if (test_get->succeeded == GNUNET_YES)
2064     return;                     /* Get has already been successful, probably ending now */
2065
2066   if (0 != memcmp (&known_keys[test_get->uid], key, sizeof (GNUNET_HashCode)))  /* || (0 != memcmp(original_data, data, sizeof(original_data)))) */
2067   {
2068     gets_completed++;
2069     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2070                 "Key or data is not the same as was inserted!\n");
2071   }
2072   else
2073   {
2074     gets_completed++;
2075     test_get->succeeded = GNUNET_YES;
2076   }
2077 #if VERBOSE > 1
2078   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n");
2079 #endif
2080   GNUNET_SCHEDULER_cancel (test_get->disconnect_task);
2081   GNUNET_SCHEDULER_add_continuation (&get_stop_task, test_get,
2082                                      GNUNET_SCHEDULER_REASON_PREREQ_DONE);
2083 }
2084
2085 /**
2086  * Set up some data, and call API PUT function
2087  */
2088 static void
2089 do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2090 {
2091   struct TestGetContext *test_get = cls;
2092
2093   if (num_gets == 0)
2094   {
2095     GNUNET_SCHEDULER_cancel (die_task);
2096     GNUNET_SCHEDULER_add_now (&finish_testing, NULL);
2097   }
2098
2099   if (test_get == NULL)
2100     return;                     /* End of the list */
2101
2102   /* Set this here in case we are re-running gets */
2103   test_get->succeeded = GNUNET_NO;
2104
2105   if (GNUNET_YES != GNUNET_TESTING_daemon_running (test_get->daemon))   /* If the peer has been churned off, don't try issuing request from it! */
2106   {
2107     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2108                 "Peer we should issue get request from is down, skipping.\n");
2109     gets_failed++;
2110     GNUNET_SCHEDULER_add_now (&get_stop_finished, test_get);
2111     GNUNET_SCHEDULER_add_now (&do_get, test_get->next);
2112     return;
2113   }
2114
2115   /* Check if more gets are outstanding than should be */
2116   if (outstanding_gets > max_outstanding_gets)
2117   {
2118     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2119                                   (GNUNET_TIME_UNIT_MILLISECONDS, 200), &do_get,
2120                                   test_get);
2121     return;
2122   }
2123
2124   /* Connect to the first peer's DHT */
2125   test_get->dht_handle = GNUNET_DHT_connect (test_get->daemon->cfg, 10);
2126   GNUNET_assert (test_get->dht_handle != NULL);
2127   outstanding_gets++;
2128
2129   cumulative_num_gets++;
2130   /* Insert the data at the first peer */
2131   test_get->get_handle =
2132       GNUNET_DHT_get_start (test_get->dht_handle, get_delay,
2133                             GNUNET_BLOCK_TYPE_TEST, &known_keys[test_get->uid],
2134                             get_replication, GNUNET_DHT_RO_NONE, NULL, 0, NULL,
2135                             0, &get_result_iterator, test_get);
2136
2137 #if VERBOSE > 1
2138   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting get for uid %u from peer %s\n",
2139               test_get->uid, test_get->daemon->shortname);
2140 #endif
2141   test_get->disconnect_task =
2142       GNUNET_SCHEDULER_add_delayed (get_timeout, &get_stop_task, test_get);
2143
2144   /* Schedule the next request in the linked list of get requests */
2145   GNUNET_SCHEDULER_add_now (&do_get, test_get->next);
2146 }
2147
2148 /**
2149  * Called when the PUT request has been transmitted to the DHT service.
2150  * Schedule the GET request for some time in the future.
2151  */
2152 static void
2153 put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2154 {
2155   struct TestPutContext *test_put = cls;
2156   struct TopologyIteratorContext *topo_ctx;
2157
2158   outstanding_puts--;
2159   puts_completed++;
2160
2161   if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0)
2162     fprintf (stderr, "PUT Request failed!\n");
2163
2164   /* Reset the daemon (which peer to insert at) for later put request iterations */
2165   if (replicate_same == GNUNET_NO)
2166     test_put->daemon =
2167         GNUNET_TESTING_daemon_get (pg,
2168                                    GNUNET_CRYPTO_random_u32
2169                                    (GNUNET_CRYPTO_QUALITY_WEAK, num_peers));
2170
2171   GNUNET_SCHEDULER_cancel (test_put->disconnect_task);
2172   test_put->disconnect_task =
2173       GNUNET_SCHEDULER_add_now (&put_disconnect_task, test_put);
2174   if (GNUNET_YES == update_meter (put_meter))
2175   {
2176     GNUNET_assert (outstanding_puts == 0);
2177     GNUNET_SCHEDULER_cancel (die_task);
2178     if ((dhtlog_handle != NULL) && (GNUNET_NO == dhtlog_minimal))
2179     {
2180       topo_ctx = GNUNET_malloc (sizeof (struct TopologyIteratorContext));
2181       topo_ctx->cont = &do_get;
2182       topo_ctx->cls = all_gets;
2183       topo_ctx->timeout = DEFAULT_GET_TIMEOUT;
2184       topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create (num_peers);
2185       die_task =
2186           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_add
2187                                         (GNUNET_TIME_relative_add
2188                                          (DEFAULT_GET_TIMEOUT, all_get_timeout),
2189                                          DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
2190                                         &end_badly,
2191                                         "from do gets (put finished)");
2192       GNUNET_SCHEDULER_add_now (&capture_current_topology, topo_ctx);
2193     }
2194     else
2195     {
2196       fprintf (stderr, "Scheduling die task (put finished)\n");
2197       die_task =
2198           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_add
2199                                         (DEFAULT_GET_TIMEOUT, all_get_timeout),
2200                                         &end_badly,
2201                                         "from do gets (put finished)");
2202       GNUNET_SCHEDULER_add_delayed (DEFAULT_GET_TIMEOUT, &do_get, all_gets);
2203     }
2204     return;
2205   }
2206 }
2207
2208 /**
2209  * Set up some data, and call API PUT function
2210  */
2211 static void
2212 do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2213 {
2214   struct TestPutContext *test_put = cls;
2215   char data[test_data_size];    /* Made up data to store */
2216   uint32_t rand;
2217   int i;
2218
2219   if (test_put == NULL)
2220     return;                     /* End of list */
2221
2222   if (GNUNET_YES != GNUNET_TESTING_daemon_running (test_put->daemon))   /* If the peer has been churned off, don't try issuing request from it! */
2223   {
2224     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2225                 "Peer we should issue put request at is down, skipping.\n");
2226     update_meter (put_meter);
2227     GNUNET_SCHEDULER_add_now (&do_put, test_put->next);
2228     return;
2229   }
2230
2231   for (i = 0; i < sizeof (data); i++)
2232   {
2233     memset (&data[i],
2234             GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX),
2235             1);
2236   }
2237
2238   if (outstanding_puts > max_outstanding_puts)
2239   {
2240     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2241                                   (GNUNET_TIME_UNIT_MILLISECONDS, 200), &do_put,
2242                                   test_put);
2243     return;
2244   }
2245
2246 #if VERBOSE > 1
2247   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting put for uid %u from peer %s\n",
2248               test_put->uid, test_put->daemon->shortname);
2249 #endif
2250   test_put->dht_handle = GNUNET_DHT_connect (test_put->daemon->cfg, 10);
2251
2252   GNUNET_assert (test_put->dht_handle != NULL);
2253   outstanding_puts++;
2254   GNUNET_DHT_put (test_put->dht_handle, &known_keys[test_put->uid],
2255                   put_replication, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_TEST,
2256                   sizeof (data), data, GNUNET_TIME_UNIT_FOREVER_ABS, put_delay,
2257                   &put_finished, test_put);
2258   test_put->disconnect_task =
2259       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
2260                                     &put_disconnect_task, test_put);
2261   rand = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
2262   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2263                                 (GNUNET_TIME_UNIT_SECONDS, rand), &do_put,
2264                                 test_put->next);
2265 }
2266
2267 static void
2268 schedule_find_peer_requests (void *cls,
2269                              const struct GNUNET_SCHEDULER_TaskContext *tc);
2270
2271 #if HAVE_MALICIOUS
2272 static void
2273 setup_malicious_peers (void *cls,
2274                        const struct GNUNET_SCHEDULER_TaskContext *tc);
2275 #endif
2276
2277 /**
2278  * Given a number of total peers and a bucket size, estimate the number of
2279  * connections in a perfect kademlia topology.
2280  */
2281 static unsigned int
2282 connection_estimate (unsigned int peer_count, unsigned int bucket_size)
2283 {
2284   unsigned int i;
2285   unsigned int filled;
2286
2287   i = num_peers;
2288
2289   filled = 0;
2290   while (i >= bucket_size)
2291   {
2292     filled++;
2293     i = i / 2;
2294   }
2295   filled++;                     /* Add one filled bucket to account for one "half full" and some miscellaneous */
2296   return filled * bucket_size * peer_count;
2297
2298 }
2299
2300 /**
2301  * Callback for iterating over all the peer connections of a peer group.
2302  */
2303 static void
2304 count_peers_cb (void *cls, const struct GNUNET_PeerIdentity *first,
2305                 const struct GNUNET_PeerIdentity *second, const char *emsg)
2306 {
2307   struct FindPeerContext *find_peer_context = cls;
2308
2309   if ((first != NULL) && (second != NULL))
2310   {
2311     add_new_connection (find_peer_context, first, second);
2312     find_peer_context->current_peers++;
2313   }
2314   else
2315   {
2316     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2317                 "Peer count finished (%u connections), %u new peers, connection estimate %u (target %u)\n",
2318                 find_peer_context->current_peers,
2319                 find_peer_context->current_peers -
2320                 find_peer_context->previous_peers,
2321                 connection_estimate (num_peers, DEFAULT_BUCKET_SIZE),
2322                 target_total_connections);
2323
2324     if ((find_peer_context->last_sent < 8) ||
2325         ((find_peer_context->current_peers <
2326           2 * connection_estimate (num_peers, DEFAULT_BUCKET_SIZE)) &&
2327          (GNUNET_TIME_absolute_get_remaining
2328           (find_peer_context->endtime).rel_value > 0) &&
2329          (find_peer_context->current_peers < target_total_connections)))
2330     {
2331       GNUNET_SCHEDULER_add_now (&schedule_find_peer_requests,
2332                                 find_peer_context);
2333     }
2334     else
2335     {
2336       GNUNET_CONTAINER_multihashmap_iterate (find_peer_context->peer_hash,
2337                                              &remove_peer_count,
2338                                              find_peer_context);
2339       GNUNET_CONTAINER_multihashmap_destroy (find_peer_context->peer_hash);
2340       GNUNET_CONTAINER_heap_destroy (find_peer_context->peer_min_heap);
2341       GNUNET_free (find_peer_context);
2342       fprintf (stderr, "Not sending any more find peer requests.\n");
2343
2344 #if HAVE_MALICIOUS
2345       if (GNUNET_YES == malicious_after_settle)
2346       {
2347         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2348                     "calling setup_malicious_peers\n");
2349         GNUNET_SCHEDULER_add_now (&setup_malicious_peers, NULL);
2350       }
2351 #endif
2352     }
2353   }
2354 }
2355
2356 /**
2357  * Set up a single find peer request for each peer in the topology.  Do this
2358  * until the settle time is over, limited by the number of outstanding requests
2359  * and the time allowed for each one!
2360  */
2361 static void
2362 schedule_find_peer_requests (void *cls,
2363                              const struct GNUNET_SCHEDULER_TaskContext *tc)
2364 {
2365   struct FindPeerContext *find_peer_ctx = cls;
2366   struct TestFindPeer *test_find_peer;
2367   struct PeerCount *peer_count;
2368   uint32_t i;
2369   uint32_t random;
2370
2371   if (find_peer_ctx->previous_peers == 0)       /* First time, go slowly */
2372     find_peer_ctx->total = 1;
2373   else if (find_peer_ctx->current_peers - find_peer_ctx->previous_peers > MAX_FIND_PEER_CUTOFF) /* Found LOTS of peers, still go slowly */
2374     find_peer_ctx->total =
2375         find_peer_ctx->last_sent - (find_peer_ctx->last_sent / 8);
2376   else
2377     find_peer_ctx->total = find_peer_ctx->last_sent * 2;
2378
2379   if (find_peer_ctx->total > max_outstanding_find_peers)
2380     find_peer_ctx->total = max_outstanding_find_peers;
2381
2382   if (find_peer_ctx->total > num_peers) /* Don't try to send more messages than we have peers! */
2383     find_peer_ctx->total = num_peers;
2384
2385   find_peer_ctx->last_sent = find_peer_ctx->total;
2386   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2387               "Sending %u find peer messages (goal at least %u connections)\n",
2388               find_peer_ctx->total, target_total_connections);
2389
2390   find_peer_offset =
2391       GNUNET_TIME_relative_divide (find_peer_delay, find_peer_ctx->total);
2392   for (i = 0; i < find_peer_ctx->total; i++)
2393   {
2394     test_find_peer = GNUNET_malloc (sizeof (struct TestFindPeer));
2395     /* If we haven't sent any requests yet, choose random peers */
2396     /* Also choose random in _half_ of all cases, so we don't
2397      * get stuck choosing topologically restricted peers with
2398      * few connections that will never be able to find any new
2399      * peers! */
2400     if ((find_peer_ctx->previous_peers == 0) || (i % 2 == 0))
2401     {
2402           /**
2403            * Attempt to spread find peer requests across even sections of the peer address
2404            * space.  Choose basically 1 peer in every num_peers / max_outstanding_requests
2405            * each time, then offset it by a randomish value.
2406            *
2407            * For instance, if num_peers is 100 and max_outstanding is 10, first chosen peer
2408            * will be between 0 - 10, second between 10 - 20, etc.
2409            */
2410       random = (num_peers / find_peer_ctx->total) * i;
2411       random =
2412           random + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2413                                              (num_peers /
2414                                               find_peer_ctx->total));
2415       if (random >= num_peers)
2416       {
2417         random = random - num_peers;
2418       }
2419 #if REAL_RANDOM
2420       random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2421 #endif
2422       test_find_peer->daemon = GNUNET_TESTING_daemon_get (pg, random);
2423     }
2424     else                        /* If we have sent requests, choose peers with a low number of connections to send requests from */
2425     {
2426       peer_count =
2427           GNUNET_CONTAINER_heap_remove_root (find_peer_ctx->peer_min_heap);
2428       GNUNET_assert (GNUNET_YES ==
2429                      GNUNET_CONTAINER_multihashmap_remove
2430                      (find_peer_ctx->peer_hash, &peer_count->peer_id.hashPubKey,
2431                       peer_count));
2432       test_find_peer->daemon =
2433           GNUNET_TESTING_daemon_get_by_id (pg, &peer_count->peer_id);
2434       GNUNET_assert (test_find_peer->daemon != NULL);
2435     }
2436
2437     test_find_peer->find_peer_context = find_peer_ctx;
2438     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2439                                   (find_peer_offset, i),
2440                                   &send_find_peer_request, test_find_peer);
2441   }
2442
2443   if ((find_peer_ctx->peer_hash == NULL) &&
2444       (find_peer_ctx->peer_min_heap == NULL))
2445   {
2446     find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create (num_peers);
2447     find_peer_ctx->peer_min_heap =
2448         GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2449   }
2450   else
2451   {
2452     GNUNET_CONTAINER_multihashmap_iterate (find_peer_ctx->peer_hash,
2453                                            &remove_peer_count, find_peer_ctx);
2454     GNUNET_CONTAINER_multihashmap_destroy (find_peer_ctx->peer_hash);
2455     find_peer_ctx->peer_hash = GNUNET_CONTAINER_multihashmap_create (num_peers);
2456   }
2457
2458   GNUNET_assert (0 ==
2459                  GNUNET_CONTAINER_multihashmap_size (find_peer_ctx->peer_hash));
2460   GNUNET_assert (0 ==
2461                  GNUNET_CONTAINER_heap_get_size (find_peer_ctx->peer_min_heap));
2462
2463 }
2464
2465 /**
2466  * Convert unique ID to hash code.
2467  *
2468  * @param uid unique ID to convert
2469  * @param hash set to uid (extended with zeros)
2470  */
2471 static void
2472 hash_from_uid (uint32_t uid, GNUNET_HashCode * hash)
2473 {
2474   memset (hash, 0, sizeof (GNUNET_HashCode));
2475   *((uint32_t *) hash) = uid;
2476 }
2477
2478 /**
2479  * Set up all of the put and get operations we want to do
2480  * in the current round.  Allocate data structure for each,
2481  * add to list, then schedule the actual PUT operations.
2482  */
2483 static void
2484 setup_puts_and_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2485 {
2486   int i;
2487   struct TestPutContext *test_put;
2488   struct TestGetContext *test_get;
2489   uint32_t temp_peer;
2490   GNUNET_HashCode uid_hash;
2491   int count;
2492
2493 #if REMEMBER
2494   int remember[num_puts][num_peers];
2495
2496   memset (&remember, 0, sizeof (int) * num_puts * num_peers);
2497 #endif
2498   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "in setup_puts_and_gets\n");
2499   known_keys = GNUNET_malloc (sizeof (GNUNET_HashCode) * num_puts);
2500   for (i = 0; i < num_puts; i++)
2501   {
2502     test_put = GNUNET_malloc (sizeof (struct TestPutContext));
2503     test_put->uid = i;
2504     GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
2505                                       &known_keys[i]);
2506     /* Set first X bits to match the chosen sybil location if we want to do the sybil attack! */
2507     if (GNUNET_YES == malicious_sybil)
2508     {
2509       memcpy (&known_keys[i], &sybil_target, sizeof (GNUNET_HashCode) / 2);
2510       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2511                   "Distance between sybil location and key is %d\n",
2512                   GNUNET_CRYPTO_hash_matching_bits (&known_keys[i],
2513                                                     &sybil_target));
2514     }
2515     temp_peer =
2516         GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2517     test_put->daemon = GNUNET_TESTING_daemon_get (pg, temp_peer);
2518     /* Don't start PUTs at malicious peers! */
2519     if (malicious_bloom != NULL)
2520     {
2521       count = 0;
2522       hash_from_uid (temp_peer, &uid_hash);
2523       while ((GNUNET_YES ==
2524               GNUNET_CONTAINER_bloomfilter_test (malicious_bloom, &uid_hash)) &&
2525              (count < num_peers))
2526       {
2527         temp_peer =
2528             GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2529         hash_from_uid (temp_peer, &uid_hash);
2530         test_put->daemon = GNUNET_TESTING_daemon_get (pg, temp_peer);
2531         count++;
2532       }
2533       if (count == num_peers)
2534         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2535                     "Couldn't find peer not in malicious bloom to select!\n");
2536     }
2537
2538     test_put->next = all_puts;
2539     all_puts = test_put;
2540   }
2541
2542   for (i = 0; i < num_gets; i++)
2543   {
2544     test_get = GNUNET_malloc (sizeof (struct TestGetContext));
2545     test_get->uid =
2546         GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_puts);
2547 #if REMEMBER
2548     while (remember[test_get->uid][temp_daemon] == 1)
2549       temp_daemon =
2550           GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2551     remember[test_get->uid][temp_daemon] = 1;
2552 #endif
2553     temp_peer =
2554         GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2555     test_get->daemon = GNUNET_TESTING_daemon_get (pg, temp_peer);
2556     /* Don't start GETs at malicious peers! */
2557     if (malicious_bloom != NULL)
2558     {
2559       hash_from_uid (temp_peer, &uid_hash);
2560       count = 0;
2561       while ((GNUNET_YES ==
2562               GNUNET_CONTAINER_bloomfilter_test (malicious_bloom, &uid_hash)) &&
2563              (count < num_peers))
2564       {
2565         temp_peer =
2566             GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2567         hash_from_uid (temp_peer, &uid_hash);
2568         test_get->daemon = GNUNET_TESTING_daemon_get (pg, temp_peer);
2569         count++;
2570       }
2571       if (count == num_peers)
2572         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2573                     "Couldn't find peer not in malicious bloom to select!\n");
2574     }
2575     test_get->next = all_gets;
2576     all_gets = test_get;
2577   }
2578
2579   /*GNUNET_SCHEDULER_cancel (die_task); */
2580   die_task =
2581       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2582                                     (GNUNET_TIME_UNIT_SECONDS, num_puts * 2),
2583                                     &end_badly, "from do puts");
2584   GNUNET_SCHEDULER_add_now (&do_put, all_puts);
2585
2586 }
2587
2588 /**
2589  * Set up some all of the put and get operations we want
2590  * to do.  Allocate data structure for each, add to list,
2591  * then call actual insert functions.
2592  */
2593 static void
2594 continue_puts_and_gets (void *cls,
2595                         const struct GNUNET_SCHEDULER_TaskContext *tc)
2596 {
2597   int i;
2598   int max;
2599   struct TopologyIteratorContext *topo_ctx;
2600   struct FindPeerContext *find_peer_context;
2601
2602   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "In continue_puts_and_gets\n");
2603   if ((dhtlog_handle != NULL) && (GNUNET_NO == dhtlog_minimal))
2604   {
2605     if (settle_time >= 180 * 2)
2606       max = (settle_time / 180) - 2;
2607     else
2608       max = 1;
2609     for (i = 1; i < max; i++)
2610     {
2611       topo_ctx = GNUNET_malloc (sizeof (struct TopologyIteratorContext));
2612       topo_ctx->current_iteration = i;
2613       topo_ctx->total_iterations = max;
2614       topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create (num_peers);
2615       //fprintf(stderr, "scheduled topology iteration in %d minutes\n", i);
2616       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2617                                     (GNUNET_TIME_UNIT_MINUTES, i * 3),
2618                                     &capture_current_topology, topo_ctx);
2619     }
2620     topo_ctx = GNUNET_malloc (sizeof (struct TopologyIteratorContext));
2621     topo_ctx->cont = &setup_puts_and_gets;
2622     topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create (num_peers);
2623     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2624                 "setting setup_puts_and_gets for %d seconds in the future\n",
2625                 settle_time + 10);
2626     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2627                                   (GNUNET_TIME_UNIT_SECONDS,
2628                                    (settle_time + 10)),
2629                                   &capture_current_topology, topo_ctx);
2630   }
2631   else
2632     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2633                                   (GNUNET_TIME_UNIT_SECONDS,
2634                                    (settle_time + 10)), &setup_puts_and_gets,
2635                                   NULL);
2636
2637   if (dhtlog_handle != NULL)
2638     dhtlog_handle->insert_round (DHT_ROUND_NORMAL, rounds_finished);
2639
2640 #if HAVE_MALICIOUS
2641   if ((GNUNET_YES != malicious_after_settle) || (settle_time == 0))
2642   {
2643     GNUNET_SCHEDULER_add_now (&setup_malicious_peers, NULL);
2644   }
2645 #endif
2646
2647   if ((GNUNET_YES == do_find_peer) && (settle_time > 0))
2648   {
2649     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2650                 "Scheduling find peer requests during \"settle\" time.\n");
2651     find_peer_context = GNUNET_malloc (sizeof (struct FindPeerContext));
2652     find_peer_context->count_peers_cb = &count_peers_cb;
2653     find_peer_context->endtime =
2654         GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply
2655                                           (GNUNET_TIME_UNIT_SECONDS,
2656                                            settle_time));
2657     GNUNET_SCHEDULER_add_now (&schedule_find_peer_requests, find_peer_context);
2658   }
2659   else
2660   {
2661     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2662                 "Assuming automatic DHT find peer requests.\n");
2663   }
2664 }
2665
2666 /**
2667  * Task to release DHT handles
2668  */
2669 static void
2670 malicious_disconnect_task (void *cls,
2671                            const struct GNUNET_SCHEDULER_TaskContext *tc)
2672 {
2673   struct MaliciousContext *ctx = cls;
2674
2675   outstanding_malicious--;
2676   malicious_completed++;
2677   ctx->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
2678   GNUNET_DHT_disconnect (ctx->dht_handle);
2679   ctx->dht_handle = NULL;
2680   GNUNET_free (ctx);
2681
2682   if (malicious_completed ==
2683       malicious_getters + malicious_putters + malicious_droppers)
2684   {
2685     fprintf (stderr, "Finished setting all malicious peers up!\n");
2686   }
2687 }
2688
2689 #if HAVE_MALICIOUS
2690 /**
2691  * Task to release DHT handles
2692  */
2693 static void
2694 malicious_done_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2695 {
2696   struct MaliciousContext *ctx = cls;
2697
2698   GNUNET_SCHEDULER_cancel (ctx->disconnect_task);
2699   GNUNET_SCHEDULER_add_now (&malicious_disconnect_task, ctx);
2700 }
2701
2702 /**
2703  * Set up some data, and call API PUT function
2704  */
2705 static void
2706 set_malicious (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2707 {
2708   struct MaliciousContext *ctx = cls;
2709
2710   if (outstanding_malicious > DEFAULT_MAX_OUTSTANDING_GETS)
2711   {
2712     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2713                                   (GNUNET_TIME_UNIT_MILLISECONDS, 100),
2714                                   &set_malicious, ctx);
2715     return;
2716   }
2717
2718   if (ctx->dht_handle == NULL)
2719   {
2720     ctx->dht_handle = GNUNET_DHT_connect (ctx->daemon->cfg, 1);
2721     outstanding_malicious++;
2722   }
2723
2724   GNUNET_assert (ctx->dht_handle != NULL);
2725
2726 #if VERBOSE > 1
2727   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting peer %s malicious type %d\n",
2728               ctx->daemon->shortname, ctx->malicious_type);
2729 #endif
2730
2731   switch (ctx->malicious_type)
2732   {
2733   case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_GET:
2734     GNUNET_DHT_set_malicious_getter (ctx->dht_handle, malicious_get_frequency,
2735                                      &malicious_done_task, ctx);
2736     break;
2737   case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_PUT:
2738     GNUNET_DHT_set_malicious_putter (ctx->dht_handle, malicious_put_frequency,
2739                                      &malicious_done_task, ctx);
2740     break;
2741   case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_DROP:
2742     GNUNET_DHT_set_malicious_dropper (ctx->dht_handle, &malicious_done_task,
2743                                       ctx);
2744     break;
2745   default:
2746     break;
2747   }
2748
2749   ctx->disconnect_task =
2750       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2751                                     &malicious_disconnect_task, ctx);
2752 }
2753
2754 /**
2755  * Choose the next peer from the peer group to set as malicious.
2756  * If we are doing a sybil attack, find the nearest peer to the
2757  * sybil location that has not already been set malicious.  Otherwise
2758  * just choose a random not already chosen peer.
2759  *
2760  * @param pg the peer group
2761  * @param bloom the bloomfilter which contains all peer already
2762  *        chosen to be malicious
2763  */
2764 static uint32_t
2765 choose_next_malicious (struct GNUNET_TESTING_PeerGroup *pg,
2766                        struct GNUNET_CONTAINER_BloomFilter *bloom)
2767 {
2768   int i;
2769   int nearest;
2770   int bits_match;
2771   int curr_distance;
2772   int count;
2773   struct GNUNET_TESTING_Daemon *temp_daemon;
2774   GNUNET_HashCode uid_hash;
2775
2776   curr_distance = 0;
2777   nearest = 0;
2778   GNUNET_assert (bloom != NULL);
2779
2780   if (GNUNET_YES == malicious_sybil)
2781   {
2782     for (i = 0; i < num_peers; i++)
2783     {
2784       temp_daemon = GNUNET_TESTING_daemon_get (pg, i);
2785       hash_from_uid (i, &uid_hash);
2786       /* Check if this peer matches the bloomfilter */
2787       if ((GNUNET_NO == GNUNET_TESTING_daemon_running (temp_daemon)) ||
2788           (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bloom, &uid_hash)))
2789         continue;
2790
2791       bits_match =
2792           GNUNET_CRYPTO_hash_matching_bits (&temp_daemon->id.hashPubKey,
2793                                             &sybil_target);
2794       if (bits_match >= curr_distance)
2795       {
2796         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2797                     "Found nearer peer %s to %s, old matching bits %d, new %d\n",
2798                     GNUNET_i2s (&temp_daemon->id), GNUNET_h2s (&sybil_target),
2799                     curr_distance, bits_match);
2800         nearest = i;
2801         curr_distance = bits_match;
2802       }
2803     }
2804   }
2805   else
2806   {
2807     nearest = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2808     hash_from_uid (nearest, &uid_hash);
2809     count = 0;
2810     while ((GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (bloom, &uid_hash))
2811            && (count < num_peers))
2812     {
2813       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2814                   "Peer %d already in bloom (tried %d times)\n", nearest,
2815                   count);
2816       nearest =
2817           GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
2818       hash_from_uid (nearest, &uid_hash);
2819       count++;
2820     }
2821     if (count == num_peers)
2822       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2823                   "Tried %d times to find a peer, selecting %d at random!!\n",
2824                   count, nearest);
2825   }
2826
2827   return nearest;
2828 }
2829
2830 /**
2831  * Select randomly from set of known peers,
2832  * set the desired number of peers to the
2833  * proper malicious types.
2834  */
2835 static void
2836 setup_malicious_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2837 {
2838   struct MaliciousContext *ctx;
2839   int i;
2840   uint32_t temp_daemon;
2841   GNUNET_HashCode uid_hash;
2842
2843   for (i = 0; i < malicious_getters; i++)
2844   {
2845     ctx = GNUNET_malloc (sizeof (struct MaliciousContext));
2846     temp_daemon = choose_next_malicious (pg, malicious_bloom);
2847     ctx->daemon = GNUNET_TESTING_daemon_get (pg, temp_daemon);
2848     hash_from_uid (temp_daemon, &uid_hash);
2849     GNUNET_CONTAINER_bloomfilter_add (malicious_bloom, &uid_hash);
2850     ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_GET;
2851     GNUNET_SCHEDULER_add_now (&set_malicious, ctx);
2852
2853   }
2854
2855   for (i = 0; i < malicious_putters; i++)
2856   {
2857     ctx = GNUNET_malloc (sizeof (struct MaliciousContext));
2858     temp_daemon = choose_next_malicious (pg, malicious_bloom);
2859     ctx->daemon = GNUNET_TESTING_daemon_get (pg, temp_daemon);
2860     hash_from_uid (temp_daemon, &uid_hash);
2861     GNUNET_CONTAINER_bloomfilter_add (malicious_bloom, &uid_hash);
2862     ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_PUT;
2863     GNUNET_SCHEDULER_add_now (&set_malicious, ctx);
2864
2865   }
2866
2867   for (i = 0; i < malicious_droppers; i++)
2868   {
2869     ctx = GNUNET_malloc (sizeof (struct MaliciousContext));
2870     temp_daemon = choose_next_malicious (pg, malicious_bloom);
2871     ctx->daemon = GNUNET_TESTING_daemon_get (pg, temp_daemon);
2872     hash_from_uid (temp_daemon, &uid_hash);
2873     GNUNET_CONTAINER_bloomfilter_add (malicious_bloom, &uid_hash);
2874     ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_DROP;
2875     GNUNET_SCHEDULER_add_now (&set_malicious, ctx);
2876   }
2877 }
2878 #endif
2879
2880 #if ONLY_TESTING
2881 /* Forward declaration */
2882 static void
2883 topology_callback (void *cls, const struct GNUNET_PeerIdentity *first,
2884                    const struct GNUNET_PeerIdentity *second, uint32_t distance,
2885                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
2886                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
2887                    struct GNUNET_TESTING_Daemon *first_daemon,
2888                    struct GNUNET_TESTING_Daemon *second_daemon,
2889                    const char *emsg);
2890
2891 /**
2892  * Retry connecting two specific peers until they connect,
2893  * at a specific interval.  These two peers previously failed
2894  * to connect, and we hope they continue to so that we can
2895  * debug the reason they are having issues.
2896  */
2897 static void
2898 repeat_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2899 {
2900
2901   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2902               "Repeating connect attempt between %s and %s.\n",
2903               repeat_connect_peer1->shortname, repeat_connect_peer2->shortname);
2904   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peer 1 configuration `%s'\n",
2905               repeat_connect_peer1->cfgfile);
2906   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peer 2 configuration `%s'\n",
2907               repeat_connect_peer2->cfgfile);
2908
2909   repeat_connect_task = GNUNET_SCHEDULER_NO_TASK;
2910   GNUNET_TESTING_daemons_connect (repeat_connect_peer1, repeat_connect_peer2,
2911                                   GNUNET_TIME_relative_multiply
2912                                   (GNUNET_TIME_UNIT_SECONDS, 60), 2,
2913                                   &topology_callback, NULL);
2914 }
2915 #endif
2916
2917 /**
2918  * This function is called whenever a connection attempt is finished between two of
2919  * the started peers (started with GNUNET_TESTING_daemons_start).  The total
2920  * number of times this function is called should equal the number returned
2921  * from the GNUNET_TESTING_connect_topology call.
2922  *
2923  * The emsg variable is NULL on success (peers connected), and non-NULL on
2924  * failure (peers failed to connect).
2925  */
2926 static void
2927 topology_callback (void *cls, const struct GNUNET_PeerIdentity *first,
2928                    const struct GNUNET_PeerIdentity *second, uint32_t distance,
2929                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
2930                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
2931                    struct GNUNET_TESTING_Daemon *first_daemon,
2932                    struct GNUNET_TESTING_Daemon *second_daemon,
2933                    const char *emsg)
2934 {
2935   struct TopologyIteratorContext *topo_ctx;
2936   uint64_t duration;
2937   uint64_t total_duration;
2938   uint64_t new_connections;
2939   uint64_t new_failed_connections;
2940   double conns_per_sec_recent;
2941   double conns_per_sec_total;
2942   double failed_conns_per_sec_recent;
2943   double failed_conns_per_sec_total;
2944   char *temp_conn_string;
2945   char *temp_conn_failed_string;
2946   char *revision_str;
2947
2948 #if ONLY_TESTING
2949   if (repeat_connect_mode == GNUNET_YES)
2950   {
2951     if ((first_daemon == repeat_connect_peer1) &&
2952         (second_daemon == repeat_connect_peer2))
2953     {
2954       if (emsg != NULL)         /* Peers failed to connect again! */
2955       {
2956         GNUNET_assert (repeat_connect_task == GNUNET_SCHEDULER_NO_TASK);
2957         repeat_connect_task =
2958             GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2959                                           (GNUNET_TIME_UNIT_SECONDS, 60),
2960                                           &repeat_connect, NULL);
2961         return;
2962       }
2963       else                      /* Repeat peers actually connected! */
2964       {
2965         if (repeat_connect_task != GNUNET_SCHEDULER_NO_TASK)
2966           GNUNET_SCHEDULER_cancel (repeat_connect_task);
2967         repeat_connect_peer1 = NULL;
2968         repeat_connect_peer2 = NULL;
2969         repeat_connect_mode = GNUNET_NO;
2970         GNUNET_TESTING_resume_connections (pg);
2971         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2972                     "Resuming normal connection mode, debug connection was successful!\n");
2973       }
2974     }
2975   }
2976 #endif
2977
2978   if (GNUNET_TIME_absolute_get_difference
2979       (connect_last_time,
2980        GNUNET_TIME_absolute_get ()).rel_value >
2981       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
2982                                      CONN_UPDATE_DURATION).rel_value)
2983   {
2984     /* Get number of new connections */
2985     new_connections = total_connections - previous_connections;
2986
2987     /* Get number of new FAILED connections */
2988     new_failed_connections = failed_connections - previous_failed_connections;
2989
2990     /* Get duration in seconds */
2991     duration =
2992         GNUNET_TIME_absolute_get_difference (connect_last_time,
2993                                              GNUNET_TIME_absolute_get
2994                                              ()).rel_value / 1000;
2995     total_duration =
2996         GNUNET_TIME_absolute_get_difference (connect_start_time,
2997                                              GNUNET_TIME_absolute_get
2998                                              ()).rel_value / 1000;
2999
3000     failed_conns_per_sec_recent =
3001         (double) new_failed_connections / (double) duration;
3002     failed_conns_per_sec_total =
3003         (double) failed_connections / (double) total_duration;
3004     conns_per_sec_recent = (double) new_connections / (double) duration;
3005     conns_per_sec_total = (double) total_connections / (double) total_duration;
3006     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3007                 "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n",
3008                 conns_per_sec_recent, conns_per_sec_total,
3009                 failed_conns_per_sec_recent, failed_conns_per_sec_total);
3010     connect_last_time = GNUNET_TIME_absolute_get ();
3011     previous_connections = total_connections;
3012     previous_failed_connections = failed_connections;
3013     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3014                 "have %llu total_connections, %llu failed\n", total_connections,
3015                 failed_connections);
3016 #if ONLY_TESTING
3017     /* These conditions likely mean we've entered the death spiral of doom */
3018     if ((total_connections > 20000) && (conns_per_sec_recent < 5.0) &&
3019         (conns_per_sec_total > 10.0) && (emsg != NULL) &&
3020         (repeat_connect_mode == GNUNET_NO))
3021     {
3022       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3023                   "Entering repeat connection attempt mode!\n");
3024       repeat_connect_peer1 = first_daemon;
3025       repeat_connect_peer2 = second_daemon;
3026       repeat_connect_mode = GNUNET_YES;
3027       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3028                   "Stopping NEW connections from being scheduled!\n");
3029       GNUNET_TESTING_stop_connections (pg);
3030       repeat_connect_task =
3031           GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3032                                         (GNUNET_TIME_UNIT_SECONDS, 60),
3033                                         &repeat_connect, NULL);
3034     }
3035 #endif
3036   }
3037
3038   if (emsg == NULL)
3039   {
3040     total_connections++;
3041 #if VERBOSE > 1
3042     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3043                 "connected peer %s to peer %s, distance %u\n",
3044                 first_daemon->shortname, second_daemon->shortname, distance);
3045 #endif
3046   }
3047   else
3048   {
3049     failed_connections++;
3050 #if VERBOSE
3051     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3052                 "Failed to connect peer %s to peer %s with error :\n%s\n",
3053                 first_daemon->shortname, second_daemon->shortname, emsg);
3054
3055     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3056                 "Failed to connect peer %s to peer %s with error :\n%s\n",
3057                 first_daemon->shortname, second_daemon->shortname, emsg);
3058 #endif
3059   }
3060
3061 #if ONLY_TESTING
3062   if ((repeat_connect_mode == GNUNET_YES))
3063     return;
3064 #endif
3065
3066   GNUNET_assert (peer_connect_meter != NULL);
3067   if (GNUNET_YES == update_meter (peer_connect_meter))
3068   {
3069 #if VERBOSE
3070     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3071                 "Created %d total connections, which is our target number!  Starting next phase of testing.\n",
3072                 total_connections);
3073 #endif
3074     if (failed_connections > 0)
3075       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3076                   "While connecting, had %u failed connections.\n",
3077                   failed_connections);
3078     if (dhtlog_handle != NULL)
3079     {
3080       dhtlog_handle->update_connections (total_connections);
3081       dhtlog_handle->insert_topology (expected_connections);
3082     }
3083
3084     total_duration =
3085         GNUNET_TIME_absolute_get_difference (connect_start_time,
3086                                              GNUNET_TIME_absolute_get
3087                                              ()).rel_value / 1000;
3088     failed_conns_per_sec_total =
3089         (long double) failed_connections / total_duration;
3090     conns_per_sec_total = (long double) total_connections / total_duration;
3091     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3092                 "Overall connection info --- Total: %u, Total Failed %u/s\n",
3093                 total_connections, failed_connections);
3094     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3095                 "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
3096                 conns_per_sec_total, failed_conns_per_sec_total);
3097
3098     GNUNET_asprintf (&temp_conn_string, "DHT Profiler Connection/s",
3099                      trial_to_run);
3100     GNUNET_asprintf (&temp_conn_failed_string,
3101                      "DHT Profiler Connection/s failed", trial_to_run);
3102     GNUNET_asprintf (&revision_str, "%llu", revision);
3103
3104     if (GNUNET_YES == insert_gauger_data)
3105       GAUGER_ID ("DHT_TESTING", temp_conn_string,
3106                  (long double) conns_per_sec_total, "conns/s", revision_str);
3107     if (GNUNET_YES == insert_gauger_data)
3108       GAUGER_ID ("DHT_TESTING", temp_conn_failed_string,
3109                  (long double) failed_conns_per_sec_total, "failed_conns",
3110                  revision_str);
3111
3112     GNUNET_free (temp_conn_string);
3113     GNUNET_free (temp_conn_failed_string);
3114     GNUNET_asprintf (&temp_conn_string, "DHT Profiler Total Connections",
3115                      trial_to_run);
3116     GNUNET_asprintf (&temp_conn_failed_string,
3117                      "DHT Profiler Total Connections failed", trial_to_run);
3118     if (GNUNET_YES == insert_gauger_data)
3119       GAUGER_ID ("DHT_TESTING", temp_conn_string, (double) total_connections,
3120                  "conns", revision_str);
3121     if (GNUNET_YES == insert_gauger_data)
3122       GAUGER_ID ("DHT_TESTING", temp_conn_failed_string,
3123                  (double) failed_connections, "failed conns", revision_str);
3124     GNUNET_free (temp_conn_string);
3125     GNUNET_free (temp_conn_failed_string);
3126     GNUNET_free (revision_str);
3127
3128     GNUNET_SCHEDULER_cancel (die_task);
3129
3130     if ((GNUNET_YES == dhtlog_minimal) && (NULL != dhtlog_handle))
3131     {
3132       topo_ctx = GNUNET_malloc (sizeof (struct TopologyIteratorContext));
3133       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3134                   "Setting continue gets and puts as topo_cont\n");
3135       topo_ctx->cont = &continue_puts_and_gets;
3136       topo_ctx->peers_seen = GNUNET_CONTAINER_multihashmap_create (num_peers);
3137       GNUNET_SCHEDULER_add_now (&capture_current_topology, topo_ctx);
3138     }
3139     else
3140     {
3141       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3142                   "For some reason, NOT scheduling final topology capture (settle_time %d, dhtlog_handle %s)!\n",
3143                   settle_time, dhtlog_handle);
3144       GNUNET_SCHEDULER_add_now (&continue_puts_and_gets, NULL);
3145     }
3146   }
3147   else if (total_connections + failed_connections == expected_connections)
3148   {
3149     GNUNET_SCHEDULER_cancel (die_task);
3150     die_task =
3151         GNUNET_SCHEDULER_add_now (&end_badly,
3152                                   "from topology_callback (too many failed connections)");
3153   }
3154 }
3155
3156 static void
3157 peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id,
3158                         const struct GNUNET_CONFIGURATION_Handle *cfg,
3159                         struct GNUNET_TESTING_Daemon *d, const char *emsg)
3160 {
3161   char *revision_str;
3162
3163   if (emsg != NULL)
3164   {
3165     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3166                 "Failed to start daemon with error: `%s'\n", emsg);
3167     return;
3168   }
3169   GNUNET_assert (id != NULL);
3170
3171 #if VERBOSE > 1
3172   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
3173               (num_peers - peers_left) + 1, num_peers);
3174 #endif
3175
3176   peers_left--;
3177
3178   if (GNUNET_YES == update_meter (peer_start_meter))
3179   {
3180 #if VERBOSE
3181     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3182                 "All %d daemons started, now connecting peers!\n", num_peers);
3183 #endif
3184     GNUNET_SCHEDULER_cancel (die_task);
3185
3186     GNUNET_asprintf (&revision_str, "%llu", revision);
3187     if (GNUNET_YES == insert_gauger_data)
3188       GAUGER_ID ("DHT_TESTING", "peer_startup_time",
3189                  GNUNET_TIME_absolute_get_duration (peer_start_time).rel_value /
3190                  (double) num_peers, "ms/peer", revision_str);
3191     GNUNET_free (revision_str);
3192
3193     expected_connections = UINT_MAX;
3194     if ((pg != NULL) && (peers_left == 0))
3195     {
3196       connect_start_time = GNUNET_TIME_absolute_get ();
3197       expected_connections =
3198           GNUNET_TESTING_connect_topology (pg, connect_topology,
3199                                            connect_topology_option,
3200                                            connect_topology_option_modifier,
3201                                            connect_timeout, connect_attempts,
3202                                            NULL, NULL);
3203
3204       peer_connect_meter =
3205           create_meter (expected_connections, "Peer connection ", GNUNET_YES);
3206       fprintf (stderr, "Have %d expected connections\n", expected_connections);
3207     }
3208
3209     if (expected_connections == 0)
3210     {
3211       die_task =
3212           GNUNET_SCHEDULER_add_now (&end_badly,
3213                                     "from connect topology (bad return)");
3214     }
3215
3216     die_task =
3217         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3218                                       (GNUNET_TIME_UNIT_SECONDS,
3219                                        DEFAULT_CONNECT_TIMEOUT *
3220                                        expected_connections), &end_badly,
3221                                       "from connect topology (timeout)");
3222
3223     ok = 0;
3224   }
3225 }
3226
3227 static void
3228 create_topology ()
3229 {
3230   unsigned int create_expected_connections;
3231
3232   peers_left = num_peers;       /* Reset counter */
3233   create_expected_connections =
3234       GNUNET_TESTING_create_topology (pg, topology, blacklist_topology,
3235                                       blacklist_transports);
3236   if (create_expected_connections > 0)
3237   {
3238     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3239                 "Topology set up, have %u expected connections, now starting peers!\n",
3240                 create_expected_connections);
3241     GNUNET_TESTING_daemons_continue_startup (pg);
3242     peer_start_time = GNUNET_TIME_absolute_get ();
3243   }
3244   else
3245   {
3246     GNUNET_SCHEDULER_cancel (die_task);
3247     die_task =
3248         GNUNET_SCHEDULER_add_now (&end_badly,
3249                                   "from create topology (bad return)");
3250   }
3251   GNUNET_free_non_null (blacklist_transports);
3252   GNUNET_SCHEDULER_cancel (die_task);
3253   die_task =
3254       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3255                                     (seconds_per_peer_start, num_peers),
3256                                     &end_badly,
3257                                     "from continue startup (timeout)");
3258 }
3259
3260 /**
3261  * Callback indicating that the hostkey was created for a peer.
3262  *
3263  * @param cls NULL
3264  * @param id the peer identity
3265  * @param d the daemon handle (pretty useless at this point, remove?)
3266  * @param emsg non-null on failure
3267  */
3268 static void
3269 hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id,
3270                   struct GNUNET_TESTING_Daemon *d, const char *emsg)
3271 {
3272   char *revision_str;
3273
3274   if (emsg != NULL)
3275   {
3276     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3277                 "Hostkey callback received error: %s\n", emsg);
3278   }
3279
3280 #if VERBOSE > 1
3281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3282               "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left,
3283               num_peers, GNUNET_i2s (id));
3284 #endif
3285
3286   peers_left--;
3287   if (GNUNET_YES == update_meter (hostkey_meter))
3288   {
3289     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3290                 "All %d hostkeys created, now creating topology!\n", num_peers);
3291
3292     GNUNET_asprintf (&revision_str, "%llu", revision);
3293     if (GNUNET_YES == insert_gauger_data)
3294     {
3295       if (GNUNET_YES ==
3296           GNUNET_CONFIGURATION_have_value (config, "TESTING", "HOSTKEYSFILE"))
3297       {
3298         GAUGER_ID ("DHT_TESTING", "HOSTKEY_GENERATION",
3299                    GNUNET_TIME_absolute_get_duration
3300                    (hostkey_start_time).rel_value / (double) num_peers,
3301                    "ms/hostkey", revision_str);
3302       }
3303       else
3304       {
3305         GAUGER_ID ("DHT_TESTING", "HOSTKEY_GENERATION_REAL",
3306                    GNUNET_TIME_absolute_get_duration
3307                    (hostkey_start_time).rel_value / (double) num_peers,
3308                    "ms/hostkey", revision_str);
3309       }
3310     }
3311
3312     GNUNET_free (revision_str);
3313
3314     GNUNET_SCHEDULER_cancel (die_task);
3315     /* Set up task in case topology creation doesn't finish
3316      * within a reasonable amount of time */
3317     die_task =
3318         GNUNET_SCHEDULER_add_delayed (DEFAULT_TOPOLOGY_TIMEOUT, &end_badly,
3319                                       "from create_topology");
3320     GNUNET_SCHEDULER_add_now (&create_topology, NULL);
3321     ok = 0;
3322   }
3323 }
3324
3325 static void
3326 run (void *cls, char *const *args, const char *cfgfile,
3327      const struct GNUNET_CONFIGURATION_Handle *cfg)
3328 {
3329   struct stat frstat;
3330   struct GNUNET_DHTLOG_TrialInfo trial_info;
3331   struct GNUNET_TESTING_Host *hosts;
3332   struct GNUNET_TESTING_Host *temphost;
3333   struct GNUNET_TESTING_Host *tempnext;
3334   char *topology_str;
3335   char *connect_topology_str;
3336   char *blacklist_topology_str;
3337   char *connect_topology_option_str;
3338   char *connect_topology_option_modifier_string;
3339   char *trialmessage;
3340   char *topology_percentage_str;
3341   float topology_percentage;
3342   char *topology_probability_str;
3343   char *hostfile;
3344   float topology_probability;
3345   unsigned long long temp_config_number;
3346   int stop_closest;
3347   int stop_found;
3348   int strict_kademlia;
3349   char *buf;
3350   char *data;
3351   char *churn_data;
3352   char *churn_filename;
3353   int count;
3354   int ret;
3355   int line_number;
3356   int k;
3357
3358   config = cfg;
3359   rounds_finished = 0;
3360   memset (&trial_info, 0, sizeof (struct GNUNET_DHTLOG_TrialInfo));
3361   /* Get path from configuration file */
3362   if (GNUNET_YES !=
3363       GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome",
3364                                              &test_directory))
3365   {
3366     ok = 404;
3367     return;
3368   }
3369
3370   /* Get number of peers to start from configuration */
3371   if (GNUNET_SYSERR ==
3372       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
3373                                              &num_peers))
3374   {
3375     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3376                 "Number of peers must be specified in section %s option %s\n",
3377                 "TESTING", "NUM_PEERS");
3378   }
3379   GNUNET_assert (num_peers > 0 && num_peers < ULONG_MAX);
3380
3381   if (GNUNET_OK ==
3382       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_timeout",
3383                                              &temp_config_number))
3384     connect_timeout =
3385         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3386                                        temp_config_number);
3387   else
3388   {
3389     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
3390                 "testing", "connect_timeout");
3391     return;
3392   }
3393
3394   if (GNUNET_OK !=
3395       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts",
3396                                              &connect_attempts))
3397   {
3398     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
3399                 "testing", "connect_attempts");
3400     return;
3401   }
3402
3403   if (GNUNET_OK !=
3404       GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
3405                                              "max_outstanding_connections",
3406                                              &max_outstanding_connections))
3407   {
3408     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
3409                 "testing", "max_outstanding_connections");
3410     return;
3411   }
3412
3413   if (GNUNET_OK !=
3414       GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
3415                                              "max_concurrent_ssh",
3416                                              &max_concurrent_ssh))
3417   {
3418     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
3419                 "testing", "max_concurrent_ssh");
3420     return;
3421   }
3422
3423   /**
3424    * Get DHT specific testing options.
3425    */
3426   if ((GNUNET_YES ==
3427        GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht_testing",
3428                                              "mysql_logging")) ||
3429       (GNUNET_YES ==
3430        GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht_testing",
3431                                              "mysql_logging_extended")) ||
3432       (GNUNET_YES ==
3433        GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht_testing",
3434                                              "mysql_logging_minimal")))
3435   {
3436     if (GNUNET_YES ==
3437         GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht_testing",
3438                                               "mysql_logging_minimal"))
3439       dhtlog_minimal = GNUNET_YES;
3440
3441     dhtlog_handle = GNUNET_DHTLOG_connect (cfg);
3442     if (dhtlog_handle == NULL)
3443     {
3444       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3445                   "Could not connect to mysql server for logging, will NOT log dht operations!");
3446       ok = 3306;
3447       return;
3448     }
3449   }
3450
3451   stop_closest =
3452       GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "stop_on_closest");
3453   if (stop_closest == GNUNET_SYSERR)
3454     stop_closest = GNUNET_NO;
3455
3456   stop_found = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "stop_found");
3457   if (stop_found == GNUNET_SYSERR)
3458     stop_found = GNUNET_NO;
3459
3460   strict_kademlia =
3461       GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "strict_kademlia");
3462   if (strict_kademlia == GNUNET_SYSERR)
3463     strict_kademlia = GNUNET_NO;
3464
3465   if (GNUNET_OK !=
3466       GNUNET_CONFIGURATION_get_value_string (cfg, "dht_testing", "comment",
3467                                              &trialmessage))
3468     trialmessage = NULL;
3469
3470   churn_data = NULL;
3471   /** Check for a churn file to do churny simulation */
3472   if (GNUNET_OK ==
3473       GNUNET_CONFIGURATION_get_value_string (cfg, "dht_testing", "churn_file",
3474                                              &churn_filename))
3475   {
3476     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Reading churn data from %s\n",
3477                 churn_filename);
3478     if (GNUNET_OK != GNUNET_DISK_file_test (churn_filename))
3479     {
3480       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Error reading churn file!\n");
3481       GNUNET_free_non_null (trialmessage);
3482       GNUNET_free (churn_filename);
3483       return;
3484     }
3485     if ((0 != STAT (churn_filename, &frstat)) || (frstat.st_size == 0))
3486     {
3487       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3488                   "Could not open file specified for churn data, ending test!");
3489       ok = 1119;
3490       GNUNET_free_non_null (trialmessage);
3491       GNUNET_free (churn_filename);
3492       return;
3493     }
3494
3495     churn_data = GNUNET_malloc_large (frstat.st_size);
3496     GNUNET_assert (churn_data != NULL);
3497     if (frstat.st_size !=
3498         GNUNET_DISK_fn_read (churn_filename, churn_data, frstat.st_size))
3499     {
3500       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3501                   "Could not read file %s specified for churn, ending test!",
3502                   churn_filename);
3503       GNUNET_free (churn_filename);
3504       GNUNET_free (churn_data);
3505       GNUNET_free_non_null (trialmessage);
3506       return;
3507     }
3508
3509     GNUNET_free_non_null (churn_filename);
3510
3511     buf = churn_data;
3512     count = 0;
3513     /* Read the first line */
3514     while (count < frstat.st_size)
3515     {
3516       count++;
3517       if (((churn_data[count] == '\n')) && (buf != &churn_data[count]))
3518       {
3519         churn_data[count] = '\0';
3520         if (1 != sscanf (buf, "%u", &churn_rounds))
3521         {
3522           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3523                       "Failed to read number of rounds from churn file, ending test!\n");
3524           ret = 4200;
3525           GNUNET_free_non_null (trialmessage);
3526           GNUNET_free_non_null (churn_data);
3527           return;
3528         }
3529         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3530                     "Read %u rounds from churn file\n", churn_rounds);
3531         buf = &churn_data[count + 1];
3532         churn_array = GNUNET_malloc (sizeof (unsigned int) * churn_rounds);
3533         break;                  /* Done with this part */
3534       }
3535     }
3536
3537     if (GNUNET_OK !=
3538         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3539                                                "churns_per_round",
3540                                                &churns_per_round))
3541     {
3542       churns_per_round = (unsigned long long) churn_rounds;
3543     }
3544
3545     line_number = 0;
3546     while ((count < frstat.st_size) && (line_number < churn_rounds))
3547     {
3548       count++;
3549       if (((churn_data[count] == '\n')) && (buf != &churn_data[count]))
3550       {
3551         churn_data[count] = '\0';
3552
3553         ret = sscanf (buf, "%u", &churn_array[line_number]);
3554         if (1 == ret)
3555         {
3556           GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Read %u peers in round %u\n",
3557                       churn_array[line_number], line_number);
3558           line_number++;
3559         }
3560         else
3561         {
3562           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3563                       "Error reading line `%s' in hostfile\n", buf);
3564           buf = &churn_data[count + 1];
3565           continue;
3566         }
3567         buf = &churn_data[count + 1];
3568       }
3569       else if (churn_data[count] == '\n')       /* Blank line */
3570         buf = &churn_data[count + 1];
3571     }
3572   }
3573   GNUNET_free_non_null (churn_data);
3574
3575   /* Check for a hostfile containing user@host:port triples */
3576   if (GNUNET_OK !=
3577       GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile",
3578                                              &hostfile))
3579     hostfile = NULL;
3580
3581   hosts = NULL;
3582   temphost = NULL;
3583   data = NULL;
3584   if (hostfile != NULL)
3585   {
3586     if (GNUNET_OK != GNUNET_DISK_file_test (hostfile))
3587       GNUNET_DISK_fn_write (hostfile, NULL, 0,
3588                             GNUNET_DISK_PERM_USER_READ |
3589                             GNUNET_DISK_PERM_USER_WRITE);
3590     if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0))
3591     {
3592       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3593                   "Could not open file specified for host list, ending test!");
3594       ok = 1119;
3595       GNUNET_free_non_null (trialmessage);
3596       GNUNET_free (hostfile);
3597       return;
3598     }
3599
3600     data = GNUNET_malloc_large (frstat.st_size);
3601     GNUNET_assert (data != NULL);
3602     if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size))
3603     {
3604       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3605                   "Could not read file %s specified for host list, ending test!",
3606                   hostfile);
3607       GNUNET_free (hostfile);
3608       GNUNET_free (data);
3609       GNUNET_free_non_null (trialmessage);
3610       return;
3611     }
3612
3613     GNUNET_free_non_null (hostfile);
3614
3615     buf = data;
3616     count = 0;
3617     while (count < frstat.st_size - 1)
3618     {
3619       count++;
3620       if (((data[count] == '\n')) && (buf != &data[count]))
3621       {
3622         data[count] = '\0';
3623         temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host));
3624         ret =
3625             sscanf (buf, "%a[a-zA-Z0-9_]@%a[a-zA-Z0-9.]:%hd",
3626                     &temphost->username, &temphost->hostname, &temphost->port);
3627         if (3 == ret)
3628         {
3629           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3630                       "Successfully read host %s, port %d and user %s from file\n",
3631                       temphost->hostname, temphost->port, temphost->username);
3632         }
3633         else
3634         {
3635           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3636                       "Error reading line `%s' in hostfile\n", buf);
3637           GNUNET_free (temphost);
3638           buf = &data[count + 1];
3639           continue;
3640         }
3641         temphost->next = hosts;
3642         hosts = temphost;
3643         buf = &data[count + 1];
3644       }
3645       else if ((data[count] == '\n') || (data[count] == '\0'))
3646         buf = &data[count + 1];
3647     }
3648   }
3649   GNUNET_free_non_null (data);
3650   if (GNUNET_OK !=
3651       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3652                                              "malicious_getters",
3653                                              &malicious_getters))
3654     malicious_getters = 0;
3655
3656   if (GNUNET_OK !=
3657       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3658                                              "malicious_putters",
3659                                              &malicious_putters))
3660     malicious_putters = 0;
3661
3662   if (GNUNET_OK !=
3663       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3664                                              "malicious_droppers",
3665                                              &malicious_droppers))
3666     malicious_droppers = 0;
3667
3668   if (GNUNET_OK !=
3669       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "settle_time",
3670                                              &settle_time))
3671     settle_time = 0;
3672
3673   if (GNUNET_SYSERR ==
3674       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_puts",
3675                                              &num_puts))
3676     num_puts = num_peers;
3677
3678   if (GNUNET_SYSERR ==
3679       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3680                                              "put_replication",
3681                                              &put_replication))
3682     put_replication = DEFAULT_PUT_REPLICATION;
3683
3684   if (GNUNET_SYSERR ==
3685       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_gets",
3686                                              &num_gets))
3687     num_gets = num_peers;
3688
3689   if (GNUNET_SYSERR ==
3690       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3691                                              "get_replication",
3692                                              &get_replication))
3693     get_replication = DEFAULT_GET_REPLICATION;
3694
3695   if (GNUNET_OK ==
3696       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3697                                              "find_peer_delay",
3698                                              &temp_config_number))
3699     find_peer_delay =
3700         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3701                                        temp_config_number);
3702   else
3703     find_peer_delay = DEFAULT_FIND_PEER_DELAY;
3704
3705   if (GNUNET_OK ==
3706       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3707                                              "concurrent_find_peers",
3708                                              &temp_config_number))
3709     max_outstanding_find_peers = temp_config_number;
3710   else
3711     max_outstanding_find_peers = DEFAULT_MAX_OUTSTANDING_FIND_PEERS;
3712
3713   if (GNUNET_OK ==
3714       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_timeout",
3715                                              &temp_config_number))
3716     get_timeout =
3717         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3718                                        temp_config_number);
3719   else
3720     get_timeout = DEFAULT_GET_TIMEOUT;
3721
3722   if (GNUNET_OK ==
3723       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3724                                              "concurrent_puts",
3725                                              &temp_config_number))
3726     max_outstanding_puts = temp_config_number;
3727   else
3728     max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS;
3729
3730   if (GNUNET_OK ==
3731       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3732                                              "concurrent_gets",
3733                                              &temp_config_number))
3734     max_outstanding_gets = temp_config_number;
3735   else
3736     max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS;
3737
3738   if (GNUNET_OK ==
3739       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "timeout",
3740                                              &temp_config_number))
3741     all_get_timeout =
3742         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3743                                        temp_config_number);
3744   else
3745     all_get_timeout.rel_value = get_timeout.rel_value * num_gets;
3746
3747   if (GNUNET_OK ==
3748       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_delay",
3749                                              &temp_config_number))
3750     get_delay =
3751         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3752                                        temp_config_number);
3753   else
3754     get_delay = DEFAULT_GET_DELAY;
3755
3756   if (GNUNET_OK ==
3757       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "put_delay",
3758                                              &temp_config_number))
3759     put_delay =
3760         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3761                                        temp_config_number);
3762   else
3763     put_delay = DEFAULT_PUT_DELAY;
3764
3765   if (GNUNET_OK ==
3766       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3767                                              "peer_start_timeout",
3768                                              &temp_config_number))
3769     seconds_per_peer_start =
3770         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3771                                        temp_config_number);
3772   else
3773     seconds_per_peer_start = DEFAULT_SECONDS_PER_PEER_START;
3774
3775   if (GNUNET_OK ==
3776       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "data_size",
3777                                              &temp_config_number))
3778     test_data_size = temp_config_number;
3779   else
3780     test_data_size = DEFAULT_TEST_DATA_SIZE;
3781
3782   /**
3783    * Get DHT testing related options.
3784    */
3785   if (GNUNET_YES ==
3786       GNUNET_CONFIGURATION_get_value_yesno (cfg, "DHT_TESTING",
3787                                             "REPLICATE_SAME"))
3788     replicate_same = GNUNET_YES;
3789
3790   if (GNUNET_SYSERR ==
3791       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3792                                              "target_completions",
3793                                              &target_completions))
3794     target_completions = 0;     /* Not required, on stack */
3795
3796   if (GNUNET_YES ==
3797       GNUNET_CONFIGURATION_get_value_yesno (cfg, "DHT_TESTING",
3798                                             "GET_FROM_SAME"))
3799     get_from_same = GNUNET_YES;
3800
3801   if (GNUNET_NO ==
3802       GNUNET_CONFIGURATION_get_value_time (cfg, "DHT_TESTING",
3803                                            "MALICIOUS_GET_FREQUENCY",
3804                                            &malicious_get_frequency))
3805     malicious_get_frequency = DEFAULT_MALICIOUS_GET_FREQUENCY;
3806
3807   if (GNUNET_NO ==
3808       GNUNET_CONFIGURATION_get_value_time (cfg, "DHT_TESTING",
3809                                            "MALICIOUS_PUT_FREQUENCY",
3810                                            &malicious_put_frequency))
3811     malicious_put_frequency = DEFAULT_MALICIOUS_PUT_FREQUENCY;
3812
3813   if (GNUNET_YES ==
3814       GNUNET_CONFIGURATION_get_value_yesno (cfg, "DHT_TESTING",
3815                                             "MALICIOUS_AFTER_SETTLE"))
3816     malicious_after_settle = GNUNET_YES;
3817
3818   if (GNUNET_YES ==
3819       GNUNET_CONFIGURATION_get_value_yesno (cfg, "DHT_TESTING",
3820                                             "MALICIOUS_SYBIL"))
3821   {
3822     /* Set up the malicious target at random for this round */
3823     GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
3824                                       &sybil_target);
3825     malicious_sybil = GNUNET_YES;
3826   }
3827
3828   /* Create the bloomfilter for choosing which peers to set malicious */
3829
3830   /* Bloomfilter size must be 2^k for some integer k */
3831   k = 1;
3832   while (1 << k < malicious_droppers)
3833     k++;
3834   if (malicious_droppers > 0)
3835     malicious_bloom =
3836         GNUNET_CONTAINER_bloomfilter_init (NULL, 1 << k, DHT_BLOOM_K);
3837
3838   /* The normal behavior of the DHT is to do find peer requests
3839    * on its own.  Only if this is explicitly turned off should
3840    * the testing driver issue find peer requests (even though
3841    * this is likely the default when testing).
3842    */
3843   if (GNUNET_NO ==
3844       GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "do_find_peer"))
3845     do_find_peer = GNUNET_YES;
3846
3847   if (GNUNET_YES ==
3848       GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht_testing",
3849                                             "insert_gauger_data"))
3850     insert_gauger_data = GNUNET_YES;
3851
3852   if (GNUNET_YES ==
3853       GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "republish"))
3854     in_dht_replication = GNUNET_YES;
3855
3856   if (GNUNET_YES !=
3857       GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING", "TRIAL_TO_RUN",
3858                                              &trial_to_run))
3859     trial_to_run = 0;
3860
3861   if (GNUNET_YES !=
3862       GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING", "REVISION",
3863                                              &revision))
3864     revision = 0;
3865
3866   if (GNUNET_YES ==
3867       GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
3868                                              "FIND_PEER_DELAY",
3869                                              &temp_config_number))
3870     find_peer_delay =
3871         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
3872                                        temp_config_number);
3873   else
3874     find_peer_delay = DEFAULT_FIND_PEER_DELAY;
3875
3876   if (GNUNET_YES !=
3877       GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING", "ROUND_DELAY",
3878                                              &round_delay))
3879     round_delay = 0;
3880
3881   if (GNUNET_NO ==
3882       GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
3883                                              "OUTSTANDING_FIND_PEERS",
3884                                              &max_outstanding_find_peers))
3885     max_outstanding_find_peers = DEFAULT_MAX_OUTSTANDING_FIND_PEERS;
3886
3887   if (GNUNET_YES ==
3888       GNUNET_CONFIGURATION_get_value_yesno (cfg, "dht", "strict_kademlia"))
3889     max_outstanding_find_peers = max_outstanding_find_peers * 1;
3890
3891   find_peer_offset =
3892       GNUNET_TIME_relative_divide (find_peer_delay, max_outstanding_find_peers);
3893
3894   if (GNUNET_SYSERR ==
3895       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_rounds",
3896                                              &total_rounds))
3897     total_rounds = 1;
3898
3899   if ((GNUNET_SYSERR ==
3900        GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing",
3901                                               "target_total_connections",
3902                                               &target_total_connections)) ||
3903       (target_total_connections == 0))
3904     target_total_connections =
3905         connection_estimate (num_peers, DEFAULT_BUCKET_SIZE);
3906
3907   topology_str = NULL;
3908   if ((GNUNET_YES ==
3909        GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology",
3910                                               &topology_str)) &&
3911       (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str)))
3912   {
3913     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3914                 "Invalid topology `%s' given for section %s option %s\n",
3915                 topology_str, "TESTING", "TOPOLOGY");
3916     topology = GNUNET_TESTING_TOPOLOGY_CLIQUE;  /* Defaults to NONE, so set better default here */
3917   }
3918
3919   if (GNUNET_OK !=
3920       GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
3921                                              &topology_percentage_str))
3922     topology_percentage = 0.5;
3923   else
3924   {
3925     topology_percentage = atof (topology_percentage_str);
3926     GNUNET_free (topology_percentage_str);
3927   }
3928
3929   if (GNUNET_OK !=
3930       GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
3931                                              &topology_probability_str))
3932     topology_probability = 0.5;
3933   else
3934   {
3935     topology_probability = atof (topology_probability_str);
3936     GNUNET_free (topology_probability_str);
3937   }
3938
3939   if ((GNUNET_YES ==
3940        GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
3941                                               "connect_topology",
3942                                               &connect_topology_str)) &&
3943       (GNUNET_NO ==
3944        GNUNET_TESTING_topology_get (&connect_topology, connect_topology_str)))
3945   {
3946     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3947                 "Invalid connect topology `%s' given for section %s option %s\n",
3948                 connect_topology_str, "TESTING", "CONNECT_TOPOLOGY");
3949   }
3950   GNUNET_free_non_null (connect_topology_str);
3951
3952   if ((GNUNET_YES ==
3953        GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
3954                                               "connect_topology_option",
3955                                               &connect_topology_option_str)) &&
3956       (GNUNET_NO ==
3957        GNUNET_TESTING_topology_option_get (&connect_topology_option,
3958                                            connect_topology_option_str)))
3959   {
3960     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3961                 "Invalid connect topology option `%s' given for section %s option %s\n",
3962                 connect_topology_option_str, "TESTING",
3963                 "CONNECT_TOPOLOGY_OPTION");
3964     connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL;       /* Defaults to NONE, set to ALL */
3965   }
3966   GNUNET_free_non_null (connect_topology_option_str);
3967
3968   if (GNUNET_YES ==
3969       GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
3970                                              "connect_topology_option_modifier",
3971                                              &connect_topology_option_modifier_string))
3972   {
3973     if (sscanf
3974         (connect_topology_option_modifier_string, "%lf",
3975          &connect_topology_option_modifier) != 1)
3976     {
3977       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3978                   _
3979                   ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
3980                   connect_topology_option_modifier_string,
3981                   "connect_topology_option_modifier", "TESTING");
3982     }
3983     GNUNET_free (connect_topology_option_modifier_string);
3984   }
3985
3986   if (GNUNET_YES !=
3987       GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
3988                                              "blacklist_transports",
3989                                              &blacklist_transports))
3990     blacklist_transports = NULL;
3991
3992   if ((GNUNET_YES ==
3993        GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
3994                                               "blacklist_topology",
3995                                               &blacklist_topology_str)) &&
3996       (GNUNET_NO ==
3997        GNUNET_TESTING_topology_get (&blacklist_topology,
3998                                     blacklist_topology_str)))
3999   {
4000     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4001                 "Invalid topology `%s' given for section %s option %s\n",
4002                 topology_str, "TESTING", "BLACKLIST_TOPOLOGY");
4003   }
4004   GNUNET_free_non_null (topology_str);
4005   GNUNET_free_non_null (blacklist_topology_str);
4006
4007   /* Set peers_left so we know when all peers started */
4008   peers_left = num_peers;
4009
4010   /* Set up a task to end testing if peer start fails */
4011   die_task =
4012       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4013                                     (seconds_per_peer_start, num_peers),
4014                                     &end_badly,
4015                                     "didn't generate all hostkeys within allowed startup time!");
4016
4017   if (dhtlog_handle == NULL)
4018     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "dhtlog_handle is NULL!");
4019
4020   trial_info.other_identifier = (unsigned int) trial_to_run;
4021   trial_info.num_nodes = peers_left;
4022   trial_info.topology = topology;
4023   trial_info.blacklist_topology = blacklist_topology;
4024   trial_info.connect_topology = connect_topology;
4025   trial_info.connect_topology_option = connect_topology_option;
4026   trial_info.connect_topology_option_modifier =
4027       connect_topology_option_modifier;
4028   trial_info.topology_percentage = topology_percentage;
4029   trial_info.topology_probability = topology_probability;
4030   trial_info.puts = num_puts;
4031   trial_info.gets = num_gets;
4032   trial_info.concurrent = max_outstanding_gets;
4033   trial_info.settle_time = settle_time;
4034   trial_info.num_rounds = total_rounds;
4035   trial_info.malicious_getters = malicious_getters;
4036   trial_info.malicious_putters = malicious_putters;
4037   trial_info.malicious_droppers = malicious_droppers;
4038   trial_info.malicious_get_frequency = malicious_get_frequency.rel_value;
4039   trial_info.malicious_put_frequency = malicious_put_frequency.rel_value;
4040   trial_info.stop_closest = stop_closest;
4041   trial_info.stop_found = stop_found;
4042   trial_info.strict_kademlia = strict_kademlia;
4043
4044   if (trialmessage != NULL)
4045     trial_info.message = trialmessage;
4046   else
4047     trial_info.message = "";
4048
4049   if (dhtlog_handle != NULL)
4050     dhtlog_handle->insert_trial (&trial_info);
4051
4052   GNUNET_free_non_null (trialmessage);
4053
4054   hostkey_meter = create_meter (peers_left, "Hostkeys created ", GNUNET_YES);
4055   peer_start_meter = create_meter (peers_left, "Peers started ", GNUNET_YES);
4056
4057   put_meter = create_meter (num_puts, "Puts completed ", GNUNET_YES);
4058   get_meter = create_meter (num_gets, "Gets completed ", GNUNET_YES);
4059   hostkey_start_time = GNUNET_TIME_absolute_get ();
4060   pg = GNUNET_TESTING_daemons_start (cfg, peers_left,
4061                                      max_outstanding_connections,
4062                                      max_concurrent_ssh,
4063                                      GNUNET_TIME_relative_multiply
4064                                      (seconds_per_peer_start, num_peers),
4065                                      &hostkey_callback, NULL,
4066                                      &peers_started_callback, NULL,
4067                                      &topology_callback, NULL, hosts);
4068   temphost = hosts;
4069   while (temphost != NULL)
4070   {
4071     tempnext = temphost->next;
4072     GNUNET_free (temphost->username);
4073     GNUNET_free (temphost->hostname);
4074     GNUNET_free (temphost);
4075     temphost = tempnext;
4076   }
4077 }
4078
4079 int
4080 main (int argc, char *argv[])
4081 {
4082   int ret;
4083
4084   struct GNUNET_GETOPT_CommandLineOption options[] = {
4085     GNUNET_GETOPT_OPTION_END
4086   };
4087
4088   ret =
4089       GNUNET_PROGRAM_run (argc, argv, "gnunet-dht-driver", "nohelp", options,
4090                           &run, &ok);
4091
4092   if (malicious_bloom != NULL)
4093     GNUNET_CONTAINER_bloomfilter_free (malicious_bloom);
4094
4095   if (ret != GNUNET_OK)
4096   {
4097     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4098                 "`gnunet-dht-driver': Failed with error code %d\n", ret);
4099   }
4100
4101   /**
4102    * Need to remove base directory, subdirectories taken care
4103    * of by the testing framework.
4104    */
4105   if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
4106   {
4107     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4108                 "Failed to remove testing directory %s\n", test_directory);
4109   }
4110   return ret;
4111 }
4112
4113 /* end of gnunet-dht-driver.c */