fix warning
[oweals/gnunet.git] / src / testing / testing_peergroup.c
1 /*
2  This file is part of GNUnet
3  (C) 2008-2011 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 /**
22  * @file testing/testing_peergroup.c
23  * @brief API implementation for easy peer group creation
24  * @author Nathan Evans
25  * @author Christian Grothoff
26  *
27  */
28 #include "platform.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_arm_service.h"
31 #include "gnunet_testing_lib.h"
32 #include "gnunet_core_service.h"
33
34 /** Globals **/
35 #define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
36
37 #define DEFAULT_CONNECT_ATTEMPTS 2
38
39 /** Struct definitions **/
40
41 struct PeerGroupStartupContext
42 {
43   struct GNUNET_TESTING_PeerGroup *pg;
44   const struct GNUNET_CONFIGURATION_Handle *cfg;
45   unsigned int total;
46   unsigned int peers_left;
47   unsigned long long max_concurrent_connections;
48   unsigned long long connect_attempts;
49   unsigned long long max_concurrent_ssh;
50   struct GNUNET_TIME_Absolute timeout;
51   GNUNET_TESTING_NotifyConnection connect_cb;
52   GNUNET_TESTING_NotifyCompletion peergroup_cb;
53
54   /**
55    * Closure for all peergroup callbacks.
56    */
57   void *cls;
58
59   const struct GNUNET_TESTING_Host *hostnames;
60   enum GNUNET_TESTING_Topology topology;
61
62   float topology_percentage;
63
64   float topology_probability;
65
66   enum GNUNET_TESTING_Topology restrict_topology;
67   char *restrict_transports;
68   enum GNUNET_TESTING_Topology connect_topology;
69   enum GNUNET_TESTING_TopologyOption connect_topology_option;
70   double connect_topology_option_modifier;
71   int verbose;
72
73   struct ProgressMeter *hostkey_meter;
74   struct ProgressMeter *peer_start_meter;
75   struct ProgressMeter *connect_meter;
76
77   /**
78    * Task used to kill the peergroup.
79    */
80   GNUNET_SCHEDULER_TaskIdentifier die_task;
81
82   char *fail_reason;
83
84   /**
85    * Variable used to store the number of connections we should wait for.
86    */
87   unsigned int expected_connections;
88
89   /**
90    * Time when the connecting peers was started.
91    */
92   struct GNUNET_TIME_Absolute connect_start_time;
93
94   /**
95    * The total number of connections that have been created so far.
96    */
97   unsigned int total_connections;
98
99   /**
100    * The total number of connections that have failed so far.
101    */
102   unsigned int failed_connections;
103 };
104
105 /**
106  * Simple struct to keep track of progress, and print a
107  * percentage meter for long running tasks.
108  */
109 struct ProgressMeter
110 {
111   /**
112    * Total number of tasks to complete.
113    */
114   unsigned int total;
115
116   /**
117    * Print percentage done after modnum tasks.
118    */
119   unsigned int modnum;
120
121   /**
122    * Print a . each dotnum tasks.
123    */
124   unsigned int dotnum;
125
126   /**
127    * Total number completed thus far.
128    */
129   unsigned int completed;
130
131   /**
132    * Whether or not to print.
133    */
134   int print;
135
136   /**
137    * Startup string for progress meter.
138    */
139   char *startup_string;
140 };
141
142
143 /** Utility functions **/
144
145 /**
146  * Create a meter to keep track of the progress of some task.
147  *
148  * @param total the total number of items to complete
149  * @param start_string a string to prefix the meter with (if printing)
150  * @param print GNUNET_YES to print the meter, GNUNET_NO to count
151  *              internally only
152  *
153  * @return the progress meter
154  */
155 static struct ProgressMeter *
156 create_meter(unsigned int total, char * start_string, int print)
157 {
158   struct ProgressMeter *ret;
159   ret = GNUNET_malloc(sizeof(struct ProgressMeter));
160   ret->print = print;
161   ret->total = total;
162   ret->modnum = total / 4;
163   ret->dotnum = (total / 50) + 1;
164   if (start_string != NULL)
165     ret->startup_string = GNUNET_strdup(start_string);
166   else
167     ret->startup_string = GNUNET_strdup("");
168
169   return ret;
170 }
171
172 /**
173  * Update progress meter (increment by one).
174  *
175  * @param meter the meter to update and print info for
176  *
177  * @return GNUNET_YES if called the total requested,
178  *         GNUNET_NO if more items expected
179  */
180 static int
181 update_meter(struct ProgressMeter *meter)
182 {
183   if (meter->print == GNUNET_YES)
184     {
185       if (meter->completed % meter->modnum == 0)
186         {
187           if (meter->completed == 0)
188             {
189               fprintf (stdout, "%sProgress: [0%%", meter->startup_string);
190             }
191           else
192             fprintf (stdout, "%d%%", (int) (((float) meter->completed
193                 / meter->total) * 100));
194         }
195       else if (meter->completed % meter->dotnum == 0)
196         fprintf (stdout, ".");
197
198       if (meter->completed + 1 == meter->total)
199         fprintf (stdout, "%d%%]\n", 100);
200       fflush (stdout);
201     }
202   meter->completed++;
203
204   if (meter->completed == meter->total)
205     return GNUNET_YES;
206   return GNUNET_NO;
207 }
208
209 /**
210  * Reset progress meter.
211  *
212  * @param meter the meter to reset
213  *
214  * @return GNUNET_YES if meter reset,
215  *         GNUNET_SYSERR on error
216  */
217 static int
218 reset_meter(struct ProgressMeter *meter)
219 {
220   if (meter == NULL)
221     return GNUNET_SYSERR;
222
223   meter->completed = 0;
224   return GNUNET_YES;
225 }
226
227 /**
228  * Release resources for meter
229  *
230  * @param meter the meter to free
231  */
232 static void
233 free_meter(struct ProgressMeter *meter)
234 {
235   GNUNET_free_non_null (meter->startup_string);
236   GNUNET_free (meter);
237 }
238
239
240 /** Functions for creating, starting and connecting the peergroup **/
241
242 /**
243  * Check whether peers successfully shut down.
244  */
245 static void
246 internal_shutdown_callback(void *cls, const char *emsg)
247 {
248   struct PeerGroupStartupContext *pg_start_ctx = cls;
249   if (emsg != NULL)
250     pg_start_ctx->peergroup_cb(pg_start_ctx->cls, emsg);
251   else
252     pg_start_ctx->peergroup_cb(pg_start_ctx->cls, pg_start_ctx->fail_reason);
253 }
254
255 /**
256  * Check if the get_handle is being used, if so stop the request.  Either
257  * way, schedule the end_badly_cont function which actually shuts down the
258  * test.
259  */
260 static void
261 end_badly(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
262 {
263   struct PeerGroupStartupContext *pg_start_ctx = cls;
264   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failing peer group startup with error: `%s'!\n",
265               pg_start_ctx->fail_reason);
266
267   GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout), &internal_shutdown_callback, pg_start_ctx);
268
269   if (pg_start_ctx->hostkey_meter != NULL)
270     free_meter (pg_start_ctx->hostkey_meter);
271   if (pg_start_ctx->peer_start_meter != NULL)
272     free_meter (pg_start_ctx->peer_start_meter);
273   if (pg_start_ctx->connect_meter != NULL)
274     free_meter (pg_start_ctx->connect_meter);
275 }
276
277 /**
278  * This function is called whenever a connection attempt is finished between two of
279  * the started peers (started with GNUNET_TESTING_daemons_start).  The total
280  * number of times this function is called should equal the number returned
281  * from the GNUNET_TESTING_connect_topology call.
282  *
283  * The emsg variable is NULL on success (peers connected), and non-NULL on
284  * failure (peers failed to connect).
285  */
286 static void
287 internal_topology_callback(
288                            void *cls,
289                            const struct GNUNET_PeerIdentity *first,
290                            const struct GNUNET_PeerIdentity *second,
291                            uint32_t distance,
292                            const struct GNUNET_CONFIGURATION_Handle *first_cfg,
293                            const struct GNUNET_CONFIGURATION_Handle *second_cfg,
294                            struct GNUNET_TESTING_Daemon *first_daemon,
295                            struct GNUNET_TESTING_Daemon *second_daemon,
296                            const char *emsg)
297 {
298   struct PeerGroupStartupContext *pg_start_ctx = cls;
299 #if TIMING
300   unsigned long long duration;
301   unsigned long long total_duration;
302   unsigned int new_connections;
303   unsigned int new_failed_connections;
304   double conns_per_sec_recent;
305   double conns_per_sec_total;
306   double failed_conns_per_sec_recent;
307   double failed_conns_per_sec_total;
308 #endif
309
310 #if TIMING
311   if (GNUNET_TIME_absolute_get_difference (connect_last_time,
312                                            GNUNET_TIME_absolute_get ()).rel_value
313       > GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
314                                        CONN_UPDATE_DURATION).rel_value)
315     {
316       /* Get number of new connections */
317       new_connections = total_connections - previous_connections;
318
319       /* Get number of new FAILED connections */
320       new_failed_connections = failed_connections - previous_failed_connections;
321
322       /* Get duration in seconds */
323       duration
324           = GNUNET_TIME_absolute_get_difference (connect_last_time,
325                                                  GNUNET_TIME_absolute_get ()).rel_value
326               / 1000;
327       total_duration
328           = GNUNET_TIME_absolute_get_difference (connect_start_time,
329                                                  GNUNET_TIME_absolute_get ()).rel_value
330               / 1000;
331
332       failed_conns_per_sec_recent = (double) new_failed_connections / duration;
333       failed_conns_per_sec_total = (double) failed_connections / total_duration;
334       conns_per_sec_recent = (double) new_connections / duration;
335       conns_per_sec_total = (double) total_connections / total_duration;
336       GNUNET_log (
337                   GNUNET_ERROR_TYPE_WARNING,
338                   "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n",
339                   conns_per_sec_recent, CONN_UPDATE_DURATION,
340                   conns_per_sec_total, failed_conns_per_sec_recent,
341                   failed_conns_per_sec_total);
342       connect_last_time = GNUNET_TIME_absolute_get ();
343       previous_connections = total_connections;
344       previous_failed_connections = failed_connections;
345       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
346                   "have %u total_connections, %u failed\n", total_connections,
347                   failed_connections);
348     }
349 #endif
350
351
352   if (emsg == NULL)
353     {
354       pg_start_ctx->total_connections++;
355 #if VERBOSE > 1
356       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
357           first_daemon->shortname,
358           second_daemon->shortname,
359           distance);
360 #endif
361     }
362   else
363     {
364       pg_start_ctx->failed_connections++;
365 #if VERBOSE
366       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peer %s to peer %s with error :\n%s\n",
367           first_daemon->shortname,
368           second_daemon->shortname, emsg);
369
370       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
371           first_daemon->shortname,
372           second_daemon->shortname, emsg);
373 #endif
374     }
375
376   GNUNET_assert(pg_start_ctx->connect_meter != NULL);
377   if (pg_start_ctx->connect_cb != NULL)
378     pg_start_ctx->connect_cb(pg_start_ctx->cls, first,
379                              second,
380                              distance,
381                              first_cfg,
382                              second_cfg,
383                              first_daemon,
384                              second_daemon,
385                              emsg);
386   if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter))
387     {
388 #if VERBOSE
389       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390           "Created %d total connections, which is our target number!  Starting next phase of testing.\n",
391           total_connections);
392 #endif
393
394 #if TIMING
395       total_duration
396           = GNUNET_TIME_absolute_get_difference (connect_start_time,
397                                                  GNUNET_TIME_absolute_get ()).rel_value
398               / 1000;
399       failed_conns_per_sec_total = (double) failed_connections / total_duration;
400       conns_per_sec_total = (double) total_connections / total_duration;
401       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
402                   "Overall connection info --- Total: %u, Total Failed %u/s\n",
403                   total_connections, failed_connections);
404       GNUNET_log (
405                   GNUNET_ERROR_TYPE_WARNING,
406                   "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
407                   conns_per_sec_total, failed_conns_per_sec_total);
408 #endif
409
410       GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
411       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
412
413       /* Call final callback, signifying that the peer group has been started and connected */
414       if (pg_start_ctx->peergroup_cb != NULL)
415         pg_start_ctx->peergroup_cb(pg_start_ctx->cls, NULL);
416     }
417 }
418
419 static void
420 internal_peers_started_callback(void *cls, const struct GNUNET_PeerIdentity *id,
421     const struct GNUNET_CONFIGURATION_Handle *cfg,
422     struct GNUNET_TESTING_Daemon *d, const char *emsg)
423 {
424   struct PeerGroupStartupContext *pg_start_ctx = cls;
425   if (emsg != NULL)
426     {
427       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428                   "Failed to start daemon with error: `%s'\n", emsg);
429       return;
430     }
431   GNUNET_assert (id != NULL);
432
433 #if VERBOSE > 1
434   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
435       (num_peers - peers_left) + 1, num_peers);
436 #endif
437
438   pg_start_ctx->peers_left--;
439
440   if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
441     {
442 #if VERBOSE
443       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444           "All %d daemons started, now connecting peers!\n",
445           num_peers);
446 #endif
447       GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
448       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
449
450       pg_start_ctx->expected_connections = UINT_MAX;
451       if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
452         {
453           pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
454           pg_start_ctx->expected_connections
455               = GNUNET_TESTING_connect_topology (
456                                                  pg_start_ctx->pg,
457                                                  pg_start_ctx->connect_topology,
458                                                  pg_start_ctx->connect_topology_option,
459                                                  pg_start_ctx->connect_topology_option_modifier,
460                                                  DEFAULT_CONNECT_TIMEOUT,
461                                                  pg_start_ctx->connect_attempts,
462                                                  NULL, NULL);
463
464           pg_start_ctx->connect_meter
465               = create_meter (pg_start_ctx->expected_connections,
466                               "Peer connection ", pg_start_ctx->verbose);
467           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468                       "Have %d expected connections\n",
469                       pg_start_ctx->expected_connections);
470         }
471
472       if (pg_start_ctx->expected_connections == 0)
473         {
474           GNUNET_free_non_null(pg_start_ctx->fail_reason);
475           pg_start_ctx->fail_reason = GNUNET_strdup("from connect topology (bad return)");
476           pg_start_ctx->die_task
477               = GNUNET_SCHEDULER_add_now (&end_badly,
478                                           pg_start_ctx);
479         }
480
481       GNUNET_free_non_null(pg_start_ctx->fail_reason);
482       pg_start_ctx->fail_reason = GNUNET_strdup("from connect topology (timeout)");
483       pg_start_ctx->die_task
484           = GNUNET_SCHEDULER_add_delayed (
485                                           GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout),
486                                           &end_badly,
487                                           pg_start_ctx);
488     }
489 }
490
491 /**
492  * Callback indicating that the hostkey was created for a peer.
493  *
494  * @param cls NULL
495  * @param id the peer identity
496  * @param d the daemon handle (pretty useless at this point, remove?)
497  * @param emsg non-null on failure
498  */
499 static void
500 internal_hostkey_callback(void *cls, const struct GNUNET_PeerIdentity *id,
501                           struct GNUNET_TESTING_Daemon *d, const char *emsg)
502 {
503   struct PeerGroupStartupContext *pg_start_ctx = cls;
504   unsigned int create_expected_connections;
505
506   if (emsg != NULL)
507     {
508       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
509                   "Hostkey callback received error: %s\n", emsg);
510     }
511
512 #if VERBOSE > 1
513   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
514       "Hostkey (%d/%d) created for peer `%s'\n",
515       num_peers - peers_left, num_peers, GNUNET_i2s(id));
516 #endif
517
518   pg_start_ctx->peers_left--;
519   if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
520     {
521       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
522       /* Set up task in case topology creation doesn't finish
523        * within a reasonable amount of time */
524       pg_start_ctx->die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
525                                                              &end_badly,
526                                                              "from create_topology");
527       pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */
528       create_expected_connections = GNUNET_TESTING_create_topology (pg_start_ctx->pg, pg_start_ctx->topology, pg_start_ctx->restrict_topology,
529                                                                     pg_start_ctx->restrict_transports);
530       if (create_expected_connections > 0)
531         {
532           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
533                       "Topology set up, have %u expected connections, now starting peers!\n", create_expected_connections);
534           GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg);
535         }
536       else
537         {
538           GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
539           pg_start_ctx->die_task = GNUNET_SCHEDULER_add_now (&end_badly,
540                                                "from create topology (bad return)");
541         }
542
543       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
544       pg_start_ctx->die_task
545           = GNUNET_SCHEDULER_add_delayed (
546                                           GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
547                                           &end_badly,
548                                           "from continue startup (timeout)");
549     }
550 }
551
552
553 /**
554  * Start a peer group with a given number of peers.  Notify
555  * on completion of peer startup and connection based on given
556  * topological constraints.  Optionally notify on each
557  * established connection.
558  *
559  * @param cfg configuration template to use
560  * @param total number of daemons to start
561  * @param timeout total time allowed for peers to start
562  * @param connect_cb function to call each time two daemons are connected
563  * @param peergroup_cb function to call once all peers are up and connected
564  * @param peergroup_cls closure for peergroup callbacks
565  * @param hostnames linked list of host structs to use to start peers on
566  *                  (NULL to run on localhost only)
567  *
568  * @return NULL on error, otherwise handle to control peer group
569  */
570 struct GNUNET_TESTING_PeerGroup *
571 GNUNET_TESTING_peergroup_start(
572                                const struct GNUNET_CONFIGURATION_Handle *cfg,
573                                unsigned int total,
574                                struct GNUNET_TIME_Relative timeout,
575                                GNUNET_TESTING_NotifyConnection connect_cb,
576                                GNUNET_TESTING_NotifyCompletion peergroup_cb,
577                                void *peergroup_cls,
578                                const struct GNUNET_TESTING_Host *hostnames)
579 {
580   struct PeerGroupStartupContext *pg_start_ctx;
581   unsigned long long temp_config_number;
582   char *temp_str;
583   GNUNET_assert(total > 0);
584   GNUNET_assert(cfg != NULL);
585
586   pg_start_ctx = GNUNET_malloc(sizeof(struct PeerGroupStartupContext));
587
588   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
589                                                           "connect_attempts",
590                                                           &pg_start_ctx->connect_attempts))
591     {
592       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
593                   "testing", "connect_attempts");
594       GNUNET_free(pg_start_ctx);
595       return NULL;
596     }
597
598   if (GNUNET_OK
599       != GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
600                                                 "max_outstanding_connections",
601                                                 &pg_start_ctx->max_concurrent_connections))
602     {
603       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
604                   "testing", "max_outstanding_connections");
605       GNUNET_free(pg_start_ctx);
606       return NULL;
607     }
608
609   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
610                                                           "max_concurrent_ssh",
611                                                           &pg_start_ctx->max_concurrent_ssh))
612     {
613       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
614                   "testing", "max_concurrent_ssh");
615       GNUNET_free(pg_start_ctx);
616       return NULL;
617     }
618
619   if (GNUNET_SYSERR == (pg_start_ctx->verbose = GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing",
620                                                           "use_progressbars")))
621     {
622       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
623                   "testing", "use_progressbars");
624       GNUNET_free(pg_start_ctx);
625       return NULL;
626     }
627
628   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
629                                                           "peergroup_timeout",
630                                                           &temp_config_number))
631     pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute(GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
632                                                      temp_config_number));
633   else
634     {
635       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
636                   "testing", "peergroup_timeout");
637       GNUNET_free(pg_start_ctx);
638       return NULL;
639     }
640
641
642   /* Read topology related options from the configuration file */
643   temp_str = NULL;
644   if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
645                                                             "topology",
646                                                             &temp_str))
647       && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str)))
648     {
649       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
650                   "Invalid topology `%s' given for section %s option %s\n",
651                   temp_str, "TESTING", "TOPOLOGY");
652       pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
653     }
654   GNUNET_free_non_null(temp_str);
655
656   if (GNUNET_OK
657       != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
658                                                 &temp_str))
659     pg_start_ctx->topology_percentage = 0.5;
660   else
661     {
662       pg_start_ctx->topology_percentage = atof (temp_str);
663       GNUNET_free(temp_str);
664     }
665
666   if (GNUNET_OK
667       != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
668                                                 &temp_str))
669     pg_start_ctx->topology_probability = 0.5;
670   else
671     {
672       pg_start_ctx->topology_probability = atof (temp_str);
673       GNUNET_free(temp_str);
674     }
675
676   if ((GNUNET_YES
677       == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
678                                                 "connect_topology",
679                                                 &temp_str))
680       && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology,
681                                                     temp_str)))
682     {
683       GNUNET_log (
684                   GNUNET_ERROR_TYPE_WARNING,
685                   "Invalid connect topology `%s' given for section %s option %s\n",
686                   temp_str, "TESTING", "CONNECT_TOPOLOGY");
687     }
688   GNUNET_free_non_null(temp_str);
689
690   if ((GNUNET_YES
691       == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
692                                                 "connect_topology_option",
693                                                 &temp_str))
694       && (GNUNET_NO
695           == GNUNET_TESTING_topology_option_get (&pg_start_ctx->connect_topology_option,
696                                                  temp_str)))
697     {
698       GNUNET_log (
699                   GNUNET_ERROR_TYPE_WARNING,
700                   "Invalid connect topology option `%s' given for section %s option %s\n",
701                   temp_str, "TESTING",
702                   "CONNECT_TOPOLOGY_OPTION");
703       pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
704     }
705   GNUNET_free_non_null(temp_str);
706
707   if (GNUNET_YES
708       == GNUNET_CONFIGURATION_get_value_string (
709                                                 cfg,
710                                                 "testing",
711                                                 "connect_topology_option_modifier",
712                                                 &temp_str))
713     {
714       if (sscanf (temp_str, "%lf",
715                   &pg_start_ctx->connect_topology_option_modifier) != 1)
716         {
717           GNUNET_log (
718                       GNUNET_ERROR_TYPE_WARNING,
719                       _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
720                           temp_str,
721                       "connect_topology_option_modifier", "TESTING");
722           GNUNET_free (temp_str);
723           GNUNET_free(pg_start_ctx);
724           return NULL;
725         }
726       GNUNET_free (temp_str);
727     }
728
729   if (GNUNET_YES
730       != GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
731                                                 "blacklist_transports",
732                                                 &pg_start_ctx->restrict_transports))
733     pg_start_ctx->restrict_transports = NULL;
734
735   if ((GNUNET_YES
736       == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
737                                                 "blacklist_topology",
738                                                 &temp_str))
739       && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology,
740                                                     temp_str)))
741     {
742       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
743                   "Invalid topology `%s' given for section %s option %s\n",
744                   temp_str, "TESTING", "BLACKLIST_TOPOLOGY");
745     }
746   GNUNET_free_non_null(temp_str);
747
748   pg_start_ctx->cfg = cfg;
749   pg_start_ctx->total = total;
750   pg_start_ctx->peers_left = total;
751   pg_start_ctx->connect_cb = connect_cb;
752   pg_start_ctx->peergroup_cb = peergroup_cb;
753   pg_start_ctx->cls = peergroup_cls;
754   pg_start_ctx->hostnames = hostnames;
755   pg_start_ctx->hostkey_meter = create_meter (pg_start_ctx->peers_left, "Hostkeys created ", pg_start_ctx->verbose);
756   pg_start_ctx->peer_start_meter = create_meter (pg_start_ctx->peers_left, "Peers started ", pg_start_ctx->verbose);
757   /* Make compilers happy */
758   reset_meter(pg_start_ctx->peer_start_meter);
759   pg_start_ctx->die_task
760       = GNUNET_SCHEDULER_add_delayed (
761                                       GNUNET_TIME_absolute_get_remaining (
762                                                                           pg_start_ctx->timeout),
763                                       &end_badly,
764                                       "didn't generate all hostkeys within allowed startup time!");
765
766   pg_start_ctx->pg
767       = GNUNET_TESTING_daemons_start (
768                                       pg_start_ctx->cfg,
769                                       pg_start_ctx->peers_left,
770                                       pg_start_ctx->max_concurrent_connections,
771                                       pg_start_ctx->max_concurrent_ssh,
772                                       GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
773                                       &internal_hostkey_callback, pg_start_ctx,
774                                       &internal_peers_started_callback,
775                                       pg_start_ctx,
776                                       &internal_topology_callback,
777                                       pg_start_ctx, pg_start_ctx->hostnames);
778
779   return pg_start_ctx->pg;
780 }
781
782 /* end of testing_peergroup.c */