initial peergroup convenience implementation
[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 int max_concurrent_connections;
48   unsigned int max_concurrent_ssh;
49   struct GNUNET_TIME_Absolute timeout;
50   GNUNET_TESTING_NotifyConnection connect_cb;
51   void *connect_cb_cls;
52   GNUNET_TESTING_NotifyCompletion peergroup_cb;
53   void *peergroup_cb_cls;
54   const struct GNUNET_TESTING_Host *hostnames;
55   enum GNUNET_TESTING_Topology topology;
56   enum GNUNET_TESTING_Topology restrict_topology;
57   const char *restrict_transports;
58   enum GNUNET_TESTING_Topology connect_topology;
59   enum GNUNET_TESTING_TopologyOption connect_topology_option;
60   double connect_topology_option_modifier;
61   int verbose;
62
63   struct ProgressMeter *hostkey_meter;
64   struct ProgressMeter *peer_start_meter;
65   struct ProgressMeter *connect_meter;
66
67   /**
68    * Task used to kill the peergroup.
69    */
70   GNUNET_SCHEDULER_TaskIdentifier die_task;
71
72   char *fail_reason;
73
74   /**
75    * Variable used to store the number of connections we should wait for.
76    */
77   unsigned int expected_connections;
78
79   /**
80    * Time when the connecting peers was started.
81    */
82   struct GNUNET_TIME_Absolute connect_start_time;
83
84   /**
85    * The total number of connections that have been created so far.
86    */
87   unsigned int total_connections;
88
89   /**
90    * The total number of connections that have failed so far.
91    */
92   unsigned int failed_connections;
93 };
94
95 /**
96  * Simple struct to keep track of progress, and print a
97  * percentage meter for long running tasks.
98  */
99 struct ProgressMeter
100 {
101   /**
102    * Total number of tasks to complete.
103    */
104   unsigned int total;
105
106   /**
107    * Print percentage done after modnum tasks.
108    */
109   unsigned int modnum;
110
111   /**
112    * Print a . each dotnum tasks.
113    */
114   unsigned int dotnum;
115
116   /**
117    * Total number completed thus far.
118    */
119   unsigned int completed;
120
121   /**
122    * Whether or not to print.
123    */
124   int print;
125
126   /**
127    * Startup string for progress meter.
128    */
129   char *startup_string;
130 };
131
132
133 /** Utility functions **/
134
135 /**
136  * Create a meter to keep track of the progress of some task.
137  *
138  * @param total the total number of items to complete
139  * @param start_string a string to prefix the meter with (if printing)
140  * @param print GNUNET_YES to print the meter, GNUNET_NO to count
141  *              internally only
142  *
143  * @return the progress meter
144  */
145 static struct ProgressMeter *
146 create_meter(unsigned int total, char * start_string, int print)
147 {
148   struct ProgressMeter *ret;
149   ret = GNUNET_malloc(sizeof(struct ProgressMeter));
150   ret->print = print;
151   ret->total = total;
152   ret->modnum = total / 4;
153   ret->dotnum = (total / 50) + 1;
154   if (start_string != NULL)
155     ret->startup_string = GNUNET_strdup(start_string);
156   else
157     ret->startup_string = GNUNET_strdup("");
158
159   return ret;
160 }
161
162 /**
163  * Update progress meter (increment by one).
164  *
165  * @param meter the meter to update and print info for
166  *
167  * @return GNUNET_YES if called the total requested,
168  *         GNUNET_NO if more items expected
169  */
170 static int
171 update_meter(struct ProgressMeter *meter)
172 {
173   if (meter->print == GNUNET_YES)
174     {
175       if (meter->completed % meter->modnum == 0)
176         {
177           if (meter->completed == 0)
178             {
179               fprintf (stdout, "%sProgress: [0%%", meter->startup_string);
180             }
181           else
182             fprintf (stdout, "%d%%", (int) (((float) meter->completed
183                 / meter->total) * 100));
184         }
185       else if (meter->completed % meter->dotnum == 0)
186         fprintf (stdout, ".");
187
188       if (meter->completed + 1 == meter->total)
189         fprintf (stdout, "%d%%]\n", 100);
190       fflush (stdout);
191     }
192   meter->completed++;
193
194   if (meter->completed == meter->total)
195     return GNUNET_YES;
196   return GNUNET_NO;
197 }
198
199 /**
200  * Reset progress meter.
201  *
202  * @param meter the meter to reset
203  *
204  * @return GNUNET_YES if meter reset,
205  *         GNUNET_SYSERR on error
206  */
207 static int
208 reset_meter(struct ProgressMeter *meter)
209 {
210   if (meter == NULL)
211     return GNUNET_SYSERR;
212
213   meter->completed = 0;
214   return GNUNET_YES;
215 }
216
217 /**
218  * Release resources for meter
219  *
220  * @param meter the meter to free
221  */
222 static void
223 free_meter(struct ProgressMeter *meter)
224 {
225   GNUNET_free_non_null (meter->startup_string);
226   GNUNET_free (meter);
227 }
228
229
230 /** Functions for creating, starting and connecting the peergroup **/
231
232 /**
233  * Check whether peers successfully shut down.
234  */
235 static void
236 internal_shutdown_callback(void *cls, const char *emsg)
237 {
238   struct PeerGroupStartupContext *pg_start_ctx = cls;
239   if (emsg != NULL)
240     pg_start_ctx->peergroup_cb(pg_start_ctx->peergroup_cb_cls, emsg);
241   else
242     pg_start_ctx->peergroup_cb(pg_start_ctx->peergroup_cb_cls, pg_start_ctx->fail_reason);
243 }
244
245 /**
246  * Check if the get_handle is being used, if so stop the request.  Either
247  * way, schedule the end_badly_cont function which actually shuts down the
248  * test.
249  */
250 static void
251 end_badly(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
252 {
253   struct PeerGroupStartupContext *pg_start_ctx = cls;
254   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failing peer group startup with error: `%s'!\n",
255               pg_start_ctx->fail_reason);
256
257   GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout), &internal_shutdown_callback, pg_start_ctx);
258
259   if (pg_start_ctx->hostkey_meter != NULL)
260     free_meter (pg_start_ctx->hostkey_meter);
261   if (pg_start_ctx->peer_start_meter != NULL)
262     free_meter (pg_start_ctx->peer_start_meter);
263   if (pg_start_ctx->connect_meter != NULL)
264     free_meter (pg_start_ctx->connect_meter);
265 }
266
267 /**
268  * This function is called whenever a connection attempt is finished between two of
269  * the started peers (started with GNUNET_TESTING_daemons_start).  The total
270  * number of times this function is called should equal the number returned
271  * from the GNUNET_TESTING_connect_topology call.
272  *
273  * The emsg variable is NULL on success (peers connected), and non-NULL on
274  * failure (peers failed to connect).
275  */
276 static void
277 internal_topology_callback(
278                            void *cls,
279                            const struct GNUNET_PeerIdentity *first,
280                            const struct GNUNET_PeerIdentity *second,
281                            uint32_t distance,
282                            const struct GNUNET_CONFIGURATION_Handle *first_cfg,
283                            const struct GNUNET_CONFIGURATION_Handle *second_cfg,
284                            struct GNUNET_TESTING_Daemon *first_daemon,
285                            struct GNUNET_TESTING_Daemon *second_daemon,
286                            const char *emsg)
287 {
288   struct PeerGroupStartupContext *pg_start_ctx = cls;
289 #if TIMING
290   unsigned long long duration;
291   unsigned long long total_duration;
292   unsigned int new_connections;
293   unsigned int new_failed_connections;
294   double conns_per_sec_recent;
295   double conns_per_sec_total;
296   double failed_conns_per_sec_recent;
297   double failed_conns_per_sec_total;
298 #endif
299
300 #if TIMING
301   if (GNUNET_TIME_absolute_get_difference (connect_last_time,
302                                            GNUNET_TIME_absolute_get ()).rel_value
303       > GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
304                                        CONN_UPDATE_DURATION).rel_value)
305     {
306       /* Get number of new connections */
307       new_connections = total_connections - previous_connections;
308
309       /* Get number of new FAILED connections */
310       new_failed_connections = failed_connections - previous_failed_connections;
311
312       /* Get duration in seconds */
313       duration
314           = GNUNET_TIME_absolute_get_difference (connect_last_time,
315                                                  GNUNET_TIME_absolute_get ()).rel_value
316               / 1000;
317       total_duration
318           = GNUNET_TIME_absolute_get_difference (connect_start_time,
319                                                  GNUNET_TIME_absolute_get ()).rel_value
320               / 1000;
321
322       failed_conns_per_sec_recent = (double) new_failed_connections / duration;
323       failed_conns_per_sec_total = (double) failed_connections / total_duration;
324       conns_per_sec_recent = (double) new_connections / duration;
325       conns_per_sec_total = (double) total_connections / total_duration;
326       GNUNET_log (
327                   GNUNET_ERROR_TYPE_WARNING,
328                   "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n",
329                   conns_per_sec_recent, CONN_UPDATE_DURATION,
330                   conns_per_sec_total, failed_conns_per_sec_recent,
331                   failed_conns_per_sec_total);
332       connect_last_time = GNUNET_TIME_absolute_get ();
333       previous_connections = total_connections;
334       previous_failed_connections = failed_connections;
335       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
336                   "have %u total_connections, %u failed\n", total_connections,
337                   failed_connections);
338     }
339 #endif
340
341
342   if (emsg == NULL)
343     {
344       pg_start_ctx->total_connections++;
345 #if VERBOSE > 1
346       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
347           first_daemon->shortname,
348           second_daemon->shortname,
349           distance);
350 #endif
351     }
352   else
353     {
354       pg_start_ctx->failed_connections++;
355 #if VERBOSE
356       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peer %s to peer %s with error :\n%s\n",
357           first_daemon->shortname,
358           second_daemon->shortname, emsg);
359
360       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
361           first_daemon->shortname,
362           second_daemon->shortname, emsg);
363 #endif
364     }
365
366   GNUNET_assert(pg_start_ctx->connect_meter != NULL);
367   if (pg_start_ctx->connect_cb != NULL)
368     pg_start_ctx->connect_cb(pg_start_ctx->connect_cb_cls, first,
369                              second,
370                              distance,
371                              first_cfg,
372                              second_cfg,
373                              first_daemon,
374                              second_daemon,
375                              emsg);
376   if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter))
377     {
378 #if VERBOSE
379       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
380           "Created %d total connections, which is our target number!  Starting next phase of testing.\n",
381           total_connections);
382 #endif
383
384 #if TIMING
385       total_duration
386           = GNUNET_TIME_absolute_get_difference (connect_start_time,
387                                                  GNUNET_TIME_absolute_get ()).rel_value
388               / 1000;
389       failed_conns_per_sec_total = (double) failed_connections / total_duration;
390       conns_per_sec_total = (double) total_connections / total_duration;
391       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
392                   "Overall connection info --- Total: %u, Total Failed %u/s\n",
393                   total_connections, failed_connections);
394       GNUNET_log (
395                   GNUNET_ERROR_TYPE_WARNING,
396                   "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
397                   conns_per_sec_total, failed_conns_per_sec_total);
398 #endif
399
400       GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
401       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
402
403       /* Call final callback, signifying that the peer group has been started and connected */
404     }
405 }
406
407 static void
408 internal_peers_started_callback(void *cls, const struct GNUNET_PeerIdentity *id,
409     const struct GNUNET_CONFIGURATION_Handle *cfg,
410     struct GNUNET_TESTING_Daemon *d, const char *emsg)
411 {
412   struct PeerGroupStartupContext *pg_start_ctx = cls;
413   if (emsg != NULL)
414     {
415       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
416                   "Failed to start daemon with error: `%s'\n", emsg);
417       return;
418     }
419   GNUNET_assert (id != NULL);
420
421 #if VERBOSE > 1
422   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
423       (num_peers - peers_left) + 1, num_peers);
424 #endif
425
426   pg_start_ctx->peers_left--;
427
428   if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
429     {
430 #if VERBOSE
431       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432           "All %d daemons started, now connecting peers!\n",
433           num_peers);
434 #endif
435       GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
436       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
437
438       pg_start_ctx->expected_connections = UINT_MAX;
439       if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
440         {
441           pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
442           pg_start_ctx->expected_connections
443               = GNUNET_TESTING_connect_topology (
444                                                  pg_start_ctx->pg,
445                                                  pg_start_ctx->connect_topology,
446                                                  pg_start_ctx->connect_topology_option,
447                                                  pg_start_ctx->connect_topology_option_modifier,
448                                                  DEFAULT_CONNECT_TIMEOUT,
449                                                  DEFAULT_CONNECT_ATTEMPTS,
450                                                  NULL, NULL);
451
452           pg_start_ctx->connect_meter
453               = create_meter (pg_start_ctx->expected_connections,
454                               "Peer connection ", pg_start_ctx->verbose);
455           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
456                       "Have %d expected connections\n",
457                       pg_start_ctx->expected_connections);
458         }
459
460       if (pg_start_ctx->expected_connections == 0)
461         {
462           GNUNET_free_non_null(pg_start_ctx->fail_reason);
463           pg_start_ctx->fail_reason = GNUNET_strdup("from connect topology (bad return)");
464           pg_start_ctx->die_task
465               = GNUNET_SCHEDULER_add_now (&end_badly,
466                                           pg_start_ctx);
467         }
468
469       GNUNET_free_non_null(pg_start_ctx->fail_reason);
470       pg_start_ctx->fail_reason = GNUNET_strdup("from connect topology (timeout)");
471       pg_start_ctx->die_task
472           = GNUNET_SCHEDULER_add_delayed (
473                                           GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout),
474                                           &end_badly,
475                                           pg_start_ctx);
476     }
477 }
478
479 /**
480  * Callback indicating that the hostkey was created for a peer.
481  *
482  * @param cls NULL
483  * @param id the peer identity
484  * @param d the daemon handle (pretty useless at this point, remove?)
485  * @param emsg non-null on failure
486  */
487 static void
488 internal_hostkey_callback(void *cls, const struct GNUNET_PeerIdentity *id,
489                           struct GNUNET_TESTING_Daemon *d, const char *emsg)
490 {
491   struct PeerGroupStartupContext *pg_start_ctx = cls;
492   unsigned int create_expected_connections;
493
494   if (emsg != NULL)
495     {
496       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
497                   "Hostkey callback received error: %s\n", emsg);
498     }
499
500 #if VERBOSE > 1
501   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
502       "Hostkey (%d/%d) created for peer `%s'\n",
503       num_peers - peers_left, num_peers, GNUNET_i2s(id));
504 #endif
505
506   pg_start_ctx->peers_left--;
507   if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
508     {
509       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
510                   "All %d hostkeys created, now creating topology!\n",
511                   pg_start_ctx->total);
512       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
513       /* Set up task in case topology creation doesn't finish
514        * within a reasonable amount of time */
515       pg_start_ctx->die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
516                                                              &end_badly,
517                                                              "from create_topology");
518       pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */
519       create_expected_connections = GNUNET_TESTING_create_topology (pg_start_ctx->pg, pg_start_ctx->topology, pg_start_ctx->restrict_topology,
520                                                                     pg_start_ctx->restrict_transports);
521       if (create_expected_connections > 0)
522         {
523           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
524                       "Topology set up, have %u expected connections, now starting peers!\n", create_expected_connections);
525           GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg);
526         }
527       else
528         {
529           GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
530           pg_start_ctx->die_task = GNUNET_SCHEDULER_add_now (&end_badly,
531                                                "from create topology (bad return)");
532         }
533
534       GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
535       pg_start_ctx->die_task
536           = GNUNET_SCHEDULER_add_delayed (
537                                           GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
538                                           &end_badly,
539                                           "from continue startup (timeout)");
540     }
541 }
542
543
544 /**
545  * Start a peer group with a given number of peers.  Notify
546  * on completion of peer startup and connection based on given
547  * topological constraints.  Optionally notify on each
548  * established connection.
549  *
550  * @param cfg configuration template to use
551  * @param total number of daemons to start
552  * @param max_concurrent_connections for testing, how many peers can
553 *                                   we connect to simultaneously
554  * @param max_concurrent_ssh when starting with ssh, how many ssh
555  *        connections will we allow at once (based on remote hosts allowed!)
556  * @param timeout total time allowed for peers to start
557  * @param connect_cb function to call each time two daemons are connected
558  * @param connect_cb_cls closure for connect_callback
559  * @param peergroup_cb function to call once all peers are up and connected
560  * @param peergroup_cb_cls closure for peergroup_cb
561  * @param hostnames linked list of host structs to use to start peers on
562  *                  (NULL to run on localhost only)
563  * @param topology allowed overlay topology
564  * @param restrict_topology blacklist connections to this topology
565  * @param restrict_transports specific transports to blacklist
566  * @param connect_topology topology to connect peers in (defaults to allowed
567  *        topology)
568  * @param connect_topology_options options for connect topology
569  * @param connect_topology_option_modifier option modifier for connect topology
570  * @param verbose GNUNET_YES to print progress bars, GNUNET_NO otherwise
571  *
572  * @return NULL on error, otherwise handle to control peer group
573  */
574 struct GNUNET_TESTING_PeerGroup *
575 GNUNET_TESTING_PeerGroup_start(
576                                const struct GNUNET_CONFIGURATION_Handle *cfg,
577                                unsigned int total,
578                                unsigned int max_concurrent_connections,
579                                unsigned int max_concurrent_ssh,
580                                struct GNUNET_TIME_Relative timeout,
581                                GNUNET_TESTING_NotifyConnection connect_cb,
582                                void *connect_cb_cls,
583                                GNUNET_TESTING_NotifyCompletion peergroup_cb,
584                                void *peergroup_cb_cls,
585                                const struct GNUNET_TESTING_Host *hostnames,
586                                enum GNUNET_TESTING_Topology topology,
587                                enum GNUNET_TESTING_Topology restrict_topology,
588                                const char *restrict_transports,
589                                enum GNUNET_TESTING_Topology connect_topology,
590                                enum GNUNET_TESTING_TopologyOption connect_topology_options,
591                                double connect_topology_option_modifier, int verbose)
592 {
593   struct PeerGroupStartupContext *pg_start_ctx;
594
595   GNUNET_assert(total > 0);
596   GNUNET_assert(cfg != NULL);
597
598   pg_start_ctx = GNUNET_malloc(sizeof(struct PeerGroupStartupContext));
599   pg_start_ctx->cfg = cfg;
600   pg_start_ctx->total = total;
601   pg_start_ctx->peers_left = total;
602   pg_start_ctx->max_concurrent_connections = max_concurrent_connections;
603   pg_start_ctx->max_concurrent_ssh = max_concurrent_ssh;
604   pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute(timeout);
605   pg_start_ctx->connect_cb = connect_cb_cls;
606   pg_start_ctx->peergroup_cb = peergroup_cb;
607   pg_start_ctx->peergroup_cb_cls = peergroup_cb_cls;
608   pg_start_ctx->hostnames = hostnames;
609   pg_start_ctx->topology = topology;
610   pg_start_ctx->restrict_topology = restrict_topology;
611   pg_start_ctx->restrict_transports = restrict_transports;
612   pg_start_ctx->connect_topology = connect_topology;
613   pg_start_ctx->connect_topology_option = connect_topology_options;
614   pg_start_ctx->connect_topology_option_modifier = connect_topology_option_modifier;
615   pg_start_ctx->verbose = verbose;
616   pg_start_ctx->hostkey_meter = create_meter (pg_start_ctx->peers_left, "Hostkeys created ", pg_start_ctx->verbose);
617   pg_start_ctx->peer_start_meter = create_meter (pg_start_ctx->peers_left, "Peers started ", pg_start_ctx->verbose);
618   /* Make compilers happy */
619   reset_meter(pg_start_ctx->peer_start_meter);
620   pg_start_ctx->die_task
621       = GNUNET_SCHEDULER_add_delayed (
622                                       GNUNET_TIME_absolute_get_remaining (
623                                                                           pg_start_ctx->timeout),
624                                       &end_badly,
625                                       "didn't generate all hostkeys within allowed startup time!");
626
627   pg_start_ctx->pg
628       = GNUNET_TESTING_daemons_start (
629                                       pg_start_ctx->cfg,
630                                       pg_start_ctx->peers_left,
631                                       pg_start_ctx->max_concurrent_connections,
632                                       pg_start_ctx->max_concurrent_ssh,
633                                       GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
634                                       &internal_hostkey_callback, pg_start_ctx,
635                                       &internal_peers_started_callback,
636                                       pg_start_ctx,
637                                       &internal_topology_callback,
638                                       pg_start_ctx, pg_start_ctx->hostnames);
639
640   return pg_start_ctx->pg;
641 }
642
643
644 /* end of testing_peergroup.c */