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