nitpicks
[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  *
27  * FIXME: Do churn, enable malicious peers!
28  */
29 #include "platform.h"
30 #include "gnunet_testing_lib.h"
31 #include "gnunet_core_service.h"
32 #include "gnunet_dht_service.h"
33 #include "dhtlog.h"
34 #include "dht.h"
35
36 /* DEFINES */
37 #define VERBOSE GNUNET_NO
38
39 /* Timeout for entire driver to run */
40 #define DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
41
42 /* Timeout for waiting for (individual) replies to get requests */
43 #define DEFAULT_GET_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
44
45 #define DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
46
47 /* Timeout for waiting for gets to be sent to the service */
48 #define DEFAULT_GET_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
49
50 /* Timeout for waiting for puts to be sent to the service */
51 #define DEFAULT_PUT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 10)
52
53 /* Timeout for waiting for puts to be sent to the service */
54 #define DEFAULT_FIND_PEER_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40)
55
56 #define DEFAULT_SECONDS_PER_PEER_START GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 45)
57
58 #define DEFAULT_TEST_DATA_SIZE 8
59
60 #define DEFAULT_BUCKET_SIZE 4
61
62 #define FIND_PEER_THRESHOLD DEFAULT_BUCKET_SIZE * 2
63
64 #define DEFAULT_MAX_OUTSTANDING_PUTS 10
65
66 #define DEFAULT_MAX_OUTSTANDING_FIND_PEERS 10
67
68 #define DEFAULT_FIND_PEER_OFFSET GNUNET_TIME_relative_divide (DEFAULT_SECONDS_PER_PEER_START, DEFAULT_MAX_OUTSTANDING_FIND_PEERS)
69
70 #define DEFAULT_MAX_OUTSTANDING_GETS 10
71
72 #define DEFAULT_CONNECT_TIMEOUT 60
73
74 #define DEFAULT_TOPOLOGY_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 8)
75
76 /*
77  * Default frequency for sending malicious get messages
78  */
79 #define DEFAULT_MALICIOUS_GET_FREQUENCY 1000 /* Number of milliseconds */
80
81 /*
82  * Default frequency for sending malicious put messages
83  */
84 #define DEFAULT_MALICIOUS_PUT_FREQUENCY 1000 /* Default is in milliseconds */
85
86 /* Structs */
87
88 struct MaliciousContext
89 {
90   /**
91    * Handle to DHT service (via the API)
92    */
93   struct GNUNET_DHT_Handle *dht_handle;
94
95   /**
96    *  Handle to the peer daemon
97    */
98   struct GNUNET_TESTING_Daemon *daemon;
99
100   /**
101    * Task for disconnecting DHT handles
102    */
103   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
104
105   /**
106    * What type of malicious to set this peer to.
107    */
108   int malicious_type;
109 };
110
111 struct TestFindPeer
112 {
113   /* This is a linked list */
114   struct TestFindPeer *next;
115
116   /* Handle to the bigger context */
117   struct FindPeerContext *find_peer_context;
118
119   /**
120    * Handle to the peer's DHT service (via the API)
121    */
122   struct GNUNET_DHT_Handle *dht_handle;
123
124   /**
125    *  Handle to the peer daemon
126    */
127   struct GNUNET_TESTING_Daemon *daemon;
128
129   /**
130    * Task for disconnecting DHT handles
131    */
132   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
133 };
134
135 struct TestPutContext
136 {
137   /* This is a linked list */
138   struct TestPutContext *next;
139
140   /**
141    * Handle to the first peers DHT service (via the API)
142    */
143   struct GNUNET_DHT_Handle *dht_handle;
144
145   /**
146    *  Handle to the PUT peer daemon
147    */
148   struct GNUNET_TESTING_Daemon *daemon;
149
150   /**
151    *  Identifier for this PUT
152    */
153   uint32_t uid;
154
155   /**
156    * Task for disconnecting DHT handles
157    */
158   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
159 };
160
161 struct TestGetContext
162 {
163   /* This is a linked list */
164   struct TestGetContext *next;
165
166   /**
167    * Handle to the first peers DHT service (via the API)
168    */
169   struct GNUNET_DHT_Handle *dht_handle;
170
171   /**
172    * Handle for the DHT get request
173    */
174   struct GNUNET_DHT_GetHandle *get_handle;
175
176   /**
177    *  Handle to the GET peer daemon
178    */
179   struct GNUNET_TESTING_Daemon *daemon;
180
181   /**
182    *  Identifier for this GET
183    */
184   uint32_t uid;
185
186   /**
187    * Task for disconnecting DHT handles (and stopping GET)
188    */
189   GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
190
191   /**
192    * Whether or not this request has been fulfilled already.
193    */
194   int succeeded;
195 };
196
197 /**
198  * Simple struct to keep track of progress, and print a
199  * nice little percentage meter for long running tasks.
200  */
201 struct ProgressMeter
202 {
203   unsigned int total;
204
205   unsigned int modnum;
206
207   unsigned int dotnum;
208
209   unsigned int completed;
210
211   int print;
212
213   char *startup_string;
214 };
215
216 /**
217  * Linked list of information for populating statistics
218  * before ending trial.
219  */
220 struct StatisticsIteratorContext
221 {
222   const struct GNUNET_PeerIdentity *peer;
223   unsigned int stat_routes;
224   unsigned int stat_route_forwards;
225   unsigned int stat_results;
226   unsigned int stat_results_to_client;
227   unsigned int stat_result_forwards;
228   unsigned int stat_gets;
229   unsigned int stat_puts;
230   unsigned int stat_puts_inserted;
231   unsigned int stat_find_peer;
232   unsigned int stat_find_peer_start;
233   unsigned int stat_get_start;
234   unsigned int stat_put_start;
235   unsigned int stat_find_peer_reply;
236   unsigned int stat_get_reply;
237   unsigned int stat_find_peer_answer;
238   unsigned int stat_get_response_start;
239 };
240
241 /**
242  * Context for getting a topology, logging it, and continuing
243  * on with some next operation.
244  */
245 struct TopologyIteratorContext
246 {
247   unsigned int total_connections;
248   struct GNUNET_PeerIdentity *peer;
249   GNUNET_SCHEDULER_Task cont;
250   void *cls;
251   struct GNUNET_TIME_Relative timeout;
252 };
253
254 /* Globals */
255
256 /**
257  * Timeout to let all get requests happen.
258  */
259 static struct GNUNET_TIME_Relative all_get_timeout;
260
261 /**
262  * Per get timeout
263  */
264 static struct GNUNET_TIME_Relative get_timeout;
265
266 static struct GNUNET_TIME_Relative get_delay;
267
268 static struct GNUNET_TIME_Relative put_delay;
269
270 static struct GNUNET_TIME_Relative find_peer_delay;
271
272 static struct GNUNET_TIME_Relative seconds_per_peer_start;
273
274 static int do_find_peer;
275
276 static unsigned long long test_data_size = DEFAULT_TEST_DATA_SIZE;
277
278 static unsigned long long max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS;
279
280 static unsigned long long max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS;
281
282 static unsigned long long malicious_getters;
283
284 static unsigned long long max_outstanding_find_peers;
285
286 static unsigned long long malicious_putters;
287
288 static unsigned long long malicious_droppers;
289
290 static unsigned long long malicious_get_frequency;
291
292 static unsigned long long malicious_put_frequency;
293
294 static unsigned long long settle_time;
295
296 static struct GNUNET_DHTLOG_Handle *dhtlog_handle;
297
298 static unsigned long long trialuid;
299
300 /**
301  * Hash map of stats contexts.
302  */
303 struct GNUNET_CONTAINER_MultiHashMap *stats_map;
304
305 /**
306  * LL of malicious settings.
307  */
308 struct MaliciousContext *all_malicious;
309
310 /**
311  * List of GETS to perform
312  */
313 struct TestGetContext *all_gets;
314
315 /**
316  * List of PUTS to perform
317  */
318 struct TestPutContext *all_puts;
319
320 /**
321  * Directory to store temporary data in, defined in config file
322  */
323 static char *test_directory;
324
325 /**
326  * Variable used to store the number of connections we should wait for.
327  */
328 static unsigned int expected_connections;
329
330 /**
331  * Variable used to keep track of how many peers aren't yet started.
332  */
333 static unsigned long long peers_left;
334
335 /**
336  * Handle to the set of all peers run for this test.
337  */
338 static struct GNUNET_TESTING_PeerGroup *pg;
339
340 /**
341  * Global scheduler, used for all GNUNET_SCHEDULER_* functions.
342  */
343 static struct GNUNET_SCHEDULER_Handle *sched;
344
345 /**
346  * Global config handle.
347  */
348 const struct GNUNET_CONFIGURATION_Handle *config;
349
350 /**
351  * Total number of peers to run, set based on config file.
352  */
353 static unsigned long long num_peers;
354
355 /**
356  * Total number of items to insert.
357  */
358 static unsigned long long num_puts;
359
360 /**
361  * How many puts do we currently have in flight?
362  */
363 static unsigned long long outstanding_puts;
364
365 /**
366  * How many puts are done?
367  */
368 static unsigned long long puts_completed;
369
370 /**
371  * Total number of items to attempt to get.
372  */
373 static unsigned long long num_gets;
374
375 /**
376  * How many puts do we currently have in flight?
377  */
378 static unsigned long long outstanding_gets;
379
380 /**
381  * How many gets are done?
382  */
383 static unsigned long long gets_completed;
384
385 /**
386  * How many gets failed?
387  */
388 static unsigned long long gets_failed;
389
390 /**
391  * How many malicious control messages do
392  * we currently have in flight?
393  */
394 static unsigned long long outstanding_malicious;
395
396 /**
397  * How many set malicious peers are done?
398  */
399 static unsigned long long malicious_completed;
400
401 /**
402  * Global used to count how many connections we have currently
403  * been notified about (how many times has topology_callback been called
404  * with success?)
405  */
406 static unsigned int total_connections;
407
408 /**
409  * Global used to count how many failed connections we have
410  * been notified about (how many times has topology_callback
411  * been called with failure?)
412  */
413 static unsigned int failed_connections;
414
415 /* Task handle to use to schedule shutdown if something goes wrong */
416 GNUNET_SCHEDULER_TaskIdentifier die_task;
417
418 static char *blacklist_transports;
419
420 static enum GNUNET_TESTING_Topology topology;
421
422 static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */
423
424 static enum GNUNET_TESTING_Topology connect_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */
425
426 static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL;
427
428 static double connect_topology_option_modifier = 0.0;
429
430 static struct ProgressMeter *hostkey_meter;
431
432 static struct ProgressMeter *peer_start_meter;
433
434 static struct ProgressMeter *peer_connect_meter;
435
436 static struct ProgressMeter *put_meter;
437
438 static struct ProgressMeter *get_meter;
439
440 /* Global return value (0 for success, anything else for failure) */
441 static int ok;
442
443 /**
444  * Create a meter to keep track of the progress of some task.
445  *
446  * @param total the total number of items to complete
447  * @param start_string a string to prefix the meter with (if printing)
448  * @param print GNUNET_YES to print the meter, GNUNET_NO to count
449  *              internally only
450  *
451  * @return the progress meter
452  */
453 static struct ProgressMeter *
454 create_meter(unsigned int total, char * start_string, int print)
455 {
456   struct ProgressMeter *ret;
457   ret = GNUNET_malloc(sizeof(struct ProgressMeter));
458   ret->print = print;
459   ret->total = total;
460   ret->modnum = total / 4;
461   ret->dotnum = (total / 50) + 1;
462   if (start_string != NULL)
463     ret->startup_string = GNUNET_strdup(start_string);
464   else
465     ret->startup_string = GNUNET_strdup("");
466
467   return ret;
468 }
469
470 /**
471  * Update progress meter (increment by one).
472  *
473  * @param meter the meter to update and print info for
474  *
475  * @return GNUNET_YES if called the total requested,
476  *         GNUNET_NO if more items expected
477  */
478 static int
479 update_meter(struct ProgressMeter *meter)
480 {
481   if (meter->print == GNUNET_YES)
482     {
483       if (meter->completed % meter->modnum == 0)
484         {
485           if (meter->completed == 0)
486             {
487               fprintf(stdout, "%sProgress: [0%%", meter->startup_string);
488             }
489           else
490             fprintf(stdout, "%d%%", (int)(((float)meter->completed / meter->total) * 100));
491         }
492       else if (meter->completed % meter->dotnum == 0)
493         fprintf(stdout, ".");
494
495       if (meter->completed + 1 == meter->total)
496         fprintf(stdout, "%d%%]\n", 100);
497       fflush(stdout);
498     }
499   meter->completed++;
500
501   if (meter->completed == meter->total)
502     return GNUNET_YES;
503   return GNUNET_NO;
504 }
505
506 /**
507  * Release resources for meter
508  *
509  * @param meter the meter to free
510  */
511 static void
512 free_meter(struct ProgressMeter *meter)
513 {
514   GNUNET_free_non_null(meter->startup_string);
515   GNUNET_free_non_null(meter);
516 }
517
518 /**
519  * Check whether peers successfully shut down.
520  */
521 void shutdown_callback (void *cls,
522                         const char *emsg)
523 {
524   if (emsg != NULL)
525     {
526       if (ok == 0)
527         ok = 2;
528     }
529 }
530
531 /**
532  * Task to release DHT handles for PUT
533  */
534 static void
535 put_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
536 {
537   struct TestPutContext *test_put = cls;
538   test_put->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
539   GNUNET_DHT_disconnect(test_put->dht_handle);
540   test_put->dht_handle = NULL;
541 }
542
543 /**
544  * Function scheduled to be run on the successful completion of this
545  * testcase.
546  */
547 static void
548 finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
549 {
550   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending test normally!\n", (char *)cls);
551   GNUNET_assert (pg != NULL);
552   struct TestPutContext *test_put = all_puts;
553   struct TestGetContext *test_get = all_gets;
554
555   while (test_put != NULL)
556     {
557       if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
558         GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task);
559       if (test_put->dht_handle != NULL)
560         GNUNET_DHT_disconnect(test_put->dht_handle);
561       test_put = test_put->next;
562     }
563
564   while (test_get != NULL)
565     {
566       if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
567         GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task);
568       if (test_get->get_handle != NULL)
569         GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL);
570       if (test_get->dht_handle != NULL)
571         GNUNET_DHT_disconnect(test_get->dht_handle);
572       test_get = test_get->next;
573     }
574
575   GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL);
576
577   if (dhtlog_handle != NULL)
578     {
579       fprintf(stderr, "Update trial endtime\n");
580       dhtlog_handle->update_trial (trialuid, gets_completed);
581       GNUNET_DHTLOG_disconnect(dhtlog_handle);
582       dhtlog_handle = NULL;
583     }
584
585   if (hostkey_meter != NULL)
586     free_meter(hostkey_meter);
587   if (peer_start_meter != NULL)
588     free_meter(peer_start_meter);
589   if (peer_connect_meter != NULL)
590     free_meter(peer_connect_meter);
591   if (put_meter != NULL)
592     free_meter(put_meter);
593   if (get_meter != NULL)
594     free_meter(get_meter);
595
596   ok = 0;
597 }
598
599 /**
600  * Callback for iterating over all the peer connections of a peer group.
601  */
602 void log_topology_cb (void *cls,
603                       const struct GNUNET_PeerIdentity *first,
604                       const struct GNUNET_PeerIdentity *second,
605                       struct GNUNET_TIME_Relative latency,
606                       uint32_t distance,
607                       const char *emsg)
608 {
609   struct TopologyIteratorContext *topo_ctx = cls;
610   if ((first != NULL) && (second != NULL))
611     {
612       topo_ctx->total_connections++;
613       if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(config, "dht_testing", "mysql_logging_extended"))
614         dhtlog_handle->insert_extended_topology(first, second);
615     }
616   else
617     {
618       GNUNET_assert(dhtlog_handle != NULL);
619       fprintf(stderr, "topology iteration finished (%u connections), scheduling continuation\n", topo_ctx->total_connections);
620       dhtlog_handle->update_topology(topo_ctx->total_connections);
621       if (topo_ctx->cont != NULL)
622         GNUNET_SCHEDULER_add_now (sched, topo_ctx->cont, topo_ctx->cls);
623       GNUNET_free(topo_ctx);
624     }
625 }
626
627 /**
628  * Iterator over hash map entries.
629  *
630  * @param cls closure - always NULL
631  * @param key current key code
632  * @param value value in the hash map, a stats context
633  * @return GNUNET_YES if we should continue to
634  *         iterate,
635  *         GNUNET_NO if not.
636  */
637 static int stats_iterate (void *cls,
638                           const GNUNET_HashCode * key,
639                           void *value)
640 {
641   struct StatisticsIteratorContext *stats_ctx;
642   if (value == NULL)
643     return GNUNET_NO;
644   stats_ctx = value;
645   dhtlog_handle->insert_stat(stats_ctx->peer, stats_ctx->stat_routes, stats_ctx->stat_route_forwards, stats_ctx->stat_results,
646                              stats_ctx->stat_results_to_client, stats_ctx->stat_result_forwards, stats_ctx->stat_gets,
647                              stats_ctx->stat_puts, stats_ctx->stat_puts_inserted, stats_ctx->stat_find_peer,
648                              stats_ctx->stat_find_peer_start, stats_ctx->stat_get_start, stats_ctx->stat_put_start,
649                              stats_ctx->stat_find_peer_reply, stats_ctx->stat_get_reply, stats_ctx->stat_find_peer_answer,
650                              stats_ctx->stat_get_response_start);
651   GNUNET_free(stats_ctx);
652   return GNUNET_YES;
653 }
654
655 static void stats_finished (void *cls, int result)
656 {
657   fprintf(stderr, "Finished getting all peers statistics, iterating!\n");
658   GNUNET_CONTAINER_multihashmap_iterate(stats_map, &stats_iterate, NULL);
659   GNUNET_CONTAINER_multihashmap_destroy(stats_map);
660   GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
661 }
662
663 /**
664  * Callback function to process statistic values.
665  *
666  * @param cls closure
667  * @param peer the peer the statistics belong to
668  * @param subsystem name of subsystem that created the statistic
669  * @param name the name of the datum
670  * @param value the current value
671  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
672  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
673  */
674 static int stats_handle  (void *cls,
675                           const struct GNUNET_PeerIdentity *peer,
676                           const char *subsystem,
677                           const char *name,
678                           uint64_t value,
679                           int is_persistent)
680 {
681   struct StatisticsIteratorContext *stats_ctx;
682
683   if (dhtlog_handle != NULL)
684     dhtlog_handle->add_generic_stat(peer, name, subsystem, value);
685   if (GNUNET_CONTAINER_multihashmap_contains(stats_map, &peer->hashPubKey))
686     {
687       stats_ctx = GNUNET_CONTAINER_multihashmap_get(stats_map, &peer->hashPubKey);
688     }
689   else
690     {
691       stats_ctx = GNUNET_malloc(sizeof(struct StatisticsIteratorContext));
692       stats_ctx->peer = peer;
693       GNUNET_CONTAINER_multihashmap_put(stats_map, &peer->hashPubKey, stats_ctx, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
694     }
695   GNUNET_assert(stats_ctx != NULL);
696
697   if (strcmp(name, STAT_ROUTES) == 0)
698     stats_ctx->stat_routes = value;
699   else if (strcmp(name, STAT_ROUTE_FORWARDS) == 0)
700     stats_ctx->stat_route_forwards = value;
701   else if (strcmp(name, STAT_RESULTS) == 0)
702     stats_ctx->stat_results = value;
703   else if (strcmp(name, STAT_RESULTS_TO_CLIENT) == 0)
704     stats_ctx->stat_results_to_client = value;
705   else if (strcmp(name, STAT_RESULT_FORWARDS) == 0)
706     stats_ctx->stat_result_forwards = value;
707   else if (strcmp(name, STAT_GETS) == 0)
708     stats_ctx->stat_gets = value;
709   else if (strcmp(name, STAT_PUTS) == 0)
710     stats_ctx->stat_puts = value;
711   else if (strcmp(name, STAT_PUTS_INSERTED) == 0)
712     stats_ctx->stat_puts_inserted = value;
713   else if (strcmp(name, STAT_FIND_PEER) == 0)
714     stats_ctx->stat_find_peer = value;
715   else if (strcmp(name, STAT_FIND_PEER_START) == 0)
716     stats_ctx->stat_find_peer_start = value;
717   else if (strcmp(name, STAT_GET_START) == 0)
718     stats_ctx->stat_get_start = value;
719   else if (strcmp(name, STAT_PUT_START) == 0)
720     stats_ctx->stat_put_start = value;
721   else if (strcmp(name, STAT_FIND_PEER_REPLY) == 0)
722     stats_ctx->stat_find_peer_reply = value;
723   else if (strcmp(name, STAT_GET_REPLY) == 0)
724     stats_ctx->stat_get_reply = value;
725   else if (strcmp(name, STAT_FIND_PEER_ANSWER) == 0)
726     stats_ctx->stat_find_peer_answer = value;
727   else if (strcmp(name, STAT_GET_RESPONSE_START) == 0)
728     stats_ctx->stat_get_response_start = value;
729
730   return GNUNET_OK;
731 }
732
733 /**
734  * Connect to statistics service for each peer and get the appropriate
735  * dht statistics for safe keeping.
736  */
737 static void
738 log_dht_statistics (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
739 {
740   stats_map = GNUNET_CONTAINER_multihashmap_create(num_peers);
741   fprintf(stderr, "Starting statistics logging\n");
742   GNUNET_TESTING_get_statistics(pg, &stats_finished, &stats_handle, NULL);
743 }
744
745
746 /**
747  * Connect to all peers in the peer group and iterate over their
748  * connections.
749  */
750 static void
751 capture_current_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
752 {
753   struct TopologyIteratorContext *topo_ctx = cls;
754   dhtlog_handle->insert_topology(0);
755   GNUNET_TESTING_get_topology (pg, &log_topology_cb, topo_ctx);
756 }
757
758
759 /**
760  * Check if the get_handle is being used, if so stop the request.  Either
761  * way, schedule the end_badly_cont function which actually shuts down the
762  * test.
763  */
764 static void
765 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
766 {
767   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failing test with error: `%s'!\n", (char *)cls);
768
769   struct TestPutContext *test_put = all_puts;
770   struct TestGetContext *test_get = all_gets;
771
772   while (test_put != NULL)
773     {
774       if (test_put->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
775         GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task);
776       if (test_put->dht_handle != NULL)
777         GNUNET_DHT_disconnect(test_put->dht_handle);
778       test_put = test_put->next;
779     }
780
781   while (test_get != NULL)
782     {
783       if (test_get->disconnect_task != GNUNET_SCHEDULER_NO_TASK)
784         GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task);
785       if (test_get->get_handle != NULL)
786         GNUNET_DHT_get_stop(test_get->get_handle, NULL, NULL);
787       if (test_get->dht_handle != NULL)
788         GNUNET_DHT_disconnect(test_get->dht_handle);
789       test_get = test_get->next;
790     }
791
792   GNUNET_TESTING_daemons_stop (pg, DEFAULT_TIMEOUT, &shutdown_callback, NULL);
793
794   if (dhtlog_handle != NULL)
795     {
796       fprintf(stderr, "Update trial endtime\n");
797       dhtlog_handle->update_trial (trialuid, gets_completed);
798       GNUNET_DHTLOG_disconnect(dhtlog_handle);
799       dhtlog_handle = NULL;
800     }
801
802   if (hostkey_meter != NULL)
803     free_meter(hostkey_meter);
804   if (peer_start_meter != NULL)
805     free_meter(peer_start_meter);
806   if (peer_connect_meter != NULL)
807     free_meter(peer_connect_meter);
808   if (put_meter != NULL)
809     free_meter(put_meter);
810   if (get_meter != NULL)
811     free_meter(get_meter);
812
813   ok = 1;
814 }
815
816 /**
817  * Task to release DHT handle associated with GET request.
818  */
819 static void
820 get_stop_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
821 {
822   struct TestGetContext *test_get = cls;
823   struct TopologyIteratorContext *topo_ctx;
824   outstanding_gets--; /* GET is really finished */
825   GNUNET_DHT_disconnect(test_get->dht_handle);
826   test_get->dht_handle = NULL;
827
828 #if VERBOSE > 1
829   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%d gets succeeded, %d gets failed!\n", gets_completed, gets_failed);
830 #endif
831   update_meter(get_meter);
832   if ((gets_completed + gets_failed == num_gets) && (outstanding_gets == 0))
833     {
834       GNUNET_SCHEDULER_cancel(sched, die_task);
835       //GNUNET_SCHEDULER_add_now(sched, &finish_testing, NULL);
836       if (dhtlog_handle != NULL)
837         {
838           topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
839           topo_ctx->cont = &log_dht_statistics;
840           GNUNET_SCHEDULER_add_now(sched, &capture_current_topology, topo_ctx);
841         }
842       else
843         GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
844     }
845 }
846
847 /**
848  * Task to release get handle.
849  */
850 static void
851 get_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
852 {
853   struct TestGetContext *test_get = cls;
854
855   if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT)
856     gets_failed++;
857   GNUNET_assert(test_get->get_handle != NULL);
858   GNUNET_DHT_get_stop(test_get->get_handle, &get_stop_finished, test_get);
859   test_get->get_handle = NULL;
860   test_get->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
861 }
862
863 /**
864  * Iterator called if the GET request initiated returns a response.
865  *
866  * @param cls closure
867  * @param exp when will this value expire
868  * @param key key of the result
869  * @param type type of the result
870  * @param size number of bytes in data
871  * @param data pointer to the result data
872  */
873 void get_result_iterator (void *cls,
874                           struct GNUNET_TIME_Absolute exp,
875                           const GNUNET_HashCode * key,
876                           uint32_t type,
877                           uint32_t size,
878                           const void *data)
879 {
880   struct TestGetContext *test_get = cls;
881   GNUNET_HashCode search_key; /* Key stored under */
882   char original_data[test_data_size]; /* Made up data to store */
883
884   memset(original_data, test_get->uid, sizeof(original_data));
885   GNUNET_CRYPTO_hash(original_data, test_data_size, &search_key);
886
887   if (test_get->succeeded == GNUNET_YES)
888     return; /* Get has already been successful, probably ending now */
889
890   if ((0 != memcmp(&search_key, key, sizeof (GNUNET_HashCode))) || (0 != memcmp(original_data, data, sizeof(original_data))))
891     {
892       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Key or data is not the same as was inserted!\n");
893     }
894   else
895     {
896       gets_completed++;
897       test_get->succeeded = GNUNET_YES;
898     }
899 #if VERBOSE > 1
900   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received correct GET response!\n");
901 #endif
902   GNUNET_SCHEDULER_cancel(sched, test_get->disconnect_task);
903   GNUNET_SCHEDULER_add_continuation(sched, &get_stop_task, test_get, GNUNET_SCHEDULER_REASON_PREREQ_DONE);
904 }
905
906 /**
907  * Continuation telling us GET request was sent.
908  */
909 static void
910 get_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
911 {
912   // Is there something to be done here?
913   if (tc->reason != GNUNET_SCHEDULER_REASON_PREREQ_DONE)
914     return;
915 }
916
917 /**
918  * Set up some data, and call API PUT function
919  */
920 static void
921 do_get (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
922 {
923   struct TestGetContext *test_get = cls;
924   GNUNET_HashCode key; /* Made up key to store data under */
925   char data[test_data_size]; /* Made up data to store */
926
927   if (num_gets == 0)
928     {
929       GNUNET_SCHEDULER_cancel(sched, die_task);
930       GNUNET_SCHEDULER_add_now(sched, &finish_testing, NULL);
931     }
932   if (test_get == NULL)
933     return; /* End of the list */
934
935   memset(data, test_get->uid, sizeof(data));
936   GNUNET_CRYPTO_hash(data, test_data_size, &key);
937
938   if (outstanding_gets > max_outstanding_gets)
939     {
940       GNUNET_SCHEDULER_add_delayed (sched, get_delay, &do_get, test_get);
941       return;
942     }
943
944   test_get->dht_handle = GNUNET_DHT_connect(sched, test_get->daemon->cfg, 10);
945   /* Insert the data at the first peer */
946   GNUNET_assert(test_get->dht_handle != NULL);
947   outstanding_gets++;
948   test_get->get_handle = GNUNET_DHT_get_start(test_get->dht_handle,
949                                               GNUNET_TIME_relative_get_forever(),
950                                               1,
951                                               &key,
952                                               &get_result_iterator,
953                                               test_get,
954                                               &get_continuation,
955                                               test_get);
956 #if VERBOSE > 1
957   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting get for uid %u from peer %s\n",
958              test_get->uid,
959              test_get->daemon->shortname);
960 #endif
961   test_get->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, get_timeout, &get_stop_task, test_get);
962   GNUNET_SCHEDULER_add_now (sched, &do_get, test_get->next);
963 }
964
965 /**
966  * Called when the PUT request has been transmitted to the DHT service.
967  * Schedule the GET request for some time in the future.
968  */
969 static void
970 put_finished (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
971 {
972   struct TestPutContext *test_put = cls;
973   struct TopologyIteratorContext *topo_ctx;
974   outstanding_puts--;
975   puts_completed++;
976
977   if (tc->reason == GNUNET_SCHEDULER_REASON_TIMEOUT)
978     fprintf(stderr, "PUT Request failed!\n");
979
980   GNUNET_SCHEDULER_cancel(sched, test_put->disconnect_task);
981   test_put->disconnect_task = GNUNET_SCHEDULER_add_now(sched, &put_disconnect_task, test_put);
982   if (GNUNET_YES == update_meter(put_meter))
983     {
984       GNUNET_assert(outstanding_puts == 0);
985       GNUNET_SCHEDULER_cancel (sched, die_task);
986       if (dhtlog_handle != NULL)
987         {
988           topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
989           topo_ctx->cont = &do_get;
990           topo_ctx->cls = all_gets;
991           topo_ctx->timeout = DEFAULT_GET_TIMEOUT;
992           die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout), DEFAULT_TOPOLOGY_CAPTURE_TIMEOUT),
993                                                    &end_badly, "from do gets");
994           GNUNET_SCHEDULER_add_now(sched, &capture_current_topology, topo_ctx);
995         }
996       else
997         {
998           die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_add(DEFAULT_GET_TIMEOUT, all_get_timeout),
999                                                        &end_badly, "from do gets");
1000           GNUNET_SCHEDULER_add_delayed(sched, DEFAULT_GET_TIMEOUT, &do_get, all_gets);
1001           GNUNET_SCHEDULER_add_now (sched, &finish_testing, NULL);
1002         }
1003       return;
1004     }
1005 }
1006
1007 /**
1008  * Set up some data, and call API PUT function
1009  */
1010 static void
1011 do_put (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1012 {
1013   struct TestPutContext *test_put = cls;
1014   GNUNET_HashCode key; /* Made up key to store data under */
1015   char data[test_data_size]; /* Made up data to store */
1016   uint32_t rand;
1017
1018   if (test_put == NULL)
1019     return; /* End of list */
1020
1021   memset(data, test_put->uid, sizeof(data));
1022   GNUNET_CRYPTO_hash(data, test_data_size, &key);
1023
1024   if (outstanding_puts > max_outstanding_puts)
1025     {
1026       GNUNET_SCHEDULER_add_delayed (sched, put_delay, &do_put, test_put);
1027       return;
1028     }
1029
1030 #if VERBOSE > 1
1031     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting put for uid %u from peer %s\n",
1032                test_put->uid,
1033                test_put->daemon->shortname);
1034 #endif
1035   test_put->dht_handle = GNUNET_DHT_connect(sched, test_put->daemon->cfg, 10);
1036
1037   GNUNET_assert(test_put->dht_handle != NULL);
1038   outstanding_puts++;
1039   GNUNET_DHT_put(test_put->dht_handle,
1040                  &key,
1041                  1,
1042                  sizeof(data), data,
1043                  GNUNET_TIME_absolute_get_forever(),
1044                  GNUNET_TIME_relative_get_forever(),
1045                  &put_finished, test_put);
1046   test_put->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_get_forever(), &put_disconnect_task, test_put);
1047   rand = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 2);
1048   GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, rand), &do_put, test_put->next);
1049 }
1050
1051 /**
1052  * Context for sending out find peer requests.
1053  */
1054 struct FindPeerContext
1055 {
1056   struct GNUNET_DHT_Handle *dht_handle;
1057   struct GNUNET_TIME_Absolute endtime;
1058   unsigned int current_peers;
1059   unsigned int previous_peers;
1060   unsigned int outstanding;
1061   unsigned int total;
1062 };
1063
1064 static void
1065 schedule_find_peer_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc);
1066
1067 /**
1068  * Given a number of total peers and a bucket size, estimate the number of
1069  * connections in a perfect kademlia topology.
1070  */
1071 static unsigned int connection_estimate(unsigned int peer_count, unsigned int bucket_size)
1072 {
1073   unsigned int i;
1074   unsigned int filled;
1075   i = num_peers;
1076
1077   filled = 0;
1078   while (i > bucket_size)
1079     {
1080       filled++;
1081       i = i/2;
1082     }
1083   return filled * bucket_size * peer_count;
1084
1085 }
1086
1087 /**
1088  * Callback for iterating over all the peer connections of a peer group.
1089  */
1090 void count_peers_cb (void *cls,
1091                       const struct GNUNET_PeerIdentity *first,
1092                       const struct GNUNET_PeerIdentity *second,
1093                       struct GNUNET_TIME_Relative latency,
1094                       uint32_t distance,
1095                       const char *emsg)
1096 {
1097   struct FindPeerContext *find_peer_context = cls;
1098   if ((first != NULL) && (second != NULL))
1099     {
1100       find_peer_context->current_peers++;
1101     }
1102   else
1103     {
1104       GNUNET_assert(dhtlog_handle != NULL);
1105       fprintf(stderr, "peer count finished (%u connections), %u new peers, connection estimate %u\n", find_peer_context->current_peers, find_peer_context->current_peers - find_peer_context->previous_peers, connection_estimate(num_peers, DEFAULT_BUCKET_SIZE));
1106       if ((find_peer_context->current_peers - find_peer_context->previous_peers > FIND_PEER_THRESHOLD) &&
1107           (find_peer_context->current_peers < connection_estimate(num_peers, DEFAULT_BUCKET_SIZE)) &&
1108           (GNUNET_TIME_absolute_get_remaining(find_peer_context->endtime).value > 0))
1109         {
1110           fprintf(stderr, "Scheduling another round of find peer requests.\n");
1111           GNUNET_SCHEDULER_add_now(sched, schedule_find_peer_requests, find_peer_context);
1112         }
1113       else
1114         {
1115           fprintf(stderr, "Not sending any more find peer requests.\n");
1116         }
1117     }
1118 }
1119
1120 /**
1121  * Connect to all peers in the peer group and iterate over their
1122  * connections.
1123  */
1124 static void
1125 count_new_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1126 {
1127   struct FindPeerContext *find_peer_context = cls;
1128   find_peer_context->previous_peers = find_peer_context->current_peers;
1129   find_peer_context->current_peers = 0;
1130   GNUNET_TESTING_get_topology (pg, &count_peers_cb, find_peer_context);
1131 }
1132
1133
1134 static void
1135 decrement_find_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1136 {
1137   struct TestFindPeer *test_find_peer = cls;
1138   GNUNET_assert(test_find_peer->find_peer_context->outstanding > 0);
1139   test_find_peer->find_peer_context->outstanding--;
1140   test_find_peer->find_peer_context->total--;
1141   GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "%d find_peers remaining\n", test_find_peer->find_peer_context->total);
1142   if ((0 == test_find_peer->find_peer_context->total) &&
1143       (GNUNET_TIME_absolute_get_remaining(test_find_peer->find_peer_context->endtime).value > 0))
1144   {
1145     GNUNET_SCHEDULER_add_now(sched, &count_new_peers, test_find_peer->find_peer_context);
1146   }
1147   GNUNET_free(test_find_peer);
1148 }
1149
1150 /**
1151  * A find peer request has been sent to the server, now we will schedule a task
1152  * to wait the appropriate time to allow the request to go out and back.
1153  *
1154  * @param cls closure - a TestFindPeer struct
1155  * @param tc context the task is being called with
1156  */
1157 static void
1158 handle_find_peer_sent (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1159 {
1160   struct TestFindPeer *test_find_peer = cls;
1161
1162   GNUNET_DHT_disconnect(test_find_peer->dht_handle);
1163   GNUNET_SCHEDULER_add_delayed(sched, find_peer_delay, &decrement_find_peers, test_find_peer);
1164 }
1165
1166 static void
1167 send_find_peer_request (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1168 {
1169   struct TestFindPeer *test_find_peer = cls;
1170
1171   if (test_find_peer->find_peer_context->outstanding > max_outstanding_find_peers)
1172   {
1173     GNUNET_SCHEDULER_add_delayed(sched, DEFAULT_FIND_PEER_OFFSET, &send_find_peer_request, test_find_peer);
1174     return;
1175   }
1176
1177   test_find_peer->find_peer_context->outstanding++;
1178   if (GNUNET_TIME_absolute_get_remaining(test_find_peer->find_peer_context->endtime).value == 0)
1179   {
1180     GNUNET_SCHEDULER_add_now(sched, &decrement_find_peers, test_find_peer);
1181     return;
1182   }
1183
1184   test_find_peer->dht_handle = GNUNET_DHT_connect(sched, test_find_peer->daemon->cfg, 1);
1185   GNUNET_assert(test_find_peer->dht_handle != NULL);
1186   fprintf(stderr, "calling GNUNET_DHT_find_peers\n");
1187   GNUNET_DHT_find_peers (test_find_peer->dht_handle,
1188                          &handle_find_peer_sent, test_find_peer);
1189 }
1190
1191 /**
1192  * Set up a single find peer request for each peer in the topology.  Do this
1193  * until the settle time is over, limited by the number of outstanding requests
1194  * and the time allowed for each one!
1195  */
1196 static void
1197 schedule_find_peer_requests (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1198 {
1199   struct FindPeerContext *find_peer_ctx = cls;
1200   struct TestFindPeer *test_find_peer;
1201   uint32_t i;
1202   uint32_t random;
1203
1204   for (i = 0; i < max_outstanding_find_peers; i++)
1205     {
1206       test_find_peer = GNUNET_malloc(sizeof(struct TestFindPeer));
1207       random = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1208       test_find_peer->daemon  = GNUNET_TESTING_daemon_get(pg, random);
1209       test_find_peer->find_peer_context = find_peer_ctx;
1210       find_peer_ctx->total++;
1211       GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(DEFAULT_FIND_PEER_OFFSET, i), &send_find_peer_request, test_find_peer);
1212     }
1213 }
1214
1215 /**
1216  * Set up some all of the put and get operations we want
1217  * to do.  Allocate data structure for each, add to list,
1218  * then call actual insert functions.
1219  */
1220 static void
1221 setup_puts_and_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1222 {
1223   int i;
1224   uint32_t temp_daemon;
1225   struct TestPutContext *test_put;
1226   struct TestGetContext *test_get;
1227   int remember[num_puts][num_peers];
1228
1229   memset(&remember, 0, sizeof(int) * num_puts * num_peers);
1230   for (i = 0; i < num_puts; i++)
1231     {
1232       test_put = GNUNET_malloc(sizeof(struct TestPutContext));
1233       test_put->uid = i;
1234       temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1235       test_put->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
1236       test_put->next = all_puts;
1237       all_puts = test_put;
1238     }
1239
1240   for (i = 0; i < num_gets; i++)
1241     {
1242       test_get = GNUNET_malloc(sizeof(struct TestGetContext));
1243       test_get->uid = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_puts);
1244       temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1245       while (remember[test_get->uid][temp_daemon] == 1)
1246         temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1247       test_get->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
1248       remember[test_get->uid][temp_daemon] = 1;
1249       test_get->next = all_gets;
1250       all_gets = test_get;
1251     }
1252
1253   /*GNUNET_SCHEDULER_cancel (sched, die_task);*/
1254   die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, num_puts * 2),
1255                                            &end_badly, "from do puts");
1256   GNUNET_SCHEDULER_add_now (sched, &do_put, all_puts);
1257 }
1258
1259 /**
1260  * Set up some all of the put and get operations we want
1261  * to do.  Allocate data structure for each, add to list,
1262  * then call actual insert functions.
1263  */
1264 static void
1265 continue_puts_and_gets (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1266 {
1267   int i;
1268   int max;
1269   struct TopologyIteratorContext *topo_ctx;
1270   struct FindPeerContext *find_peer_context;
1271   if (dhtlog_handle != NULL)
1272     {
1273       if (settle_time >= 60 * 2)
1274         max = (settle_time / 60) - 2;
1275       else
1276         max = 1;
1277       for (i = 1; i < max; i++)
1278         {
1279           topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
1280           fprintf(stderr, "scheduled topology iteration in %d minutes\n", i);
1281           GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, i), &capture_current_topology, topo_ctx);
1282         }
1283       topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
1284       topo_ctx->cont = &setup_puts_and_gets;
1285       GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time), &capture_current_topology, topo_ctx);
1286     }
1287   else
1288     GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time), &setup_puts_and_gets, NULL);
1289
1290   if (GNUNET_YES == do_find_peer)
1291   {
1292     find_peer_context = GNUNET_malloc(sizeof(struct FindPeerContext));
1293     find_peer_context->endtime = GNUNET_TIME_relative_to_absolute(GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time));
1294     GNUNET_SCHEDULER_add_now(sched, &schedule_find_peer_requests, find_peer_context);
1295   }
1296 }
1297
1298 /**
1299  * Task to release DHT handles
1300  */
1301 static void
1302 malicious_disconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1303 {
1304   struct MaliciousContext *ctx = cls;
1305   outstanding_malicious--;
1306   malicious_completed++;
1307   ctx->disconnect_task = GNUNET_SCHEDULER_NO_TASK;
1308   GNUNET_DHT_disconnect(ctx->dht_handle);
1309   ctx->dht_handle = NULL;
1310   GNUNET_free(ctx);
1311
1312   if (malicious_completed == malicious_getters + malicious_putters + malicious_droppers)
1313     {
1314       GNUNET_SCHEDULER_cancel(sched, die_task);
1315       fprintf(stderr, "Finished setting all malicious peers up, calling continuation!\n");
1316       if (dhtlog_handle != NULL)
1317         GNUNET_SCHEDULER_add_now (sched,
1318                                   &continue_puts_and_gets, NULL);
1319       else
1320         GNUNET_SCHEDULER_add_delayed (sched,
1321                                     GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time),
1322                                     &continue_puts_and_gets, NULL);
1323     }
1324
1325 }
1326
1327 /**
1328  * Task to release DHT handles
1329  */
1330 static void
1331 malicious_done_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1332 {
1333   struct MaliciousContext *ctx = cls;
1334   GNUNET_SCHEDULER_cancel(sched, ctx->disconnect_task);
1335   GNUNET_SCHEDULER_add_now(sched, &malicious_disconnect_task, ctx);
1336 }
1337
1338 /**
1339  * Set up some data, and call API PUT function
1340  */
1341 static void
1342 set_malicious (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1343 {
1344   struct MaliciousContext *ctx = cls;
1345   int ret;
1346
1347   if (outstanding_malicious > DEFAULT_MAX_OUTSTANDING_GETS)
1348     {
1349       GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &set_malicious, ctx);
1350       return;
1351     }
1352
1353   if (ctx->dht_handle == NULL)
1354     {
1355       ctx->dht_handle = GNUNET_DHT_connect(sched, ctx->daemon->cfg, 1);
1356       outstanding_malicious++;
1357     }
1358
1359   GNUNET_assert(ctx->dht_handle != NULL);
1360
1361
1362 #if VERBOSE > 1
1363     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Setting peer %s malicious type %d\n",
1364                 ctx->daemon->shortname, ctx->malicious_type);
1365 #endif
1366
1367   ret = GNUNET_YES;
1368   switch (ctx->malicious_type)
1369   {
1370   case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_GET:
1371     ret = GNUNET_DHT_set_malicious_getter(ctx->dht_handle, malicious_get_frequency, &malicious_done_task, ctx);
1372     break;
1373   case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_PUT:
1374     ret = GNUNET_DHT_set_malicious_putter(ctx->dht_handle, malicious_put_frequency, &malicious_done_task, ctx);
1375     break;
1376   case GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_DROP:
1377     ret = GNUNET_DHT_set_malicious_dropper(ctx->dht_handle, &malicious_done_task, ctx);
1378     break;
1379   default:
1380     break;
1381   }
1382
1383   if (ret == GNUNET_NO)
1384     {
1385       GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &set_malicious, ctx);
1386     }
1387   else
1388     ctx->disconnect_task = GNUNET_SCHEDULER_add_delayed(sched, GNUNET_TIME_relative_get_forever(), &malicious_disconnect_task, ctx);
1389 }
1390
1391 /**
1392  * Select randomly from set of known peers,
1393  * set the desired number of peers to the
1394  * proper malicious types.
1395  */
1396 static void
1397 setup_malicious_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
1398 {
1399   struct MaliciousContext *ctx;
1400   int i;
1401   uint32_t temp_daemon;
1402
1403   for (i = 0; i < malicious_getters; i++)
1404     {
1405       ctx = GNUNET_malloc(sizeof(struct MaliciousContext));
1406       temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1407       ctx->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
1408       ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_GET;
1409       GNUNET_SCHEDULER_add_now (sched, &set_malicious, ctx);
1410
1411     }
1412
1413   for (i = 0; i < malicious_putters; i++)
1414     {
1415       ctx = GNUNET_malloc(sizeof(struct MaliciousContext));
1416       temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1417       ctx->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
1418       ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_PUT;
1419       GNUNET_SCHEDULER_add_now (sched, &set_malicious, ctx);
1420
1421     }
1422
1423   for (i = 0; i < malicious_droppers; i++)
1424     {
1425       ctx = GNUNET_malloc(sizeof(struct MaliciousContext));
1426       temp_daemon = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, num_peers);
1427       ctx->daemon = GNUNET_TESTING_daemon_get(pg, temp_daemon);
1428       ctx->malicious_type = GNUNET_MESSAGE_TYPE_DHT_MALICIOUS_DROP;
1429       GNUNET_SCHEDULER_add_now (sched, &set_malicious, ctx);
1430     }
1431
1432   if (malicious_getters + malicious_putters + malicious_droppers > 0)
1433     die_task = GNUNET_SCHEDULER_add_delayed (sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, (malicious_getters + malicious_putters + malicious_droppers) * 2),
1434                                              &end_badly, "from set malicious");
1435   else
1436     {
1437       if (dhtlog_handle != NULL)
1438         GNUNET_SCHEDULER_add_now (sched,
1439                                   &continue_puts_and_gets, NULL);
1440       else
1441         GNUNET_SCHEDULER_add_delayed (sched,
1442                                     GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time),
1443                                     &continue_puts_and_gets, NULL);
1444     }
1445
1446 }
1447
1448 /**
1449  * This function is called whenever a connection attempt is finished between two of
1450  * the started peers (started with GNUNET_TESTING_daemons_start).  The total
1451  * number of times this function is called should equal the number returned
1452  * from the GNUNET_TESTING_connect_topology call.
1453  *
1454  * The emsg variable is NULL on success (peers connected), and non-NULL on
1455  * failure (peers failed to connect).
1456  */
1457 void
1458 topology_callback (void *cls,
1459                    const struct GNUNET_PeerIdentity *first,
1460                    const struct GNUNET_PeerIdentity *second,
1461                    uint32_t distance,
1462                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
1463                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
1464                    struct GNUNET_TESTING_Daemon *first_daemon,
1465                    struct GNUNET_TESTING_Daemon *second_daemon,
1466                    const char *emsg)
1467 {
1468   struct TopologyIteratorContext *topo_ctx;
1469   if (emsg == NULL)
1470     {
1471       total_connections++;
1472 #if VERBOSE > 1
1473       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
1474                  first_daemon->shortname,
1475                  second_daemon->shortname,
1476                  distance);
1477 #endif
1478     }
1479 #if VERBOSE
1480   else
1481     {
1482       failed_connections++;
1483       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
1484                   first_daemon->shortname,
1485                   second_daemon->shortname, emsg);
1486     }
1487 #endif
1488   GNUNET_assert(peer_connect_meter != NULL);
1489   if (GNUNET_YES == update_meter(peer_connect_meter))
1490     {
1491 #if VERBOSE
1492       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1493                   "Created %d total connections, which is our target number!  Starting next phase of testing.\n",
1494                   total_connections);
1495 #endif
1496       if (dhtlog_handle != NULL)
1497         {
1498           dhtlog_handle->update_connections (trialuid, total_connections);
1499           dhtlog_handle->insert_topology(expected_connections);
1500         }
1501
1502       GNUNET_SCHEDULER_cancel (sched, die_task);
1503       /*die_task = GNUNET_SCHEDULER_add_delayed (sched, DEFAULT_TIMEOUT,
1504                                                &end_badly, "from setup puts/gets");*/
1505       if ((dhtlog_handle != NULL) && (settle_time > 0))
1506         {
1507           topo_ctx = GNUNET_malloc(sizeof(struct TopologyIteratorContext));
1508           topo_ctx->cont = &setup_malicious_peers;
1509           //topo_ctx->cont = &continue_puts_and_gets;
1510           GNUNET_SCHEDULER_add_now(sched, &capture_current_topology, topo_ctx);
1511         }
1512       else
1513         {
1514           GNUNET_SCHEDULER_add_now(sched, &setup_malicious_peers, NULL);
1515           /*GNUNET_SCHEDULER_add_delayed (sched,
1516                                         GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, settle_time),
1517                                         &continue_puts_and_gets, NULL);*/
1518         }
1519     }
1520   else if (total_connections + failed_connections == expected_connections)
1521     {
1522       GNUNET_SCHEDULER_cancel (sched, die_task);
1523       die_task = GNUNET_SCHEDULER_add_now (sched,
1524                                            &end_badly, "from topology_callback (too many failed connections)");
1525     }
1526 }
1527
1528 static void
1529 peers_started_callback (void *cls,
1530        const struct GNUNET_PeerIdentity *id,
1531        const struct GNUNET_CONFIGURATION_Handle *cfg,
1532        struct GNUNET_TESTING_Daemon *d, const char *emsg)
1533 {
1534   if (emsg != NULL)
1535     {
1536       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start daemon with error: `%s'\n",
1537                   emsg);
1538       return;
1539     }
1540   GNUNET_assert (id != NULL);
1541
1542 #if VERBOSE > 1
1543   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
1544               (num_peers - peers_left) + 1, num_peers);
1545 #endif
1546
1547   peers_left--;
1548
1549   if (GNUNET_YES == update_meter(peer_start_meter))
1550     {
1551 #if VERBOSE
1552       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1553                   "All %d daemons started, now connecting peers!\n",
1554                   num_peers);
1555 #endif
1556       GNUNET_SCHEDULER_cancel (sched, die_task);
1557
1558       expected_connections = -1;
1559       if ((pg != NULL) && (peers_left == 0))
1560         {
1561           expected_connections = GNUNET_TESTING_connect_topology (pg, connect_topology, connect_topology_option, connect_topology_option_modifier);
1562
1563           peer_connect_meter = create_meter(expected_connections, "Peer connection ", GNUNET_YES);
1564           fprintf(stderr, "Have %d expected connections\n", expected_connections);
1565         }
1566
1567       if (expected_connections == GNUNET_SYSERR)
1568         {
1569           die_task = GNUNET_SCHEDULER_add_now (sched,
1570                                                &end_badly, "from connect topology (bad return)");
1571         }
1572
1573       die_task = GNUNET_SCHEDULER_add_delayed (sched,
1574                                                GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, DEFAULT_CONNECT_TIMEOUT * expected_connections),
1575                                                &end_badly, "from connect topology (timeout)");
1576
1577       ok = 0;
1578     }
1579 }
1580
1581 static void
1582 create_topology ()
1583 {
1584   peers_left = num_peers; /* Reset counter */
1585   if (GNUNET_TESTING_create_topology (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR)
1586     {
1587 #if VERBOSE
1588       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1589                   "Topology set up, now starting peers!\n");
1590 #endif
1591       GNUNET_TESTING_daemons_continue_startup(pg);
1592     }
1593   else
1594     {
1595       GNUNET_SCHEDULER_cancel (sched, die_task);
1596       die_task = GNUNET_SCHEDULER_add_now (sched,
1597                                            &end_badly, "from create topology (bad return)");
1598     }
1599   GNUNET_free_non_null(blacklist_transports);
1600   GNUNET_SCHEDULER_cancel (sched, die_task);
1601   die_task = GNUNET_SCHEDULER_add_delayed (sched,
1602                                            GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers),
1603                                            &end_badly, "from continue startup (timeout)");
1604 }
1605
1606 /**
1607  * Callback indicating that the hostkey was created for a peer.
1608  *
1609  * @param cls NULL
1610  * @param id the peer identity
1611  * @param d the daemon handle (pretty useless at this point, remove?)
1612  * @param emsg non-null on failure
1613  */
1614 void hostkey_callback (void *cls,
1615                        const struct GNUNET_PeerIdentity *id,
1616                        struct GNUNET_TESTING_Daemon *d,
1617                        const char *emsg)
1618 {
1619   if (emsg != NULL)
1620     {
1621       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Hostkey callback received error: %s\n", emsg);
1622     }
1623
1624 #if VERBOSE > 1
1625     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1626                 "Hostkey (%d/%d) created for peer `%s'\n",
1627                 num_peers - peers_left, num_peers, GNUNET_i2s(id));
1628 #endif
1629
1630     peers_left--;
1631     if (GNUNET_YES == update_meter(hostkey_meter))
1632       {
1633 #if VERBOSE
1634         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1635                     "All %d hostkeys created, now creating topology!\n",
1636                     num_peers);
1637 #endif
1638         GNUNET_SCHEDULER_cancel (sched, die_task);
1639         /* Set up task in case topology creation doesn't finish
1640          * within a reasonable amount of time */
1641         die_task = GNUNET_SCHEDULER_add_delayed (sched,
1642                                                  DEFAULT_TOPOLOGY_TIMEOUT,
1643                                                  &end_badly, "from create_topology");
1644         GNUNET_SCHEDULER_add_now(sched, &create_topology, NULL);
1645         ok = 0;
1646       }
1647 }
1648
1649
1650 static void
1651 run (void *cls,
1652      struct GNUNET_SCHEDULER_Handle *s,
1653      char *const *args,
1654      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
1655 {
1656   struct stat frstat;
1657   struct GNUNET_TESTING_Host *hosts;
1658   struct GNUNET_TESTING_Host *temphost;
1659   char *topology_str;
1660   char *connect_topology_str;
1661   char *blacklist_topology_str;
1662   char *connect_topology_option_str;
1663   char *connect_topology_option_modifier_string;
1664   char *trialmessage;
1665   char *topology_percentage_str;
1666   float topology_percentage;
1667   char *topology_probability_str;
1668   char *hostfile;
1669   float topology_probability;
1670   unsigned long long temp_config_number;
1671   int stop_closest;
1672   int stop_found;
1673   int strict_kademlia;
1674   char *buf;
1675   char *data;
1676   int count;
1677
1678   sched = s;
1679   config = cfg;
1680   /* Get path from configuration file */
1681   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string(cfg, "paths", "servicehome", &test_directory))
1682     {
1683       ok = 404;
1684       return;
1685     }
1686
1687   /**
1688    * Get DHT specific testing options.
1689    */
1690   if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging")) ||
1691       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht_testing", "mysql_logging_extended")))
1692     {
1693       dhtlog_handle = GNUNET_DHTLOG_connect(cfg);
1694       if (dhtlog_handle == NULL)
1695         {
1696           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1697                       "Could not connect to mysql server for logging, will NOT log dht operations!");
1698           ok = 3306;
1699           return;
1700         }
1701     }
1702
1703   stop_closest = GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht", "stop_on_closest");
1704   if (stop_closest == GNUNET_SYSERR)
1705     stop_closest = GNUNET_NO;
1706
1707   stop_found = GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht", "stop_found");
1708   if (stop_found == GNUNET_SYSERR)
1709     stop_found = GNUNET_NO;
1710
1711   strict_kademlia = GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht", "strict_kademlia");
1712   if (strict_kademlia == GNUNET_SYSERR)
1713     strict_kademlia = GNUNET_NO;
1714
1715   if (GNUNET_OK !=
1716       GNUNET_CONFIGURATION_get_value_string (cfg, "dht_testing", "comment",
1717                                              &trialmessage))
1718     trialmessage = NULL;
1719
1720   if (GNUNET_OK !=
1721       GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile",
1722                                              &hostfile))
1723     hostfile = NULL;
1724
1725   hosts = NULL;
1726   temphost = NULL;
1727   if (hostfile != NULL)
1728     {
1729       if (GNUNET_OK != GNUNET_DISK_file_test (hostfile))
1730           GNUNET_DISK_fn_write (hostfile, NULL, 0, GNUNET_DISK_PERM_USER_READ
1731             | GNUNET_DISK_PERM_USER_WRITE);
1732       if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0))
1733         {
1734           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1735                       "Could not open file specified for host list, ending test!");
1736           ok = 1119;
1737           GNUNET_free_non_null(trialmessage);
1738           GNUNET_free(hostfile);
1739           return;
1740         }
1741
1742     data = GNUNET_malloc_large (frstat.st_size);
1743     GNUNET_assert(data != NULL);
1744     if (frstat.st_size !=
1745         GNUNET_DISK_fn_read (hostfile, data, frstat.st_size))
1746       {
1747         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1748                   "Could not read file %s specified for host list, ending test!", hostfile);
1749         GNUNET_free (hostfile);
1750         GNUNET_free (data);
1751         GNUNET_free_non_null(trialmessage);
1752         return;
1753       }
1754
1755     GNUNET_free_non_null(hostfile);
1756
1757     buf = data;
1758     count = 0;
1759     while (count < frstat.st_size)
1760       {
1761         count++;
1762         if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count]))
1763           {
1764             data[count] = '\0';
1765             temphost = GNUNET_malloc(sizeof(struct GNUNET_TESTING_Host));
1766             temphost->hostname = buf;
1767             temphost->next = hosts;
1768             hosts = temphost;
1769             buf = &data[count + 1];
1770           }
1771         else if ((data[count] == '\n') || (data[count] == '\0'))
1772           buf = &data[count + 1];
1773       }
1774     }
1775
1776   if (GNUNET_OK !=
1777           GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_getters",
1778                                                  &malicious_getters))
1779     malicious_getters = 0;
1780
1781   if (GNUNET_OK !=
1782           GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_putters",
1783                                                  &malicious_putters))
1784     malicious_putters = 0;
1785
1786   if (GNUNET_OK !=
1787             GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "malicious_droppers",
1788                                                    &malicious_droppers))
1789     malicious_droppers = 0;
1790
1791   if (GNUNET_OK !=
1792       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "settle_time",
1793                                                  &settle_time))
1794     settle_time = 0;
1795
1796   if (GNUNET_SYSERR ==
1797       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_puts",
1798                                              &num_puts))
1799     num_puts = num_peers;
1800
1801   if (GNUNET_SYSERR ==
1802       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "num_gets",
1803                                              &num_gets))
1804     num_gets = num_peers;
1805
1806   if (GNUNET_OK ==
1807         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "find_peer_delay",
1808                                                &temp_config_number))
1809     find_peer_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
1810   else
1811     find_peer_delay = DEFAULT_FIND_PEER_DELAY;
1812
1813   if (GNUNET_OK ==
1814         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_find_peers",
1815                                                &temp_config_number))
1816     max_outstanding_find_peers = temp_config_number;
1817   else
1818     max_outstanding_find_peers = DEFAULT_MAX_OUTSTANDING_FIND_PEERS;
1819
1820   if (GNUNET_OK ==
1821         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_timeout",
1822                                                &temp_config_number))
1823     get_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
1824   else
1825     get_timeout = DEFAULT_GET_TIMEOUT;
1826
1827   if (GNUNET_OK ==
1828         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_puts",
1829                                                &temp_config_number))
1830     max_outstanding_puts = temp_config_number;
1831   else
1832     max_outstanding_puts = DEFAULT_MAX_OUTSTANDING_PUTS;
1833
1834   if (GNUNET_OK ==
1835         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "concurrent_gets",
1836                                                &temp_config_number))
1837     max_outstanding_gets = temp_config_number;
1838   else
1839     max_outstanding_gets = DEFAULT_MAX_OUTSTANDING_GETS;
1840
1841   if (GNUNET_OK ==
1842         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "timeout",
1843                                                &temp_config_number))
1844     all_get_timeout = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
1845   else
1846     all_get_timeout.value = get_timeout.value * ((num_gets / max_outstanding_gets) + 1);
1847
1848   if (GNUNET_OK ==
1849         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "get_delay",
1850                                                &temp_config_number))
1851     get_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
1852   else
1853     get_delay = DEFAULT_GET_DELAY;
1854
1855   if (GNUNET_OK ==
1856         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "put_delay",
1857                                                &temp_config_number))
1858     put_delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
1859   else
1860     put_delay = DEFAULT_PUT_DELAY;
1861
1862   if (GNUNET_OK ==
1863       GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "peer_start_timeout",
1864                                              &temp_config_number))
1865     seconds_per_peer_start = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, temp_config_number);
1866   else
1867     seconds_per_peer_start = DEFAULT_SECONDS_PER_PEER_START;
1868
1869   if (GNUNET_OK ==
1870         GNUNET_CONFIGURATION_get_value_number (cfg, "dht_testing", "data_size",
1871                                                &temp_config_number))
1872     test_data_size = temp_config_number;
1873   else
1874     test_data_size = DEFAULT_TEST_DATA_SIZE;
1875
1876   /**
1877    * Get testing related options.
1878    */
1879
1880   if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
1881                                                           "MALICIOUS_GET_FREQUENCY",
1882                                                           &malicious_get_frequency))
1883     malicious_get_frequency = DEFAULT_MALICIOUS_GET_FREQUENCY;
1884
1885
1886   if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_number (cfg, "DHT_TESTING",
1887                                                           "MALICIOUS_PUT_FREQUENCY",
1888                                                           &malicious_put_frequency))
1889     malicious_put_frequency = DEFAULT_MALICIOUS_PUT_FREQUENCY;
1890
1891   if (GNUNET_NO ==
1892         GNUNET_CONFIGURATION_get_value_yesno(cfg, "dht",
1893                                              "find_peers"))
1894     {
1895       do_find_peer = GNUNET_NO;
1896     }
1897   else
1898     do_find_peer = GNUNET_YES;
1899
1900   topology_str = NULL;
1901   if ((GNUNET_YES ==
1902       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "topology",
1903                                             &topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&topology, topology_str)))
1904     {
1905       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1906                   "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "TOPOLOGY");
1907       topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
1908     }
1909
1910   if (GNUNET_OK !=
1911       GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
1912                                                  &topology_percentage_str))
1913     topology_percentage = 0.5;
1914   else
1915     {
1916       topology_percentage = atof (topology_percentage_str);
1917       GNUNET_free(topology_percentage_str);
1918     }
1919
1920   if (GNUNET_OK !=
1921       GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
1922                                                  &topology_probability_str))
1923     topology_probability = 0.5;
1924   else
1925     {
1926      topology_probability = atof (topology_probability_str);
1927      GNUNET_free(topology_probability_str);
1928     }
1929
1930   if ((GNUNET_YES ==
1931       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology",
1932                                             &connect_topology_str)) && (GNUNET_NO == GNUNET_TESTING_topology_get(&connect_topology, connect_topology_str)))
1933     {
1934       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1935                   "Invalid connect topology `%s' given for section %s option %s\n", connect_topology_str, "TESTING", "CONNECT_TOPOLOGY");
1936     }
1937   GNUNET_free_non_null(connect_topology_str);
1938
1939   if ((GNUNET_YES ==
1940       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "connect_topology_option",
1941                                             &connect_topology_option_str)) && (GNUNET_NO == GNUNET_TESTING_topology_option_get(&connect_topology_option, connect_topology_option_str)))
1942     {
1943       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1944                   "Invalid connect topology option `%s' given for section %s option %s\n", connect_topology_option_str, "TESTING", "CONNECT_TOPOLOGY_OPTION");
1945       connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
1946     }
1947   GNUNET_free_non_null(connect_topology_option_str);
1948
1949   if (GNUNET_YES ==
1950         GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "connect_topology_option_modifier",
1951                                                &connect_topology_option_modifier_string))
1952     {
1953       if (sscanf(connect_topology_option_modifier_string, "%lf", &connect_topology_option_modifier) != 1)
1954       {
1955         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1956         _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1957         connect_topology_option_modifier_string,
1958         "connect_topology_option_modifier",
1959         "TESTING");
1960       }
1961       GNUNET_free (connect_topology_option_modifier_string);
1962     }
1963
1964   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "blacklist_transports",
1965                                          &blacklist_transports))
1966     blacklist_transports = NULL;
1967
1968   if ((GNUNET_YES ==
1969       GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "blacklist_topology",
1970                                             &blacklist_topology_str)) &&
1971       (GNUNET_NO == GNUNET_TESTING_topology_get(&blacklist_topology, blacklist_topology_str)))
1972     {
1973       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1974                   "Invalid topology `%s' given for section %s option %s\n", topology_str, "TESTING", "BLACKLIST_TOPOLOGY");
1975     }
1976   GNUNET_free_non_null(topology_str);
1977   GNUNET_free_non_null(blacklist_topology_str);
1978
1979   /* Get number of peers to start from configuration */
1980   if (GNUNET_SYSERR ==
1981       GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers",
1982                                              &num_peers))
1983     {
1984       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1985                   "Number of peers must be specified in section %s option %s\n", topology_str, "TESTING", "NUM_PEERS");
1986     }
1987   GNUNET_assert(num_peers > 0 && num_peers < (unsigned long long)-1);
1988   /* Set peers_left so we know when all peers started */
1989   peers_left = num_peers;
1990
1991   /* Set up a task to end testing if peer start fails */
1992   die_task = GNUNET_SCHEDULER_add_delayed (sched,
1993                                            GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers),
1994                                            &end_badly, "didn't generate all hostkeys within allowed startup time!");
1995
1996   if (dhtlog_handle == NULL)
1997     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1998                 "dhtlog_handle is NULL!");
1999
2000   if ((trialmessage != NULL) && (dhtlog_handle != NULL))
2001     {
2002       dhtlog_handle->insert_trial (&trialuid, peers_left, topology,
2003                                     blacklist_topology, connect_topology,
2004                                     connect_topology_option,
2005                                     connect_topology_option_modifier, topology_percentage,
2006                                     topology_probability, num_puts, num_gets,
2007                                     max_outstanding_gets, settle_time, 1,
2008                                     malicious_getters, malicious_putters,
2009                                     malicious_droppers, malicious_get_frequency,
2010                                     malicious_put_frequency, stop_closest, stop_found,
2011                                     strict_kademlia, 0, trialmessage);
2012     }
2013   else if (dhtlog_handle != NULL)
2014     {
2015       dhtlog_handle->insert_trial (&trialuid, peers_left, topology,
2016                                     blacklist_topology, connect_topology,
2017                                     connect_topology_option,
2018                                     connect_topology_option_modifier, topology_percentage,
2019                                     topology_probability, num_puts, num_gets,
2020                                     max_outstanding_gets, settle_time, 1,
2021                                     malicious_getters, malicious_putters,
2022                                     malicious_droppers, malicious_get_frequency,
2023                                     malicious_put_frequency, stop_closest, stop_found,
2024                                     strict_kademlia, 0, "");
2025     }
2026
2027   GNUNET_free_non_null(trialmessage);
2028
2029   hostkey_meter = create_meter(peers_left, "Hostkeys created ", GNUNET_YES);
2030   peer_start_meter = create_meter(peers_left, "Peers started ", GNUNET_YES);
2031
2032   put_meter = create_meter(num_puts, "Puts completed ", GNUNET_YES);
2033   get_meter = create_meter(num_gets, "Gets completed ", GNUNET_YES);
2034   pg = GNUNET_TESTING_daemons_start (sched, cfg,
2035                                      peers_left,
2036                                      GNUNET_TIME_relative_multiply(seconds_per_peer_start, num_peers),
2037                                      &hostkey_callback, NULL,
2038                                      &peers_started_callback, NULL,
2039                                      &topology_callback, NULL,
2040                                      hosts);
2041
2042   GNUNET_free_non_null(temphost);
2043 }
2044
2045
2046 int
2047 main (int argc, char *argv[])
2048 {
2049   int ret;
2050   struct GNUNET_GETOPT_CommandLineOption options[] = {
2051       GNUNET_GETOPT_OPTION_END
2052     };
2053
2054   ret = GNUNET_PROGRAM_run (argc,
2055                             argv, "gnunet-dht-driver", "nohelp",
2056                             options, &run, &ok);
2057
2058   if (ret != GNUNET_OK)
2059     {
2060       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "`gnunet-dht-driver': Failed with error code %d\n", ret);
2061     }
2062
2063   /**
2064    * Need to remove base directory, subdirectories taken care
2065    * of by the testing framework.
2066    */
2067   if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK)
2068     {
2069       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to remove testing directory %s\n", test_directory);
2070     }
2071   return ret;
2072 }
2073
2074 /* end of test_dht_twopeer_put_get.c */