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