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