2 This file is part of GNUnet
3 (C) 2008-2011 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @file testing/testing_peergroup.c
23 * @brief API implementation for easy peer group creation
24 * @author Nathan Evans
25 * @author Christian Grothoff
29 #include "gnunet_constants.h"
30 #include "gnunet_arm_service.h"
31 #include "gnunet_testing_lib.h"
32 #include "gnunet_core_service.h"
35 #define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
37 #define DEFAULT_CONNECT_ATTEMPTS 2
39 /** Struct definitions **/
41 struct PeerGroupStartupContext
43 struct GNUNET_TESTING_PeerGroup *pg;
44 const struct GNUNET_CONFIGURATION_Handle *cfg;
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;
53 GNUNET_TESTING_NotifyCompletion peergroup_cb;
54 void *peergroup_cb_cls;
55 const struct GNUNET_TESTING_Host *hostnames;
56 enum GNUNET_TESTING_Topology topology;
58 float topology_percentage;
60 float topology_probability;
62 enum GNUNET_TESTING_Topology restrict_topology;
63 char *restrict_transports;
64 enum GNUNET_TESTING_Topology connect_topology;
65 enum GNUNET_TESTING_TopologyOption connect_topology_option;
66 double connect_topology_option_modifier;
69 struct ProgressMeter *hostkey_meter;
70 struct ProgressMeter *peer_start_meter;
71 struct ProgressMeter *connect_meter;
74 * Task used to kill the peergroup.
76 GNUNET_SCHEDULER_TaskIdentifier die_task;
81 * Variable used to store the number of connections we should wait for.
83 unsigned int expected_connections;
86 * Time when the connecting peers was started.
88 struct GNUNET_TIME_Absolute connect_start_time;
91 * The total number of connections that have been created so far.
93 unsigned int total_connections;
96 * The total number of connections that have failed so far.
98 unsigned int failed_connections;
102 * Simple struct to keep track of progress, and print a
103 * percentage meter for long running tasks.
108 * Total number of tasks to complete.
113 * Print percentage done after modnum tasks.
118 * Print a . each dotnum tasks.
123 * Total number completed thus far.
125 unsigned int completed;
128 * Whether or not to print.
133 * Startup string for progress meter.
135 char *startup_string;
139 /** Utility functions **/
142 * Create a meter to keep track of the progress of some task.
144 * @param total the total number of items to complete
145 * @param start_string a string to prefix the meter with (if printing)
146 * @param print GNUNET_YES to print the meter, GNUNET_NO to count
149 * @return the progress meter
151 static struct ProgressMeter *
152 create_meter(unsigned int total, char * start_string, int print)
154 struct ProgressMeter *ret;
155 ret = GNUNET_malloc(sizeof(struct ProgressMeter));
158 ret->modnum = total / 4;
159 ret->dotnum = (total / 50) + 1;
160 if (start_string != NULL)
161 ret->startup_string = GNUNET_strdup(start_string);
163 ret->startup_string = GNUNET_strdup("");
169 * Update progress meter (increment by one).
171 * @param meter the meter to update and print info for
173 * @return GNUNET_YES if called the total requested,
174 * GNUNET_NO if more items expected
177 update_meter(struct ProgressMeter *meter)
179 if (meter->print == GNUNET_YES)
181 if (meter->completed % meter->modnum == 0)
183 if (meter->completed == 0)
185 fprintf (stdout, "%sProgress: [0%%", meter->startup_string);
188 fprintf (stdout, "%d%%", (int) (((float) meter->completed
189 / meter->total) * 100));
191 else if (meter->completed % meter->dotnum == 0)
192 fprintf (stdout, ".");
194 if (meter->completed + 1 == meter->total)
195 fprintf (stdout, "%d%%]\n", 100);
200 if (meter->completed == meter->total)
206 * Reset progress meter.
208 * @param meter the meter to reset
210 * @return GNUNET_YES if meter reset,
211 * GNUNET_SYSERR on error
214 reset_meter(struct ProgressMeter *meter)
217 return GNUNET_SYSERR;
219 meter->completed = 0;
224 * Release resources for meter
226 * @param meter the meter to free
229 free_meter(struct ProgressMeter *meter)
231 GNUNET_free_non_null (meter->startup_string);
236 /** Functions for creating, starting and connecting the peergroup **/
239 * Check whether peers successfully shut down.
242 internal_shutdown_callback(void *cls, const char *emsg)
244 struct PeerGroupStartupContext *pg_start_ctx = cls;
246 pg_start_ctx->peergroup_cb(pg_start_ctx->peergroup_cb_cls, emsg);
248 pg_start_ctx->peergroup_cb(pg_start_ctx->peergroup_cb_cls, pg_start_ctx->fail_reason);
252 * Check if the get_handle is being used, if so stop the request. Either
253 * way, schedule the end_badly_cont function which actually shuts down the
257 end_badly(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
259 struct PeerGroupStartupContext *pg_start_ctx = cls;
260 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failing peer group startup with error: `%s'!\n",
261 pg_start_ctx->fail_reason);
263 GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout), &internal_shutdown_callback, pg_start_ctx);
265 if (pg_start_ctx->hostkey_meter != NULL)
266 free_meter (pg_start_ctx->hostkey_meter);
267 if (pg_start_ctx->peer_start_meter != NULL)
268 free_meter (pg_start_ctx->peer_start_meter);
269 if (pg_start_ctx->connect_meter != NULL)
270 free_meter (pg_start_ctx->connect_meter);
274 * This function is called whenever a connection attempt is finished between two of
275 * the started peers (started with GNUNET_TESTING_daemons_start). The total
276 * number of times this function is called should equal the number returned
277 * from the GNUNET_TESTING_connect_topology call.
279 * The emsg variable is NULL on success (peers connected), and non-NULL on
280 * failure (peers failed to connect).
283 internal_topology_callback(
285 const struct GNUNET_PeerIdentity *first,
286 const struct GNUNET_PeerIdentity *second,
288 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
289 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
290 struct GNUNET_TESTING_Daemon *first_daemon,
291 struct GNUNET_TESTING_Daemon *second_daemon,
294 struct PeerGroupStartupContext *pg_start_ctx = cls;
296 unsigned long long duration;
297 unsigned long long total_duration;
298 unsigned int new_connections;
299 unsigned int new_failed_connections;
300 double conns_per_sec_recent;
301 double conns_per_sec_total;
302 double failed_conns_per_sec_recent;
303 double failed_conns_per_sec_total;
307 if (GNUNET_TIME_absolute_get_difference (connect_last_time,
308 GNUNET_TIME_absolute_get ()).rel_value
309 > GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
310 CONN_UPDATE_DURATION).rel_value)
312 /* Get number of new connections */
313 new_connections = total_connections - previous_connections;
315 /* Get number of new FAILED connections */
316 new_failed_connections = failed_connections - previous_failed_connections;
318 /* Get duration in seconds */
320 = GNUNET_TIME_absolute_get_difference (connect_last_time,
321 GNUNET_TIME_absolute_get ()).rel_value
324 = GNUNET_TIME_absolute_get_difference (connect_start_time,
325 GNUNET_TIME_absolute_get ()).rel_value
328 failed_conns_per_sec_recent = (double) new_failed_connections / duration;
329 failed_conns_per_sec_total = (double) failed_connections / total_duration;
330 conns_per_sec_recent = (double) new_connections / duration;
331 conns_per_sec_total = (double) total_connections / total_duration;
333 GNUNET_ERROR_TYPE_WARNING,
334 "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n",
335 conns_per_sec_recent, CONN_UPDATE_DURATION,
336 conns_per_sec_total, failed_conns_per_sec_recent,
337 failed_conns_per_sec_total);
338 connect_last_time = GNUNET_TIME_absolute_get ();
339 previous_connections = total_connections;
340 previous_failed_connections = failed_connections;
341 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
342 "have %u total_connections, %u failed\n", total_connections,
350 pg_start_ctx->total_connections++;
352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
353 first_daemon->shortname,
354 second_daemon->shortname,
360 pg_start_ctx->failed_connections++;
362 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to connect peer %s to peer %s with error :\n%s\n",
363 first_daemon->shortname,
364 second_daemon->shortname, emsg);
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to connect peer %s to peer %s with error :\n%s\n",
367 first_daemon->shortname,
368 second_daemon->shortname, emsg);
372 GNUNET_assert(pg_start_ctx->connect_meter != NULL);
373 if (pg_start_ctx->connect_cb != NULL)
374 pg_start_ctx->connect_cb(pg_start_ctx->connect_cb_cls, first,
382 if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter))
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
392 = GNUNET_TIME_absolute_get_difference (connect_start_time,
393 GNUNET_TIME_absolute_get ()).rel_value
395 failed_conns_per_sec_total = (double) failed_connections / total_duration;
396 conns_per_sec_total = (double) total_connections / total_duration;
397 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
398 "Overall connection info --- Total: %u, Total Failed %u/s\n",
399 total_connections, failed_connections);
401 GNUNET_ERROR_TYPE_WARNING,
402 "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
403 conns_per_sec_total, failed_conns_per_sec_total);
406 GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
407 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
409 /* Call final callback, signifying that the peer group has been started and connected */
410 if (pg_start_ctx->peergroup_cb != NULL)
411 pg_start_ctx->peergroup_cb(pg_start_ctx->peergroup_cb_cls, NULL);
416 internal_peers_started_callback(void *cls, const struct GNUNET_PeerIdentity *id,
417 const struct GNUNET_CONFIGURATION_Handle *cfg,
418 struct GNUNET_TESTING_Daemon *d, const char *emsg)
420 struct PeerGroupStartupContext *pg_start_ctx = cls;
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "Failed to start daemon with error: `%s'\n", emsg);
427 GNUNET_assert (id != NULL);
430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
431 (num_peers - peers_left) + 1, num_peers);
434 pg_start_ctx->peers_left--;
436 if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "All %d daemons started, now connecting peers!\n",
443 GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
444 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
446 pg_start_ctx->expected_connections = UINT_MAX;
447 if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
449 pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
450 pg_start_ctx->expected_connections
451 = GNUNET_TESTING_connect_topology (
453 pg_start_ctx->connect_topology,
454 pg_start_ctx->connect_topology_option,
455 pg_start_ctx->connect_topology_option_modifier,
456 DEFAULT_CONNECT_TIMEOUT,
457 pg_start_ctx->connect_attempts,
460 pg_start_ctx->connect_meter
461 = create_meter (pg_start_ctx->expected_connections,
462 "Peer connection ", pg_start_ctx->verbose);
463 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
464 "Have %d expected connections\n",
465 pg_start_ctx->expected_connections);
468 if (pg_start_ctx->expected_connections == 0)
470 GNUNET_free_non_null(pg_start_ctx->fail_reason);
471 pg_start_ctx->fail_reason = GNUNET_strdup("from connect topology (bad return)");
472 pg_start_ctx->die_task
473 = GNUNET_SCHEDULER_add_now (&end_badly,
477 GNUNET_free_non_null(pg_start_ctx->fail_reason);
478 pg_start_ctx->fail_reason = GNUNET_strdup("from connect topology (timeout)");
479 pg_start_ctx->die_task
480 = GNUNET_SCHEDULER_add_delayed (
481 GNUNET_TIME_absolute_get_remaining (pg_start_ctx->timeout),
488 * Callback indicating that the hostkey was created for a peer.
491 * @param id the peer identity
492 * @param d the daemon handle (pretty useless at this point, remove?)
493 * @param emsg non-null on failure
496 internal_hostkey_callback(void *cls, const struct GNUNET_PeerIdentity *id,
497 struct GNUNET_TESTING_Daemon *d, const char *emsg)
499 struct PeerGroupStartupContext *pg_start_ctx = cls;
500 unsigned int create_expected_connections;
504 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
505 "Hostkey callback received error: %s\n", emsg);
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "Hostkey (%d/%d) created for peer `%s'\n",
511 num_peers - peers_left, num_peers, GNUNET_i2s(id));
514 pg_start_ctx->peers_left--;
515 if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
517 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
518 /* Set up task in case topology creation doesn't finish
519 * within a reasonable amount of time */
520 pg_start_ctx->die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
522 "from create_topology");
523 pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */
524 create_expected_connections = GNUNET_TESTING_create_topology (pg_start_ctx->pg, pg_start_ctx->topology, pg_start_ctx->restrict_topology,
525 pg_start_ctx->restrict_transports);
526 if (create_expected_connections > 0)
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Topology set up, have %u expected connections, now starting peers!\n", create_expected_connections);
530 GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg);
534 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
535 pg_start_ctx->die_task = GNUNET_SCHEDULER_add_now (&end_badly,
536 "from create topology (bad return)");
539 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
540 pg_start_ctx->die_task
541 = GNUNET_SCHEDULER_add_delayed (
542 GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
544 "from continue startup (timeout)");
550 * Start a peer group with a given number of peers. Notify
551 * on completion of peer startup and connection based on given
552 * topological constraints. Optionally notify on each
553 * established connection.
555 * @param cfg configuration template to use
556 * @param total number of daemons to start
557 * @param timeout total time allowed for peers to start
558 * @param connect_cb function to call each time two daemons are connected
559 * @param connect_cb_cls closure for connect_callback
560 * @param peergroup_cb function to call once all peers are up and connected
561 * @param peergroup_cb_cls closure for peergroup_cb
562 * @param hostnames linked list of host structs to use to start peers on
563 * (NULL to run on localhost only)
564 * @param verbose GNUNET_YES to print progress bars, GNUNET_NO otherwise
566 * @return NULL on error, otherwise handle to control peer group
568 struct GNUNET_TESTING_PeerGroup *
569 GNUNET_TESTING_peergroup_start(
570 const struct GNUNET_CONFIGURATION_Handle *cfg,
572 struct GNUNET_TIME_Relative timeout,
573 GNUNET_TESTING_NotifyConnection connect_cb,
574 void *connect_cb_cls,
575 GNUNET_TESTING_NotifyCompletion peergroup_cb,
576 void *peergroup_cb_cls,
577 const struct GNUNET_TESTING_Host *hostnames,
580 struct PeerGroupStartupContext *pg_start_ctx;
581 unsigned long long temp_config_number;
583 GNUNET_assert(total > 0);
584 GNUNET_assert(cfg != NULL);
586 pg_start_ctx = GNUNET_malloc(sizeof(struct PeerGroupStartupContext));
588 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
590 &pg_start_ctx->connect_attempts))
592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
593 "testing", "connect_attempts");
594 GNUNET_free(pg_start_ctx);
599 != GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
600 "max_outstanding_connections",
601 &pg_start_ctx->max_concurrent_connections))
603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
604 "testing", "max_outstanding_connections");
605 GNUNET_free(pg_start_ctx);
609 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
610 "max_concurrent_ssh",
611 &pg_start_ctx->max_concurrent_ssh))
613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
614 "testing", "max_concurrent_ssh");
615 GNUNET_free(pg_start_ctx);
619 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
621 &temp_config_number))
622 pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute(GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
623 temp_config_number));
626 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
627 "testing", "peergroup_timeout");
628 GNUNET_free(pg_start_ctx);
633 /* Read topology related options from the configuration file */
635 if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
638 && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str)))
640 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
641 "Invalid topology `%s' given for section %s option %s\n",
642 temp_str, "TESTING", "TOPOLOGY");
643 pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
645 GNUNET_free_non_null(temp_str);
648 != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
650 pg_start_ctx->topology_percentage = 0.5;
653 pg_start_ctx->topology_percentage = atof (temp_str);
654 GNUNET_free(temp_str);
658 != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
660 pg_start_ctx->topology_probability = 0.5;
663 pg_start_ctx->topology_probability = atof (temp_str);
664 GNUNET_free(temp_str);
668 == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
671 && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology,
675 GNUNET_ERROR_TYPE_WARNING,
676 "Invalid connect topology `%s' given for section %s option %s\n",
677 temp_str, "TESTING", "CONNECT_TOPOLOGY");
679 GNUNET_free_non_null(temp_str);
682 == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
683 "connect_topology_option",
686 == GNUNET_TESTING_topology_option_get (&pg_start_ctx->connect_topology_option,
690 GNUNET_ERROR_TYPE_WARNING,
691 "Invalid connect topology option `%s' given for section %s option %s\n",
693 "CONNECT_TOPOLOGY_OPTION");
694 pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
696 GNUNET_free_non_null(temp_str);
699 == GNUNET_CONFIGURATION_get_value_string (
702 "connect_topology_option_modifier",
705 if (sscanf (temp_str, "%lf",
706 &pg_start_ctx->connect_topology_option_modifier) != 1)
709 GNUNET_ERROR_TYPE_WARNING,
710 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
712 "connect_topology_option_modifier", "TESTING");
713 GNUNET_free (temp_str);
714 GNUNET_free(pg_start_ctx);
717 GNUNET_free (temp_str);
721 != GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
722 "blacklist_transports",
723 &pg_start_ctx->restrict_transports))
724 pg_start_ctx->restrict_transports = NULL;
727 == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
728 "blacklist_topology",
730 && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology,
733 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
734 "Invalid topology `%s' given for section %s option %s\n",
735 temp_str, "TESTING", "BLACKLIST_TOPOLOGY");
737 GNUNET_free_non_null(temp_str);
739 pg_start_ctx->cfg = cfg;
740 pg_start_ctx->total = total;
741 pg_start_ctx->peers_left = total;
742 pg_start_ctx->connect_cb = connect_cb_cls;
743 pg_start_ctx->peergroup_cb = peergroup_cb;
744 pg_start_ctx->peergroup_cb_cls = peergroup_cb_cls;
745 pg_start_ctx->hostnames = hostnames;
746 pg_start_ctx->verbose = verbose;
747 pg_start_ctx->hostkey_meter = create_meter (pg_start_ctx->peers_left, "Hostkeys created ", pg_start_ctx->verbose);
748 pg_start_ctx->peer_start_meter = create_meter (pg_start_ctx->peers_left, "Peers started ", pg_start_ctx->verbose);
749 /* Make compilers happy */
750 reset_meter(pg_start_ctx->peer_start_meter);
751 pg_start_ctx->die_task
752 = GNUNET_SCHEDULER_add_delayed (
753 GNUNET_TIME_absolute_get_remaining (
754 pg_start_ctx->timeout),
756 "didn't generate all hostkeys within allowed startup time!");
759 = GNUNET_TESTING_daemons_start (
761 pg_start_ctx->peers_left,
762 pg_start_ctx->max_concurrent_connections,
763 pg_start_ctx->max_concurrent_ssh,
764 GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout),
765 &internal_hostkey_callback, pg_start_ctx,
766 &internal_peers_started_callback,
768 &internal_topology_callback,
769 pg_start_ctx, pg_start_ctx->hostnames);
771 return pg_start_ctx->pg;
774 /* end of testing_peergroup.c */