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;
71 enum GNUNET_TESTING_Topology topology;
73 float topology_percentage;
75 float topology_probability;
77 enum GNUNET_TESTING_Topology restrict_topology;
78 char *restrict_transports;
79 enum GNUNET_TESTING_Topology connect_topology;
80 enum GNUNET_TESTING_TopologyOption connect_topology_option;
81 double connect_topology_option_modifier;
84 struct ProgressMeter *hostkey_meter;
85 struct ProgressMeter *peer_start_meter;
86 struct ProgressMeter *connect_meter;
89 * Task used to kill the peergroup.
91 GNUNET_SCHEDULER_TaskIdentifier die_task;
96 * Variable used to store the number of connections we should wait for.
98 unsigned int expected_connections;
101 * Time when the connecting peers was started.
103 struct GNUNET_TIME_Absolute connect_start_time;
106 * The total number of connections that have been created so far.
108 unsigned int total_connections;
111 * The total number of connections that have failed so far.
113 unsigned int failed_connections;
116 * File handle to write out topology in dot format.
118 struct GNUNET_DISK_FileHandle *topology_output_file;
121 struct TopologyOutputContext
123 struct GNUNET_DISK_FileHandle *file;
124 GNUNET_TESTING_NotifyCompletion notify_cb;
129 * Simple struct to keep track of progress, and print a
130 * percentage meter for long running tasks.
135 * Total number of tasks to complete.
140 * Print percentage done after modnum tasks.
145 * Print a . each dotnum tasks.
150 * Total number completed thus far.
152 unsigned int completed;
155 * Whether or not to print.
160 * Startup string for progress meter.
162 char *startup_string;
166 /** Utility functions **/
169 * Create a meter to keep track of the progress of some task.
171 * @param total the total number of items to complete
172 * @param start_string a string to prefix the meter with (if printing)
173 * @param print GNUNET_YES to print the meter, GNUNET_NO to count
176 * @return the progress meter
178 static struct ProgressMeter *
179 create_meter (unsigned int total, char *start_string, int print)
181 struct ProgressMeter *ret;
183 ret = GNUNET_malloc (sizeof (struct ProgressMeter));
186 ret->modnum = (total / 4 == 0) ? 1 : (total / 4);
187 ret->dotnum = (total / 50) + 1;
188 if (start_string != NULL)
189 ret->startup_string = GNUNET_strdup (start_string);
191 ret->startup_string = GNUNET_strdup ("");
197 * Update progress meter (increment by one).
199 * @param meter the meter to update and print info for
201 * @return GNUNET_YES if called the total requested,
202 * GNUNET_NO if more items expected
205 update_meter (struct ProgressMeter *meter)
207 if (meter->print == GNUNET_YES)
209 if (meter->completed % meter->modnum == 0)
211 if (meter->completed == 0)
213 FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string);
216 FPRINTF (stdout, "%d%%",
217 (int) (((float) meter->completed / meter->total) * 100));
219 else if (meter->completed % meter->dotnum == 0)
220 FPRINTF (stdout, "%s", ".");
222 if (meter->completed + 1 == meter->total)
223 FPRINTF (stdout, "%d%%]\n", 100);
228 if (meter->completed == meter->total)
234 * Reset progress meter.
236 * @param meter the meter to reset
238 * @return GNUNET_YES if meter reset,
239 * GNUNET_SYSERR on error
242 reset_meter (struct ProgressMeter *meter)
245 return GNUNET_SYSERR;
247 meter->completed = 0;
252 * Release resources for meter
254 * @param meter the meter to free
257 free_meter (struct ProgressMeter *meter)
259 GNUNET_free_non_null (meter->startup_string);
264 /** Functions for creating, starting and connecting the peergroup **/
267 * Check whether peers successfully shut down.
270 internal_shutdown_callback (void *cls, const char *emsg)
272 struct PeerGroupStartupContext *pg_start_ctx = cls;
275 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg);
277 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason);
281 * Check if the get_handle is being used, if so stop the request. Either
282 * way, schedule the end_badly_cont function which actually shuts down the
286 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
288 struct PeerGroupStartupContext *pg_start_ctx = cls;
290 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
291 "Failing peer group startup with error: `%s'!\n",
292 pg_start_ctx->fail_reason);
294 GNUNET_TESTING_daemons_stop (pg_start_ctx->pg,
295 GNUNET_TIME_absolute_get_remaining
296 (pg_start_ctx->timeout),
297 &internal_shutdown_callback, pg_start_ctx);
299 if (pg_start_ctx->hostkey_meter != NULL)
300 free_meter (pg_start_ctx->hostkey_meter);
301 if (pg_start_ctx->peer_start_meter != NULL)
302 free_meter (pg_start_ctx->peer_start_meter);
303 if (pg_start_ctx->connect_meter != NULL)
304 free_meter (pg_start_ctx->connect_meter);
308 * This function is called whenever a connection attempt is finished between two of
309 * the started peers (started with GNUNET_TESTING_daemons_start). The total
310 * number of times this function is called should equal the number returned
311 * from the GNUNET_TESTING_connect_topology call.
313 * The emsg variable is NULL on success (peers connected), and non-NULL on
314 * failure (peers failed to connect).
317 internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first,
318 const struct GNUNET_PeerIdentity *second,
320 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
321 const struct GNUNET_CONFIGURATION_Handle
323 struct GNUNET_TESTING_Daemon *first_daemon,
324 struct GNUNET_TESTING_Daemon *second_daemon,
327 struct PeerGroupStartupContext *pg_start_ctx = cls;
333 unsigned long long duration;
334 unsigned long long total_duration;
335 unsigned int new_connections;
336 unsigned int new_failed_connections;
337 double conns_per_sec_recent;
338 double conns_per_sec_total;
339 double failed_conns_per_sec_recent;
340 double failed_conns_per_sec_total;
344 if (GNUNET_TIME_absolute_get_difference
346 GNUNET_TIME_absolute_get ()).rel_value >
347 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
348 CONN_UPDATE_DURATION).rel_value)
350 /* Get number of new connections */
351 new_connections = total_connections - previous_connections;
353 /* Get number of new FAILED connections */
354 new_failed_connections = failed_connections - previous_failed_connections;
356 /* Get duration in seconds */
358 GNUNET_TIME_absolute_get_difference (connect_last_time,
359 GNUNET_TIME_absolute_get
360 ()).rel_value / 1000;
362 GNUNET_TIME_absolute_get_difference (connect_start_time,
363 GNUNET_TIME_absolute_get
364 ()).rel_value / 1000;
366 failed_conns_per_sec_recent = (double) new_failed_connections / duration;
367 failed_conns_per_sec_total = (double) failed_connections / total_duration;
368 conns_per_sec_recent = (double) new_connections / duration;
369 conns_per_sec_total = (double) total_connections / total_duration;
370 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
371 "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n",
372 conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total,
373 failed_conns_per_sec_recent, failed_conns_per_sec_total);
374 connect_last_time = GNUNET_TIME_absolute_get ();
375 previous_connections = total_connections;
376 previous_failed_connections = failed_connections;
377 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
378 "have %u total_connections, %u failed\n", total_connections,
386 pg_start_ctx->total_connections++;
388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
389 "connected peer %s to peer %s, distance %u\n",
390 first_daemon->shortname, second_daemon->shortname, distance);
392 if (pg_start_ctx->topology_output_file != NULL)
394 second_str = GNUNET_strdup (GNUNET_i2s (second));
396 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n",
397 GNUNET_i2s (first), second_str);
398 GNUNET_free (second_str);
400 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
402 GNUNET_free (temp_str);
407 pg_start_ctx->failed_connections++;
409 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
410 "Failed to connect peer %s to peer %s with error :\n%s\n",
411 first_daemon->shortname, second_daemon->shortname, emsg);
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Failed to connect peer %s to peer %s with error :\n%s\n",
415 first_daemon->shortname, second_daemon->shortname, emsg);
419 GNUNET_assert (pg_start_ctx->connect_meter != NULL);
420 if (pg_start_ctx->connect_cb != NULL)
421 pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance,
422 first_cfg, second_cfg, first_daemon,
423 second_daemon, emsg);
424 if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter))
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
428 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
429 pg_start_ctx->total_connections);
434 GNUNET_TIME_absolute_get_difference (connect_start_time,
435 GNUNET_TIME_absolute_get
436 ()).rel_value / 1000;
437 failed_conns_per_sec_total = (double) failed_connections / total_duration;
438 conns_per_sec_total = (double) total_connections / total_duration;
439 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
440 "Overall connection info --- Total: %u, Total Failed %u/s\n",
441 total_connections, failed_connections);
442 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
443 "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
444 conns_per_sec_total, failed_conns_per_sec_total);
447 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
448 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
450 /* Call final callback, signifying that the peer group has been started and connected */
451 if (pg_start_ctx->peergroup_cb != NULL)
452 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL);
454 if (pg_start_ctx->topology_output_file != NULL)
456 temp = GNUNET_asprintf (&temp_str, "}\n");
458 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
460 GNUNET_free (temp_str);
461 GNUNET_DISK_file_close (pg_start_ctx->topology_output_file);
468 * Callback called for each started daemon.
470 * @param cls Clause (PG Context).
471 * @param id PeerIdentidy of started daemon.
472 * @param cfg Configuration used by the daemon.
473 * @param d Handle for the daemon.
474 * @param emsg Error message, NULL on success.
477 internal_peers_started_callback (void *cls,
478 const struct GNUNET_PeerIdentity *id,
479 const struct GNUNET_CONFIGURATION_Handle *cfg,
480 struct GNUNET_TESTING_Daemon *d,
483 struct PeerGroupStartupContext *pg_start_ctx = cls;
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488 "Failed to start daemon with error: `%s'\n", emsg);
491 GNUNET_assert (id != NULL);
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
495 (pg_start_ctx->total - pg_start_ctx->peers_left) + 1,
496 pg_start_ctx->total);
499 pg_start_ctx->peers_left--;
501 if (NULL == pg_start_ctx->peer_start_meter)
503 /* Cancelled Ctrl-C or error */
506 if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "All %d daemons started, now connecting peers!\n",
511 pg_start_ctx->total);
513 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
514 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
516 pg_start_ctx->expected_connections = UINT_MAX;
517 // FIXME: why whould peers_left be != 0?? Or pg NULL?
518 if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
520 pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
521 pg_start_ctx->expected_connections =
522 GNUNET_TESTING_connect_topology (pg_start_ctx->pg,
523 pg_start_ctx->connect_topology,
524 pg_start_ctx->connect_topology_option,
525 pg_start_ctx->connect_topology_option_modifier,
526 pg_start_ctx->connect_timeout,
527 pg_start_ctx->connect_attempts, NULL,
530 pg_start_ctx->connect_meter =
531 create_meter (pg_start_ctx->expected_connections, "Peer connection ",
532 pg_start_ctx->verbose);
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n",
534 pg_start_ctx->expected_connections);
537 if (pg_start_ctx->expected_connections == 0)
539 GNUNET_free_non_null (pg_start_ctx->fail_reason);
540 pg_start_ctx->fail_reason =
541 GNUNET_strdup ("from connect topology (bad return)");
542 pg_start_ctx->die_task =
543 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
547 GNUNET_free_non_null (pg_start_ctx->fail_reason);
548 pg_start_ctx->fail_reason =
549 GNUNET_strdup ("from connect topology (timeout)");
550 pg_start_ctx->die_task =
551 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
552 (pg_start_ctx->timeout), &end_badly,
558 * Callback indicating that the hostkey was created for a peer.
561 * @param id the peer identity
562 * @param d the daemon handle (pretty useless at this point, remove?)
563 * @param emsg non-null on failure
566 internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id,
567 struct GNUNET_TESTING_Daemon *d, const char *emsg)
569 struct PeerGroupStartupContext *pg_start_ctx = cls;
570 unsigned int create_expected_connections;
574 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
575 "Hostkey callback received error: %s\n", emsg);
579 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 "Hostkey (%d/%d) created for peer `%s'\n",
581 pg_start_ctx->total - pg_start_ctx->peers_left + 1,
582 pg_start_ctx->total, GNUNET_i2s (id));
585 pg_start_ctx->peers_left--;
586 if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
588 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
589 GNUNET_free_non_null (pg_start_ctx->fail_reason);
590 /* Set up task in case topology creation doesn't finish
591 * within a reasonable amount of time */
592 pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology");
593 pg_start_ctx->die_task =
594 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
595 (pg_start_ctx->timeout), &end_badly,
597 pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */
598 create_expected_connections =
599 GNUNET_TESTING_create_topology (pg_start_ctx->pg,
600 pg_start_ctx->topology,
601 pg_start_ctx->restrict_topology,
602 pg_start_ctx->restrict_transports);
603 if (create_expected_connections > 0)
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Topology set up, have %u expected connections, now starting peers!\n",
607 create_expected_connections);
608 GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg);
612 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
613 GNUNET_free_non_null (pg_start_ctx->fail_reason);
614 pg_start_ctx->fail_reason =
615 GNUNET_strdup ("from create topology (bad return)");
616 pg_start_ctx->die_task =
617 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
621 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
622 GNUNET_free_non_null (pg_start_ctx->fail_reason);
623 pg_start_ctx->fail_reason =
624 GNUNET_strdup ("from continue startup (timeout)");
625 pg_start_ctx->die_task =
626 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
627 (pg_start_ctx->timeout), &end_badly,
634 * Prototype of a callback function indicating that two peers
635 * are currently connected.
638 * @param first peer id for first daemon
639 * @param second peer id for the second daemon
640 * @param emsg error message (NULL on success)
643 write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first,
644 const struct GNUNET_PeerIdentity *second, const char *emsg)
646 struct TopologyOutputContext *topo_ctx;
651 topo_ctx = (struct TopologyOutputContext *) cls;
652 GNUNET_assert (topo_ctx->file != NULL);
653 if ((emsg == NULL) && (first != NULL) && (second != NULL))
655 GNUNET_assert (first != NULL);
656 GNUNET_assert (second != NULL);
657 temp_pid2 = GNUNET_strdup (GNUNET_i2s (second));
659 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first),
661 GNUNET_free (temp_pid2);
662 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
664 else if ((emsg == NULL) && (first == NULL) && (second == NULL))
666 temp = GNUNET_asprintf (&temp_str, "}\n");
667 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
668 GNUNET_DISK_file_close (topo_ctx->file);
669 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL);
670 GNUNET_free (topo_ctx);
674 temp = GNUNET_asprintf (&temp_str, "}\n");
675 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
676 GNUNET_DISK_file_close (topo_ctx->file);
677 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg);
678 GNUNET_free (topo_ctx);
683 * Print current topology to a graphviz readable file.
685 * @param pg a currently running peergroup to print to file
686 * @param output_filename the file to write the topology to
687 * @param notify_cb callback to call upon completion or failure
688 * @param notify_cb_cls closure for notify_cb
692 GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg,
693 const char *output_filename,
694 GNUNET_TESTING_NotifyCompletion
695 notify_cb, void *notify_cb_cls)
697 struct TopologyOutputContext *topo_ctx;
701 topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext));
703 topo_ctx->notify_cb = notify_cb;
704 topo_ctx->notify_cb_cls = notify_cb_cls;
706 GNUNET_DISK_file_open (output_filename,
707 GNUNET_DISK_OPEN_READWRITE |
708 GNUNET_DISK_OPEN_CREATE,
709 GNUNET_DISK_PERM_USER_READ |
710 GNUNET_DISK_PERM_USER_WRITE);
711 if (topo_ctx->file == NULL)
713 notify_cb (notify_cb_cls, "Failed to open output file!");
714 GNUNET_free (topo_ctx);
718 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
720 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
721 GNUNET_free_non_null (temp_str);
722 GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx);
726 * Start a peer group with a given number of peers. Notify
727 * on completion of peer startup and connection based on given
728 * topological constraints. Optionally notify on each
729 * established connection.
731 * @param cfg configuration template to use
732 * @param total number of daemons to start
733 * @param timeout total time allowed for peers to start
734 * @param connect_cb function to call each time two daemons are connected
735 * @param peergroup_cb function to call once all peers are up and connected
736 * @param peergroup_cls closure for peergroup callbacks
737 * @param hostnames linked list of host structs to use to start peers on
738 * (NULL to run on localhost only)
740 * @return NULL on error, otherwise handle to control peer group
742 struct GNUNET_TESTING_PeerGroup *
743 GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
745 struct GNUNET_TIME_Relative timeout,
746 GNUNET_TESTING_NotifyConnection connect_cb,
747 GNUNET_TESTING_NotifyCompletion peergroup_cb,
749 const struct GNUNET_TESTING_Host *hostnames)
751 struct PeerGroupStartupContext *pg_start_ctx;
754 struct GNUNET_TIME_Relative rtimeout;
756 GNUNET_assert (total > 0);
757 GNUNET_assert (cfg != NULL);
759 pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext));
762 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts",
763 &pg_start_ctx->connect_attempts))
765 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
766 "testing", "connect_attempts");
767 GNUNET_free (pg_start_ctx);
772 GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT",
773 &pg_start_ctx->connect_timeout))
775 pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
779 GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
780 "max_outstanding_connections",
781 &pg_start_ctx->max_concurrent_connections))
783 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
784 "testing", "max_outstanding_connections");
785 GNUNET_free (pg_start_ctx);
790 GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
791 "max_concurrent_ssh",
792 &pg_start_ctx->max_concurrent_ssh))
794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
795 "testing", "max_concurrent_ssh");
796 GNUNET_free (pg_start_ctx);
801 (pg_start_ctx->verbose =
802 GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing",
803 "use_progressbars")))
805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
806 "testing", "use_progressbars");
807 GNUNET_free (pg_start_ctx);
812 GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "PEERGROUP_TIMEOUT",
815 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
816 "testing", "PEERGROUP_TIMEOUT");
817 GNUNET_free (pg_start_ctx);
820 pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout);
823 /* Read topology related options from the configuration file */
826 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology",
829 GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str)))
831 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
832 "Invalid topology `%s' given for section %s option %s\n",
833 temp_str, "TESTING", "TOPOLOGY");
834 pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
836 GNUNET_free_non_null (temp_str);
839 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
840 "topology_output_file", &temp_str))
842 pg_start_ctx->topology_output_file =
843 GNUNET_DISK_file_open (temp_str,
844 GNUNET_DISK_OPEN_READWRITE |
845 GNUNET_DISK_OPEN_CREATE,
846 GNUNET_DISK_PERM_USER_READ |
847 GNUNET_DISK_PERM_USER_WRITE);
848 if (pg_start_ctx->topology_output_file != NULL)
850 GNUNET_free (temp_str);
851 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
853 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
856 GNUNET_free (temp_str);
860 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
862 pg_start_ctx->topology_percentage = 0.5;
865 pg_start_ctx->topology_percentage = atof (temp_str);
866 GNUNET_free (temp_str);
870 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
872 pg_start_ctx->topology_probability = 0.5;
875 pg_start_ctx->topology_probability = atof (temp_str);
876 GNUNET_free (temp_str);
880 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
881 "connect_topology", &temp_str)) &&
883 GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str)))
885 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
886 "Invalid connect topology `%s' given for section %s option %s\n",
887 temp_str, "TESTING", "CONNECT_TOPOLOGY");
889 GNUNET_free_non_null (temp_str);
892 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
893 "connect_topology_option",
896 GNUNET_TESTING_topology_option_get
897 (&pg_start_ctx->connect_topology_option, temp_str)))
899 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
900 "Invalid connect topology option `%s' given for section %s option %s\n",
901 temp_str, "TESTING", "CONNECT_TOPOLOGY_OPTION");
902 pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
904 GNUNET_free_non_null (temp_str);
907 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
908 "connect_topology_option_modifier",
912 (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1)
914 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
916 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
917 temp_str, "connect_topology_option_modifier", "TESTING");
918 GNUNET_free (temp_str);
919 GNUNET_free (pg_start_ctx);
922 GNUNET_free (temp_str);
926 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
927 "blacklist_transports",
928 &pg_start_ctx->restrict_transports))
929 pg_start_ctx->restrict_transports = NULL;
931 pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE;
933 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
934 "blacklist_topology", &temp_str))
936 GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology,
939 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
940 "Invalid topology `%s' given for section %s option %s\n",
941 temp_str, "TESTING", "BLACKLIST_TOPOLOGY");
944 GNUNET_free_non_null (temp_str);
946 pg_start_ctx->cfg = cfg;
947 pg_start_ctx->total = total;
948 pg_start_ctx->peers_left = total;
949 pg_start_ctx->connect_cb = connect_cb;
950 pg_start_ctx->peergroup_cb = peergroup_cb;
951 pg_start_ctx->cls = peergroup_cls;
952 pg_start_ctx->hostnames = hostnames;
953 pg_start_ctx->hostkey_meter =
954 create_meter (pg_start_ctx->peers_left, "Hostkeys created ",
955 pg_start_ctx->verbose);
956 pg_start_ctx->peer_start_meter =
957 create_meter (pg_start_ctx->peers_left, "Peers started ",
958 pg_start_ctx->verbose);
959 /* Make compilers happy */
960 reset_meter (pg_start_ctx->peer_start_meter);
961 pg_start_ctx->fail_reason =
963 ("didn't generate all hostkeys within allowed startup time!");
964 pg_start_ctx->die_task =
965 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
966 (pg_start_ctx->timeout), &end_badly,
970 GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left,
971 pg_start_ctx->max_concurrent_connections,
972 pg_start_ctx->max_concurrent_ssh,
973 GNUNET_TIME_absolute_get_remaining
974 (pg_start_ctx->timeout),
975 &internal_hostkey_callback, pg_start_ctx,
976 &internal_peers_started_callback,
977 pg_start_ctx, &internal_topology_callback,
978 pg_start_ctx, pg_start_ctx->hostnames);
980 return pg_start_ctx->pg;
983 /* end of testing_peergroup.c */