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;
52 GNUNET_TESTING_NotifyCompletion peergroup_cb;
55 * Closure for all peergroup callbacks.
59 const struct GNUNET_TESTING_Host *hostnames;
60 enum GNUNET_TESTING_Topology topology;
62 float topology_percentage;
64 float topology_probability;
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;
73 struct ProgressMeter *hostkey_meter;
74 struct ProgressMeter *peer_start_meter;
75 struct ProgressMeter *connect_meter;
78 * Task used to kill the peergroup.
80 GNUNET_SCHEDULER_TaskIdentifier die_task;
85 * Variable used to store the number of connections we should wait for.
87 unsigned int expected_connections;
90 * Time when the connecting peers was started.
92 struct GNUNET_TIME_Absolute connect_start_time;
95 * The total number of connections that have been created so far.
97 unsigned int total_connections;
100 * The total number of connections that have failed so far.
102 unsigned int failed_connections;
106 * Simple struct to keep track of progress, and print a
107 * percentage meter for long running tasks.
112 * Total number of tasks to complete.
117 * Print percentage done after modnum tasks.
122 * Print a . each dotnum tasks.
127 * Total number completed thus far.
129 unsigned int completed;
132 * Whether or not to print.
137 * Startup string for progress meter.
139 char *startup_string;
143 /** Utility functions **/
146 * Create a meter to keep track of the progress of some task.
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
153 * @return the progress meter
155 static struct ProgressMeter *
156 create_meter(unsigned int total, char * start_string, int print)
158 struct ProgressMeter *ret;
159 ret = GNUNET_malloc(sizeof(struct ProgressMeter));
162 ret->modnum = total / 4;
163 ret->dotnum = (total / 50) + 1;
164 if (start_string != NULL)
165 ret->startup_string = GNUNET_strdup(start_string);
167 ret->startup_string = GNUNET_strdup("");
173 * Update progress meter (increment by one).
175 * @param meter the meter to update and print info for
177 * @return GNUNET_YES if called the total requested,
178 * GNUNET_NO if more items expected
181 update_meter(struct ProgressMeter *meter)
183 if (meter->print == GNUNET_YES)
185 if (meter->completed % meter->modnum == 0)
187 if (meter->completed == 0)
189 fprintf (stdout, "%sProgress: [0%%", meter->startup_string);
192 fprintf (stdout, "%d%%", (int) (((float) meter->completed
193 / meter->total) * 100));
195 else if (meter->completed % meter->dotnum == 0)
196 fprintf (stdout, ".");
198 if (meter->completed + 1 == meter->total)
199 fprintf (stdout, "%d%%]\n", 100);
204 if (meter->completed == meter->total)
210 * Reset progress meter.
212 * @param meter the meter to reset
214 * @return GNUNET_YES if meter reset,
215 * GNUNET_SYSERR on error
218 reset_meter(struct ProgressMeter *meter)
221 return GNUNET_SYSERR;
223 meter->completed = 0;
228 * Release resources for meter
230 * @param meter the meter to free
233 free_meter(struct ProgressMeter *meter)
235 GNUNET_free_non_null (meter->startup_string);
240 /** Functions for creating, starting and connecting the peergroup **/
243 * Check whether peers successfully shut down.
246 internal_shutdown_callback(void *cls, const char *emsg)
248 struct PeerGroupStartupContext *pg_start_ctx = cls;
250 pg_start_ctx->peergroup_cb(pg_start_ctx->cls, emsg);
252 pg_start_ctx->peergroup_cb(pg_start_ctx->cls, pg_start_ctx->fail_reason);
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
261 end_badly(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
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);
267 GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, GNUNET_TIME_absolute_get_remaining(pg_start_ctx->timeout), &internal_shutdown_callback, pg_start_ctx);
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);
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.
283 * The emsg variable is NULL on success (peers connected), and non-NULL on
284 * failure (peers failed to connect).
287 internal_topology_callback(
289 const struct GNUNET_PeerIdentity *first,
290 const struct GNUNET_PeerIdentity *second,
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,
298 struct PeerGroupStartupContext *pg_start_ctx = cls;
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;
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)
316 /* Get number of new connections */
317 new_connections = total_connections - previous_connections;
319 /* Get number of new FAILED connections */
320 new_failed_connections = failed_connections - previous_failed_connections;
322 /* Get duration in seconds */
324 = GNUNET_TIME_absolute_get_difference (connect_last_time,
325 GNUNET_TIME_absolute_get ()).rel_value
328 = GNUNET_TIME_absolute_get_difference (connect_start_time,
329 GNUNET_TIME_absolute_get ()).rel_value
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;
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,
354 pg_start_ctx->total_connections++;
356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s, distance %u\n",
357 first_daemon->shortname,
358 second_daemon->shortname,
364 pg_start_ctx->failed_connections++;
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);
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);
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,
386 if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter))
389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
396 = GNUNET_TIME_absolute_get_difference (connect_start_time,
397 GNUNET_TIME_absolute_get ()).rel_value
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);
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);
410 GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
411 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
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);
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)
424 struct PeerGroupStartupContext *pg_start_ctx = cls;
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "Failed to start daemon with error: `%s'\n", emsg);
431 GNUNET_assert (id != NULL);
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
435 (num_peers - peers_left) + 1, num_peers);
438 pg_start_ctx->peers_left--;
440 if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "All %d daemons started, now connecting peers!\n",
447 GNUNET_assert(pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
448 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
450 pg_start_ctx->expected_connections = UINT_MAX;
451 if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
453 pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
454 pg_start_ctx->expected_connections
455 = GNUNET_TESTING_connect_topology (
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,
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);
472 if (pg_start_ctx->expected_connections == 0)
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,
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),
492 * Callback indicating that the hostkey was created for a peer.
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
500 internal_hostkey_callback(void *cls, const struct GNUNET_PeerIdentity *id,
501 struct GNUNET_TESTING_Daemon *d, const char *emsg)
503 struct PeerGroupStartupContext *pg_start_ctx = cls;
504 unsigned int create_expected_connections;
508 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
509 "Hostkey callback received error: %s\n", emsg);
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));
518 pg_start_ctx->peers_left--;
519 if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
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),
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)
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);
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)");
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),
548 "from continue startup (timeout)");
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.
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)
568 * @return NULL on error, otherwise handle to control peer group
570 struct GNUNET_TESTING_PeerGroup *
571 GNUNET_TESTING_peergroup_start(
572 const struct GNUNET_CONFIGURATION_Handle *cfg,
574 struct GNUNET_TIME_Relative timeout,
575 GNUNET_TESTING_NotifyConnection connect_cb,
576 GNUNET_TESTING_NotifyCompletion peergroup_cb,
578 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_SYSERR == (pg_start_ctx->verbose = GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing",
620 "use_progressbars")))
622 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
623 "testing", "use_progressbars");
624 GNUNET_free(pg_start_ctx);
628 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
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));
635 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
636 "testing", "peergroup_timeout");
637 GNUNET_free(pg_start_ctx);
642 /* Read topology related options from the configuration file */
644 if ((GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
647 && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str)))
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 */
654 GNUNET_free_non_null(temp_str);
657 != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
659 pg_start_ctx->topology_percentage = 0.5;
662 pg_start_ctx->topology_percentage = atof (temp_str);
663 GNUNET_free(temp_str);
667 != GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
669 pg_start_ctx->topology_probability = 0.5;
672 pg_start_ctx->topology_probability = atof (temp_str);
673 GNUNET_free(temp_str);
677 == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
680 && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology,
684 GNUNET_ERROR_TYPE_WARNING,
685 "Invalid connect topology `%s' given for section %s option %s\n",
686 temp_str, "TESTING", "CONNECT_TOPOLOGY");
688 GNUNET_free_non_null(temp_str);
691 == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
692 "connect_topology_option",
695 == GNUNET_TESTING_topology_option_get (&pg_start_ctx->connect_topology_option,
699 GNUNET_ERROR_TYPE_WARNING,
700 "Invalid connect topology option `%s' given for section %s option %s\n",
702 "CONNECT_TOPOLOGY_OPTION");
703 pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
705 GNUNET_free_non_null(temp_str);
708 == GNUNET_CONFIGURATION_get_value_string (
711 "connect_topology_option_modifier",
714 if (sscanf (temp_str, "%lf",
715 &pg_start_ctx->connect_topology_option_modifier) != 1)
718 GNUNET_ERROR_TYPE_WARNING,
719 _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
721 "connect_topology_option_modifier", "TESTING");
722 GNUNET_free (temp_str);
723 GNUNET_free(pg_start_ctx);
726 GNUNET_free (temp_str);
730 != GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
731 "blacklist_transports",
732 &pg_start_ctx->restrict_transports))
733 pg_start_ctx->restrict_transports = NULL;
736 == GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
737 "blacklist_topology",
739 && (GNUNET_NO == GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology,
742 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
743 "Invalid topology `%s' given for section %s option %s\n",
744 temp_str, "TESTING", "BLACKLIST_TOPOLOGY");
746 GNUNET_free_non_null(temp_str);
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),
764 "didn't generate all hostkeys within allowed startup time!");
767 = GNUNET_TESTING_daemons_start (
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,
776 &internal_topology_callback,
777 pg_start_ctx, pg_start_ctx->hostnames);
779 return pg_start_ctx->pg;
782 /* end of testing_peergroup.c */