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"
33 #include "gnunet_disk_lib.h"
36 #define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38 #define DEFAULT_CONNECT_ATTEMPTS 2
40 /** Struct definitions **/
42 struct PeerGroupStartupContext
44 struct GNUNET_TESTING_PeerGroup *pg;
45 const struct GNUNET_CONFIGURATION_Handle *cfg;
47 unsigned int peers_left;
48 unsigned long long max_concurrent_connections;
51 * Maximum attemps to connect two daemons.
53 unsigned long long connect_attempts;
56 * How long to spend trying to establish all the connections?
58 struct GNUNET_TIME_Relative connect_timeout;
60 unsigned long long max_concurrent_ssh;
61 struct GNUNET_TIME_Absolute timeout;
62 GNUNET_TESTING_NotifyConnection connect_cb;
63 GNUNET_TESTING_NotifyCompletion peergroup_cb;
66 * Closure for all peergroup callbacks.
70 const struct GNUNET_TESTING_Host *hostnames;
75 enum GNUNET_TESTING_Topology topology;
77 float topology_percentage;
79 float topology_probability;
84 enum GNUNET_TESTING_Topology restrict_topology;
89 char *restrict_transports;
94 enum GNUNET_TESTING_Topology connect_topology;
95 enum GNUNET_TESTING_TopologyOption connect_topology_option;
96 double connect_topology_option_modifier;
99 struct ProgressMeter *hostkey_meter;
100 struct ProgressMeter *peer_start_meter;
101 struct ProgressMeter *connect_meter;
104 * Task used to kill the peergroup.
106 GNUNET_SCHEDULER_TaskIdentifier die_task;
111 * Variable used to store the number of connections we should wait for.
113 unsigned int expected_connections;
116 * Time when the connecting peers was started.
118 struct GNUNET_TIME_Absolute connect_start_time;
121 * The total number of connections that have been created so far.
123 unsigned int total_connections;
126 * The total number of connections that have failed so far.
128 unsigned int failed_connections;
131 * File handle to write out topology in dot format.
133 struct GNUNET_DISK_FileHandle *topology_output_file;
136 struct TopologyOutputContext
138 struct GNUNET_DISK_FileHandle *file;
139 GNUNET_TESTING_NotifyCompletion notify_cb;
144 * Simple struct to keep track of progress, and print a
145 * percentage meter for long running tasks.
150 * Total number of tasks to complete.
155 * Print percentage done after modnum tasks.
160 * Print a . each dotnum tasks.
165 * Total number completed thus far.
167 unsigned int completed;
170 * Whether or not to print.
175 * Startup string for progress meter.
177 char *startup_string;
181 /** Utility functions **/
184 * Create a meter to keep track of the progress of some task.
186 * @param total the total number of items to complete
187 * @param start_string a string to prefix the meter with (if printing)
188 * @param print GNUNET_YES to print the meter, GNUNET_NO to count
191 * @return the progress meter
193 static struct ProgressMeter *
194 create_meter (unsigned int total, char *start_string, int print)
196 struct ProgressMeter *ret;
198 ret = GNUNET_malloc (sizeof (struct ProgressMeter));
201 ret->modnum = (total / 4 == 0) ? 1 : (total / 4);
202 ret->dotnum = (total / 50) + 1;
203 if (start_string != NULL)
204 ret->startup_string = GNUNET_strdup (start_string);
206 ret->startup_string = GNUNET_strdup ("");
212 * Update progress meter (increment by one).
214 * @param meter the meter to update and print info for
216 * @return GNUNET_YES if called the total requested,
217 * GNUNET_NO if more items expected
220 update_meter (struct ProgressMeter *meter)
222 if (meter->print == GNUNET_YES)
224 if (meter->completed % meter->modnum == 0)
226 if (meter->completed == 0)
228 FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string);
231 FPRINTF (stdout, "%d%%",
232 (int) (((float) meter->completed / meter->total) * 100));
234 else if (meter->completed % meter->dotnum == 0)
235 FPRINTF (stdout, "%s", ".");
237 if (meter->completed + 1 == meter->total)
238 FPRINTF (stdout, "%d%%]\n", 100);
243 if (meter->completed == meter->total)
249 * Reset progress meter.
251 * @param meter the meter to reset
253 * @return GNUNET_YES if meter reset,
254 * GNUNET_SYSERR on error
257 reset_meter (struct ProgressMeter *meter)
260 return GNUNET_SYSERR;
262 meter->completed = 0;
267 * Release resources for meter
269 * @param meter the meter to free
272 free_meter (struct ProgressMeter *meter)
274 GNUNET_free_non_null (meter->startup_string);
279 /** Functions for creating, starting and connecting the peergroup **/
282 * Check whether peers successfully shut down.
285 internal_shutdown_callback (void *cls, const char *emsg)
287 struct PeerGroupStartupContext *pg_start_ctx = cls;
290 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg);
292 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason);
296 * Check if the get_handle is being used, if so stop the request. Either
297 * way, schedule the end_badly_cont function which actually shuts down the
301 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
303 struct PeerGroupStartupContext *pg_start_ctx = cls;
305 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
306 "Failing peer group startup with error: `%s'!\n",
307 pg_start_ctx->fail_reason);
309 GNUNET_TESTING_daemons_stop (pg_start_ctx->pg,
310 GNUNET_TIME_absolute_get_remaining
311 (pg_start_ctx->timeout),
312 &internal_shutdown_callback, pg_start_ctx);
314 if (pg_start_ctx->hostkey_meter != NULL)
316 free_meter (pg_start_ctx->hostkey_meter);
317 pg_start_ctx->hostkey_meter = NULL;
319 if (pg_start_ctx->peer_start_meter != NULL)
321 free_meter (pg_start_ctx->peer_start_meter);
322 pg_start_ctx->peer_start_meter = NULL;
324 if (pg_start_ctx->connect_meter != NULL)
326 free_meter (pg_start_ctx->connect_meter);
327 pg_start_ctx->connect_meter = NULL;
332 * This function is called whenever a connection attempt is finished between two of
333 * the started peers (started with GNUNET_TESTING_daemons_start). The total
334 * number of times this function is called should equal the number returned
335 * from the GNUNET_TESTING_connect_topology call.
337 * The emsg variable is NULL on success (peers connected), and non-NULL on
338 * failure (peers failed to connect).
341 internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first,
342 const struct GNUNET_PeerIdentity *second,
344 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
345 const struct GNUNET_CONFIGURATION_Handle
347 struct GNUNET_TESTING_Daemon *first_daemon,
348 struct GNUNET_TESTING_Daemon *second_daemon,
351 struct PeerGroupStartupContext *pg_start_ctx = cls;
357 unsigned long long duration;
358 unsigned long long total_duration;
359 unsigned int new_connections;
360 unsigned int new_failed_connections;
361 double conns_per_sec_recent;
362 double conns_per_sec_total;
363 double failed_conns_per_sec_recent;
364 double failed_conns_per_sec_total;
368 if (GNUNET_TIME_absolute_get_difference
370 GNUNET_TIME_absolute_get ()).rel_value >
371 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
372 CONN_UPDATE_DURATION).rel_value)
374 /* Get number of new connections */
375 new_connections = total_connections - previous_connections;
377 /* Get number of new FAILED connections */
378 new_failed_connections = failed_connections - previous_failed_connections;
380 /* Get duration in seconds */
382 GNUNET_TIME_absolute_get_difference (connect_last_time,
383 GNUNET_TIME_absolute_get
384 ()).rel_value / 1000;
386 GNUNET_TIME_absolute_get_difference (connect_start_time,
387 GNUNET_TIME_absolute_get
388 ()).rel_value / 1000;
390 failed_conns_per_sec_recent = (double) new_failed_connections / duration;
391 failed_conns_per_sec_total = (double) failed_connections / total_duration;
392 conns_per_sec_recent = (double) new_connections / duration;
393 conns_per_sec_total = (double) total_connections / total_duration;
394 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
395 "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n",
396 conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total,
397 failed_conns_per_sec_recent, failed_conns_per_sec_total);
398 connect_last_time = GNUNET_TIME_absolute_get ();
399 previous_connections = total_connections;
400 previous_failed_connections = failed_connections;
401 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
402 "have %u total_connections, %u failed\n", total_connections,
410 pg_start_ctx->total_connections++;
412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
413 "connected peer %s to peer %s, distance %u\n",
414 first_daemon->shortname, second_daemon->shortname, distance);
416 if (pg_start_ctx->topology_output_file != NULL)
418 second_str = GNUNET_strdup (GNUNET_i2s (second));
420 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n",
421 GNUNET_i2s (first), second_str);
422 GNUNET_free (second_str);
424 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
426 GNUNET_free (temp_str);
431 pg_start_ctx->failed_connections++;
433 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
434 "Failed to connect peer %s to peer %s with error :\n%s\n",
435 first_daemon->shortname, second_daemon->shortname, emsg);
437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438 "Failed to connect peer %s to peer %s with error :\n%s\n",
439 first_daemon->shortname, second_daemon->shortname, emsg);
443 GNUNET_assert (pg_start_ctx->connect_meter != NULL);
444 if (pg_start_ctx->connect_cb != NULL)
445 pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance,
446 first_cfg, second_cfg, first_daemon,
447 second_daemon, emsg);
448 if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter))
451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
453 pg_start_ctx->total_connections);
458 GNUNET_TIME_absolute_get_difference (connect_start_time,
459 GNUNET_TIME_absolute_get
460 ()).rel_value / 1000;
461 failed_conns_per_sec_total = (double) failed_connections / total_duration;
462 conns_per_sec_total = (double) total_connections / total_duration;
463 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
464 "Overall connection info --- Total: %u, Total Failed %u/s\n",
465 total_connections, failed_connections);
466 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
467 "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
468 conns_per_sec_total, failed_conns_per_sec_total);
471 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
472 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
474 /* Call final callback, signifying that the peer group has been started and connected */
475 if (pg_start_ctx->peergroup_cb != NULL)
476 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL);
478 if (pg_start_ctx->topology_output_file != NULL)
480 temp = GNUNET_asprintf (&temp_str, "}\n");
482 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
484 GNUNET_free (temp_str);
485 GNUNET_DISK_file_close (pg_start_ctx->topology_output_file);
492 * Callback called for each started daemon.
494 * @param cls Clause (PG Context).
495 * @param id PeerIdentidy of started daemon.
496 * @param cfg Configuration used by the daemon.
497 * @param d Handle for the daemon.
498 * @param emsg Error message, NULL on success.
501 internal_peers_started_callback (void *cls,
502 const struct GNUNET_PeerIdentity *id,
503 const struct GNUNET_CONFIGURATION_Handle *cfg,
504 struct GNUNET_TESTING_Daemon *d,
507 struct PeerGroupStartupContext *pg_start_ctx = cls;
511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
512 "Failed to start daemon with error: `%s'\n", emsg);
515 GNUNET_assert (id != NULL);
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
519 (pg_start_ctx->total - pg_start_ctx->peers_left) + 1,
520 pg_start_ctx->total);
523 pg_start_ctx->peers_left--;
525 if (NULL == pg_start_ctx->peer_start_meter)
527 /* Cancelled Ctrl-C or error */
530 if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
534 "All %d daemons started, now connecting peers!\n",
535 pg_start_ctx->total);
537 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
538 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
540 pg_start_ctx->expected_connections = UINT_MAX;
541 // FIXME: why whould peers_left be != 0?? Or pg NULL?
542 if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
544 pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
545 pg_start_ctx->expected_connections =
546 GNUNET_TESTING_connect_topology (pg_start_ctx->pg,
547 pg_start_ctx->connect_topology,
548 pg_start_ctx->connect_topology_option,
549 pg_start_ctx->connect_topology_option_modifier,
550 pg_start_ctx->connect_timeout,
551 pg_start_ctx->connect_attempts, NULL,
554 pg_start_ctx->connect_meter =
555 create_meter (pg_start_ctx->expected_connections, "Peer connection ",
556 pg_start_ctx->verbose);
557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n",
558 pg_start_ctx->expected_connections);
561 if (pg_start_ctx->expected_connections == 0)
563 GNUNET_free_non_null (pg_start_ctx->fail_reason);
564 pg_start_ctx->fail_reason =
565 GNUNET_strdup ("from connect topology (bad return)");
566 pg_start_ctx->die_task =
567 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
571 GNUNET_free_non_null (pg_start_ctx->fail_reason);
572 pg_start_ctx->fail_reason =
573 GNUNET_strdup ("from connect topology (timeout)");
574 pg_start_ctx->die_task =
575 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
576 (pg_start_ctx->timeout), &end_badly,
582 * Callback indicating that the hostkey was created for a peer.
585 * @param id the peer identity
586 * @param d the daemon handle (pretty useless at this point, remove?)
587 * @param emsg non-null on failure
590 internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id,
591 struct GNUNET_TESTING_Daemon *d, const char *emsg)
593 struct PeerGroupStartupContext *pg_start_ctx = cls;
594 unsigned int create_expected_connections;
598 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
599 "Hostkey callback received error: %s\n", emsg);
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604 "Hostkey (%d/%d) created for peer `%s'\n",
605 pg_start_ctx->total - pg_start_ctx->peers_left + 1,
606 pg_start_ctx->total, GNUNET_i2s (id));
609 pg_start_ctx->peers_left--;
610 if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
612 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
613 GNUNET_free_non_null (pg_start_ctx->fail_reason);
614 /* Set up task in case topology creation doesn't finish
615 * within a reasonable amount of time */
616 pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology");
617 pg_start_ctx->die_task =
618 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
619 (pg_start_ctx->timeout), &end_badly,
621 pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */
622 create_expected_connections =
623 GNUNET_TESTING_create_topology (pg_start_ctx->pg,
624 pg_start_ctx->topology,
625 pg_start_ctx->restrict_topology,
626 pg_start_ctx->restrict_transports);
627 if (create_expected_connections > 0)
629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
630 "Topology set up, have %u expected connections, now starting peers!\n",
631 create_expected_connections);
632 GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg);
636 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
637 GNUNET_free_non_null (pg_start_ctx->fail_reason);
638 pg_start_ctx->fail_reason =
639 GNUNET_strdup ("from create topology (bad return)");
640 pg_start_ctx->die_task =
641 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
645 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
646 GNUNET_free_non_null (pg_start_ctx->fail_reason);
647 pg_start_ctx->fail_reason =
648 GNUNET_strdup ("from continue startup (timeout)");
649 pg_start_ctx->die_task =
650 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
651 (pg_start_ctx->timeout), &end_badly,
658 * Prototype of a callback function indicating that two peers
659 * are currently connected.
662 * @param first peer id for first daemon
663 * @param second peer id for the second daemon
664 * @param emsg error message (NULL on success)
667 write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first,
668 const struct GNUNET_PeerIdentity *second, const char *emsg)
670 struct TopologyOutputContext *topo_ctx;
675 topo_ctx = (struct TopologyOutputContext *) cls;
676 GNUNET_assert (topo_ctx->file != NULL);
677 if ((emsg == NULL) && (first != NULL) && (second != NULL))
679 GNUNET_assert (first != NULL);
680 GNUNET_assert (second != NULL);
681 temp_pid2 = GNUNET_strdup (GNUNET_i2s (second));
683 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first),
685 GNUNET_free (temp_pid2);
686 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
688 else if ((emsg == NULL) && (first == NULL) && (second == NULL))
690 temp = GNUNET_asprintf (&temp_str, "}\n");
691 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
692 GNUNET_DISK_file_close (topo_ctx->file);
693 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL);
694 GNUNET_free (topo_ctx);
698 temp = GNUNET_asprintf (&temp_str, "}\n");
699 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
700 GNUNET_DISK_file_close (topo_ctx->file);
701 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg);
702 GNUNET_free (topo_ctx);
707 * Print current topology to a graphviz readable file.
709 * @param pg a currently running peergroup to print to file
710 * @param output_filename the file to write the topology to
711 * @param notify_cb callback to call upon completion or failure
712 * @param notify_cb_cls closure for notify_cb
716 GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg,
717 const char *output_filename,
718 GNUNET_TESTING_NotifyCompletion
719 notify_cb, void *notify_cb_cls)
721 struct TopologyOutputContext *topo_ctx;
725 topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext));
727 topo_ctx->notify_cb = notify_cb;
728 topo_ctx->notify_cb_cls = notify_cb_cls;
730 GNUNET_DISK_file_open (output_filename,
731 GNUNET_DISK_OPEN_READWRITE |
732 GNUNET_DISK_OPEN_CREATE,
733 GNUNET_DISK_PERM_USER_READ |
734 GNUNET_DISK_PERM_USER_WRITE);
735 if (topo_ctx->file == NULL)
737 notify_cb (notify_cb_cls, "Failed to open output file!");
738 GNUNET_free (topo_ctx);
742 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
744 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
745 GNUNET_free_non_null (temp_str);
746 GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx);
750 * Start a peer group with a given number of peers. Notify
751 * on completion of peer startup and connection based on given
752 * topological constraints. Optionally notify on each
753 * established connection.
755 * @param cfg configuration template to use
756 * @param total number of daemons to start
757 * @param timeout total time allowed for peers to start
758 * @param connect_cb function to call each time two daemons are connected
759 * @param peergroup_cb function to call once all peers are up and connected
760 * @param peergroup_cls closure for peergroup callbacks
761 * @param hostnames linked list of host structs to use to start peers on
762 * (NULL to run on localhost only)
764 * @return NULL on error, otherwise handle to control peer group
766 struct GNUNET_TESTING_PeerGroup *
767 GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
769 struct GNUNET_TIME_Relative timeout,
770 GNUNET_TESTING_NotifyConnection connect_cb,
771 GNUNET_TESTING_NotifyCompletion peergroup_cb,
773 const struct GNUNET_TESTING_Host *hostnames)
775 struct PeerGroupStartupContext *pg_start_ctx;
778 struct GNUNET_TIME_Relative rtimeout;
780 GNUNET_assert (total > 0);
781 GNUNET_assert (cfg != NULL);
783 pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext));
786 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts",
787 &pg_start_ctx->connect_attempts))
789 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
790 "testing", "connect_attempts");
791 GNUNET_free (pg_start_ctx);
796 GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT",
797 &pg_start_ctx->connect_timeout))
799 pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
803 GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
804 "max_outstanding_connections",
805 &pg_start_ctx->max_concurrent_connections))
807 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
808 "testing", "max_outstanding_connections");
809 GNUNET_free (pg_start_ctx);
814 GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
815 "max_concurrent_ssh",
816 &pg_start_ctx->max_concurrent_ssh))
818 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
819 "testing", "max_concurrent_ssh");
820 GNUNET_free (pg_start_ctx);
825 (pg_start_ctx->verbose =
826 GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing",
827 "use_progressbars")))
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
830 "testing", "use_progressbars");
831 GNUNET_free (pg_start_ctx);
836 GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "PEERGROUP_TIMEOUT",
839 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
840 "testing", "PEERGROUP_TIMEOUT");
841 GNUNET_free (pg_start_ctx);
844 pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout);
847 /* Read topology related options from the configuration file */
850 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology",
853 GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str)))
855 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
856 "Invalid topology `%s' given for section %s option %s\n",
857 temp_str, "TESTING", "TOPOLOGY");
858 pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
860 GNUNET_free_non_null (temp_str);
863 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
864 "topology_output_file", &temp_str))
866 pg_start_ctx->topology_output_file =
867 GNUNET_DISK_file_open (temp_str,
868 GNUNET_DISK_OPEN_READWRITE |
869 GNUNET_DISK_OPEN_CREATE,
870 GNUNET_DISK_PERM_USER_READ |
871 GNUNET_DISK_PERM_USER_WRITE);
872 if (pg_start_ctx->topology_output_file != NULL)
874 GNUNET_free (temp_str);
875 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
877 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
880 GNUNET_free (temp_str);
884 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
886 pg_start_ctx->topology_percentage = 0.5;
889 pg_start_ctx->topology_percentage = atof (temp_str);
890 GNUNET_free (temp_str);
894 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
896 pg_start_ctx->topology_probability = 0.5;
899 pg_start_ctx->topology_probability = atof (temp_str);
900 GNUNET_free (temp_str);
904 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
905 "connect_topology", &temp_str)) &&
907 GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str)))
909 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
910 "Invalid connect topology `%s' given for section %s option %s\n",
911 temp_str, "TESTING", "CONNECT_TOPOLOGY");
913 GNUNET_free_non_null (temp_str);
916 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
917 "connect_topology_option",
920 GNUNET_TESTING_topology_option_get
921 (&pg_start_ctx->connect_topology_option, temp_str)))
923 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
924 "Invalid connect topology option `%s' given for section %s option %s\n",
925 temp_str, "TESTING", "CONNECT_TOPOLOGY_OPTION");
926 pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
928 GNUNET_free_non_null (temp_str);
931 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
932 "connect_topology_option_modifier",
936 (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1)
938 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
940 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
941 temp_str, "connect_topology_option_modifier", "TESTING");
942 GNUNET_free (temp_str);
943 GNUNET_free (pg_start_ctx);
946 GNUNET_free (temp_str);
950 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
951 "blacklist_transports",
952 &pg_start_ctx->restrict_transports))
953 pg_start_ctx->restrict_transports = NULL;
955 pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE;
957 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
958 "blacklist_topology", &temp_str))
960 GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology,
963 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
964 "Invalid topology `%s' given for section %s option %s\n",
965 temp_str, "TESTING", "BLACKLIST_TOPOLOGY");
968 GNUNET_free_non_null (temp_str);
970 pg_start_ctx->cfg = cfg;
971 pg_start_ctx->total = total;
972 pg_start_ctx->peers_left = total;
973 pg_start_ctx->connect_cb = connect_cb;
974 pg_start_ctx->peergroup_cb = peergroup_cb;
975 pg_start_ctx->cls = peergroup_cls;
976 pg_start_ctx->hostnames = hostnames;
977 pg_start_ctx->hostkey_meter =
978 create_meter (pg_start_ctx->peers_left, "Hostkeys created ",
979 pg_start_ctx->verbose);
980 pg_start_ctx->peer_start_meter =
981 create_meter (pg_start_ctx->peers_left, "Peers started ",
982 pg_start_ctx->verbose);
983 /* Make compilers happy */
984 reset_meter (pg_start_ctx->peer_start_meter);
985 pg_start_ctx->fail_reason =
987 ("didn't generate all hostkeys within allowed startup time!");
988 pg_start_ctx->die_task =
989 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
990 (pg_start_ctx->timeout), &end_badly,
994 GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left,
995 pg_start_ctx->max_concurrent_connections,
996 pg_start_ctx->max_concurrent_ssh,
997 GNUNET_TIME_absolute_get_remaining
998 (pg_start_ctx->timeout),
999 &internal_hostkey_callback, pg_start_ctx,
1000 &internal_peers_started_callback,
1001 pg_start_ctx, &internal_topology_callback,
1002 pg_start_ctx, pg_start_ctx->hostnames);
1004 return pg_start_ctx->pg;
1007 /* end of testing_peergroup.c */