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