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;
49 unsigned long long connect_attempts;
50 unsigned long long max_concurrent_ssh;
51 struct GNUNET_TIME_Absolute timeout;
52 GNUNET_TESTING_NotifyConnection connect_cb;
53 GNUNET_TESTING_NotifyCompletion peergroup_cb;
56 * Closure for all peergroup callbacks.
60 const struct GNUNET_TESTING_Host *hostnames;
61 enum GNUNET_TESTING_Topology topology;
63 float topology_percentage;
65 float topology_probability;
67 enum GNUNET_TESTING_Topology restrict_topology;
68 char *restrict_transports;
69 enum GNUNET_TESTING_Topology connect_topology;
70 enum GNUNET_TESTING_TopologyOption connect_topology_option;
71 double connect_topology_option_modifier;
74 struct ProgressMeter *hostkey_meter;
75 struct ProgressMeter *peer_start_meter;
76 struct ProgressMeter *connect_meter;
79 * Task used to kill the peergroup.
81 GNUNET_SCHEDULER_TaskIdentifier die_task;
86 * Variable used to store the number of connections we should wait for.
88 unsigned int expected_connections;
91 * Time when the connecting peers was started.
93 struct GNUNET_TIME_Absolute connect_start_time;
96 * The total number of connections that have been created so far.
98 unsigned int total_connections;
101 * The total number of connections that have failed so far.
103 unsigned int failed_connections;
106 * File handle to write out topology in dot format.
108 struct GNUNET_DISK_FileHandle *topology_output_file;
111 struct TopologyOutputContext
113 struct GNUNET_DISK_FileHandle *file;
114 GNUNET_TESTING_NotifyCompletion notify_cb;
119 * Simple struct to keep track of progress, and print a
120 * percentage meter for long running tasks.
125 * Total number of tasks to complete.
130 * Print percentage done after modnum tasks.
135 * Print a . each dotnum tasks.
140 * Total number completed thus far.
142 unsigned int completed;
145 * Whether or not to print.
150 * Startup string for progress meter.
152 char *startup_string;
156 /** Utility functions **/
159 * Create a meter to keep track of the progress of some task.
161 * @param total the total number of items to complete
162 * @param start_string a string to prefix the meter with (if printing)
163 * @param print GNUNET_YES to print the meter, GNUNET_NO to count
166 * @return the progress meter
168 static struct ProgressMeter *
169 create_meter (unsigned int total, char *start_string, int print)
171 struct ProgressMeter *ret;
173 ret = GNUNET_malloc (sizeof (struct ProgressMeter));
176 ret->modnum = total / 4;
177 ret->dotnum = (total / 50) + 1;
178 if (start_string != NULL)
179 ret->startup_string = GNUNET_strdup (start_string);
181 ret->startup_string = GNUNET_strdup ("");
187 * Update progress meter (increment by one).
189 * @param meter the meter to update and print info for
191 * @return GNUNET_YES if called the total requested,
192 * GNUNET_NO if more items expected
195 update_meter (struct ProgressMeter *meter)
197 if (meter->print == GNUNET_YES)
199 if (meter->completed % meter->modnum == 0)
201 if (meter->completed == 0)
203 fprintf (stdout, "%sProgress: [0%%", meter->startup_string);
206 fprintf (stdout, "%d%%",
207 (int) (((float) meter->completed / meter->total) * 100));
209 else if (meter->completed % meter->dotnum == 0)
210 fprintf (stdout, ".");
212 if (meter->completed + 1 == meter->total)
213 fprintf (stdout, "%d%%]\n", 100);
218 if (meter->completed == meter->total)
224 * Reset progress meter.
226 * @param meter the meter to reset
228 * @return GNUNET_YES if meter reset,
229 * GNUNET_SYSERR on error
232 reset_meter (struct ProgressMeter *meter)
235 return GNUNET_SYSERR;
237 meter->completed = 0;
242 * Release resources for meter
244 * @param meter the meter to free
247 free_meter (struct ProgressMeter *meter)
249 GNUNET_free_non_null (meter->startup_string);
254 /** Functions for creating, starting and connecting the peergroup **/
257 * Check whether peers successfully shut down.
260 internal_shutdown_callback (void *cls, const char *emsg)
262 struct PeerGroupStartupContext *pg_start_ctx = cls;
265 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg);
267 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason);
271 * Check if the get_handle is being used, if so stop the request. Either
272 * way, schedule the end_badly_cont function which actually shuts down the
276 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
278 struct PeerGroupStartupContext *pg_start_ctx = cls;
280 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
281 "Failing peer group startup with error: `%s'!\n",
282 pg_start_ctx->fail_reason);
284 GNUNET_TESTING_daemons_stop (pg_start_ctx->pg,
285 GNUNET_TIME_absolute_get_remaining
286 (pg_start_ctx->timeout),
287 &internal_shutdown_callback, pg_start_ctx);
289 if (pg_start_ctx->hostkey_meter != NULL)
290 free_meter (pg_start_ctx->hostkey_meter);
291 if (pg_start_ctx->peer_start_meter != NULL)
292 free_meter (pg_start_ctx->peer_start_meter);
293 if (pg_start_ctx->connect_meter != NULL)
294 free_meter (pg_start_ctx->connect_meter);
298 * This function is called whenever a connection attempt is finished between two of
299 * the started peers (started with GNUNET_TESTING_daemons_start). The total
300 * number of times this function is called should equal the number returned
301 * from the GNUNET_TESTING_connect_topology call.
303 * The emsg variable is NULL on success (peers connected), and non-NULL on
304 * failure (peers failed to connect).
307 internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first,
308 const struct GNUNET_PeerIdentity *second,
310 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
311 const struct GNUNET_CONFIGURATION_Handle
313 struct GNUNET_TESTING_Daemon *first_daemon,
314 struct GNUNET_TESTING_Daemon *second_daemon,
317 struct PeerGroupStartupContext *pg_start_ctx = cls;
323 unsigned long long duration;
324 unsigned long long total_duration;
325 unsigned int new_connections;
326 unsigned int new_failed_connections;
327 double conns_per_sec_recent;
328 double conns_per_sec_total;
329 double failed_conns_per_sec_recent;
330 double failed_conns_per_sec_total;
334 if (GNUNET_TIME_absolute_get_difference
336 GNUNET_TIME_absolute_get ()).rel_value >
337 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
338 CONN_UPDATE_DURATION).rel_value)
340 /* Get number of new connections */
341 new_connections = total_connections - previous_connections;
343 /* Get number of new FAILED connections */
344 new_failed_connections = failed_connections - previous_failed_connections;
346 /* Get duration in seconds */
348 GNUNET_TIME_absolute_get_difference (connect_last_time,
349 GNUNET_TIME_absolute_get
350 ()).rel_value / 1000;
352 GNUNET_TIME_absolute_get_difference (connect_start_time,
353 GNUNET_TIME_absolute_get
354 ()).rel_value / 1000;
356 failed_conns_per_sec_recent = (double) new_failed_connections / duration;
357 failed_conns_per_sec_total = (double) failed_connections / total_duration;
358 conns_per_sec_recent = (double) new_connections / duration;
359 conns_per_sec_total = (double) total_connections / total_duration;
360 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
361 "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n",
362 conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total,
363 failed_conns_per_sec_recent, failed_conns_per_sec_total);
364 connect_last_time = GNUNET_TIME_absolute_get ();
365 previous_connections = total_connections;
366 previous_failed_connections = failed_connections;
367 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
368 "have %u total_connections, %u failed\n", total_connections,
376 pg_start_ctx->total_connections++;
378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
379 "connected peer %s to peer %s, distance %u\n",
380 first_daemon->shortname, second_daemon->shortname, distance);
382 if (pg_start_ctx->topology_output_file != NULL)
384 second_str = GNUNET_strdup (GNUNET_i2s (second));
386 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n",
387 GNUNET_i2s (first), second_str);
388 GNUNET_free (second_str);
390 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
392 GNUNET_free (temp_str);
397 pg_start_ctx->failed_connections++;
399 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
400 "Failed to connect peer %s to peer %s with error :\n%s\n",
401 first_daemon->shortname, second_daemon->shortname, emsg);
403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
404 "Failed to connect peer %s to peer %s with error :\n%s\n",
405 first_daemon->shortname, second_daemon->shortname, emsg);
409 GNUNET_assert (pg_start_ctx->connect_meter != NULL);
410 if (pg_start_ctx->connect_cb != NULL)
411 pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance,
412 first_cfg, second_cfg, first_daemon,
413 second_daemon, emsg);
414 if (GNUNET_YES == update_meter (pg_start_ctx->connect_meter))
417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
418 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
424 GNUNET_TIME_absolute_get_difference (connect_start_time,
425 GNUNET_TIME_absolute_get
426 ()).rel_value / 1000;
427 failed_conns_per_sec_total = (double) failed_connections / total_duration;
428 conns_per_sec_total = (double) total_connections / total_duration;
429 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
430 "Overall connection info --- Total: %u, Total Failed %u/s\n",
431 total_connections, failed_connections);
432 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
433 "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
434 conns_per_sec_total, failed_conns_per_sec_total);
437 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
438 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
440 /* Call final callback, signifying that the peer group has been started and connected */
441 if (pg_start_ctx->peergroup_cb != NULL)
442 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL);
444 if (pg_start_ctx->topology_output_file != NULL)
446 temp = GNUNET_asprintf (&temp_str, "}\n");
448 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
450 GNUNET_free (temp_str);
451 GNUNET_DISK_file_close (pg_start_ctx->topology_output_file);
457 internal_peers_started_callback (void *cls,
458 const struct GNUNET_PeerIdentity *id,
459 const struct GNUNET_CONFIGURATION_Handle *cfg,
460 struct GNUNET_TESTING_Daemon *d,
463 struct PeerGroupStartupContext *pg_start_ctx = cls;
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468 "Failed to start daemon with error: `%s'\n", emsg);
471 GNUNET_assert (id != NULL);
474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
475 (num_peers - peers_left) + 1, num_peers);
478 pg_start_ctx->peers_left--;
480 if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 "All %d daemons started, now connecting peers!\n", num_peers);
486 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
487 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
489 pg_start_ctx->expected_connections = UINT_MAX;
490 if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
492 pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
493 pg_start_ctx->expected_connections =
494 GNUNET_TESTING_connect_topology (pg_start_ctx->pg,
495 pg_start_ctx->connect_topology,
496 pg_start_ctx->connect_topology_option,
497 pg_start_ctx->connect_topology_option_modifier,
498 DEFAULT_CONNECT_TIMEOUT,
499 pg_start_ctx->connect_attempts, NULL,
502 pg_start_ctx->connect_meter =
503 create_meter (pg_start_ctx->expected_connections, "Peer connection ",
504 pg_start_ctx->verbose);
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n",
506 pg_start_ctx->expected_connections);
509 if (pg_start_ctx->expected_connections == 0)
511 GNUNET_free_non_null (pg_start_ctx->fail_reason);
512 pg_start_ctx->fail_reason =
513 GNUNET_strdup ("from connect topology (bad return)");
514 pg_start_ctx->die_task =
515 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
519 GNUNET_free_non_null (pg_start_ctx->fail_reason);
520 pg_start_ctx->fail_reason =
521 GNUNET_strdup ("from connect topology (timeout)");
522 pg_start_ctx->die_task =
523 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
524 (pg_start_ctx->timeout), &end_badly,
530 * Callback indicating that the hostkey was created for a peer.
533 * @param id the peer identity
534 * @param d the daemon handle (pretty useless at this point, remove?)
535 * @param emsg non-null on failure
538 internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id,
539 struct GNUNET_TESTING_Daemon *d, const char *emsg)
541 struct PeerGroupStartupContext *pg_start_ctx = cls;
542 unsigned int create_expected_connections;
546 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
547 "Hostkey callback received error: %s\n", emsg);
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left,
553 num_peers, GNUNET_i2s (id));
556 pg_start_ctx->peers_left--;
557 if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
559 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
560 /* Set up task in case topology creation doesn't finish
561 * within a reasonable amount of time */
562 GNUNET_free_non_null (pg_start_ctx->fail_reason);
563 pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology");
564 pg_start_ctx->die_task =
565 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
566 (pg_start_ctx->timeout), &end_badly,
568 pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */
569 create_expected_connections =
570 GNUNET_TESTING_create_topology (pg_start_ctx->pg,
571 pg_start_ctx->topology,
572 pg_start_ctx->restrict_topology,
573 pg_start_ctx->restrict_transports);
574 if (create_expected_connections > 0)
576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577 "Topology set up, have %u expected connections, now starting peers!\n",
578 create_expected_connections);
579 GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg);
583 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
584 GNUNET_free_non_null (pg_start_ctx->fail_reason);
585 pg_start_ctx->fail_reason =
586 GNUNET_strdup ("from create topology (bad return)");
587 pg_start_ctx->die_task =
588 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
592 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
593 GNUNET_free_non_null (pg_start_ctx->fail_reason);
594 pg_start_ctx->fail_reason =
595 GNUNET_strdup ("from continue startup (timeout)");
596 pg_start_ctx->die_task =
597 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
598 (pg_start_ctx->timeout), &end_badly,
605 * Prototype of a callback function indicating that two peers
606 * are currently connected.
609 * @param first peer id for first daemon
610 * @param second peer id for the second daemon
611 * @param emsg error message (NULL on success)
614 write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first,
615 const struct GNUNET_PeerIdentity *second, const char *emsg)
617 struct TopologyOutputContext *topo_ctx;
622 topo_ctx = (struct TopologyOutputContext *) cls;
623 GNUNET_assert (topo_ctx->file != NULL);
624 if ((emsg == NULL) && (first != NULL) && (second != NULL))
626 GNUNET_assert (first != NULL);
627 GNUNET_assert (second != NULL);
628 temp_pid2 = GNUNET_strdup (GNUNET_i2s (second));
630 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first),
632 GNUNET_free (temp_pid2);
633 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
635 else if ((emsg == NULL) && (first == NULL) && (second == NULL))
637 temp = GNUNET_asprintf (&temp_str, "}\n");
638 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
639 GNUNET_DISK_file_close (topo_ctx->file);
640 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL);
641 GNUNET_free (topo_ctx);
645 temp = GNUNET_asprintf (&temp_str, "}\n");
646 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
647 GNUNET_DISK_file_close (topo_ctx->file);
648 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg);
649 GNUNET_free (topo_ctx);
654 * Print current topology to a graphviz readable file.
656 * @param pg a currently running peergroup to print to file
657 * @param output_filename the file to write the topology to
658 * @param notify_cb callback to call upon completion or failure
659 * @param notify_cb_cls closure for notify_cb
663 GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg,
664 const char *output_filename,
665 GNUNET_TESTING_NotifyCompletion
666 notify_cb, void *notify_cb_cls)
668 struct TopologyOutputContext *topo_ctx;
672 topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext));
674 topo_ctx->notify_cb = notify_cb;
675 topo_ctx->notify_cb_cls = notify_cb_cls;
677 GNUNET_DISK_file_open (output_filename,
678 GNUNET_DISK_OPEN_READWRITE |
679 GNUNET_DISK_OPEN_CREATE,
680 GNUNET_DISK_PERM_USER_READ |
681 GNUNET_DISK_PERM_USER_WRITE);
682 if (topo_ctx->file == NULL)
684 notify_cb (notify_cb_cls, "Failed to open output file!");
685 GNUNET_free (topo_ctx);
689 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
691 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
692 GNUNET_free_non_null (temp_str);
693 GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx);
697 * Start a peer group with a given number of peers. Notify
698 * on completion of peer startup and connection based on given
699 * topological constraints. Optionally notify on each
700 * established connection.
702 * @param cfg configuration template to use
703 * @param total number of daemons to start
704 * @param timeout total time allowed for peers to start
705 * @param connect_cb function to call each time two daemons are connected
706 * @param peergroup_cb function to call once all peers are up and connected
707 * @param peergroup_cls closure for peergroup callbacks
708 * @param hostnames linked list of host structs to use to start peers on
709 * (NULL to run on localhost only)
711 * @return NULL on error, otherwise handle to control peer group
713 struct GNUNET_TESTING_PeerGroup *
714 GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
716 struct GNUNET_TIME_Relative timeout,
717 GNUNET_TESTING_NotifyConnection connect_cb,
718 GNUNET_TESTING_NotifyCompletion peergroup_cb,
720 const struct GNUNET_TESTING_Host *hostnames)
722 struct PeerGroupStartupContext *pg_start_ctx;
723 unsigned long long temp_config_number;
727 GNUNET_assert (total > 0);
728 GNUNET_assert (cfg != NULL);
730 pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext));
733 GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts",
734 &pg_start_ctx->connect_attempts))
736 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
737 "testing", "connect_attempts");
738 GNUNET_free (pg_start_ctx);
743 GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
744 "max_outstanding_connections",
745 &pg_start_ctx->max_concurrent_connections))
747 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
748 "testing", "max_outstanding_connections");
749 GNUNET_free (pg_start_ctx);
754 GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
755 "max_concurrent_ssh",
756 &pg_start_ctx->max_concurrent_ssh))
758 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
759 "testing", "max_concurrent_ssh");
760 GNUNET_free (pg_start_ctx);
765 (pg_start_ctx->verbose =
766 GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing",
767 "use_progressbars")))
769 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
770 "testing", "use_progressbars");
771 GNUNET_free (pg_start_ctx);
776 GNUNET_CONFIGURATION_get_value_number (cfg, "testing",
778 &temp_config_number))
779 pg_start_ctx->timeout =
780 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply
781 (GNUNET_TIME_UNIT_SECONDS,
782 temp_config_number));
785 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
786 "testing", "peergroup_timeout");
787 GNUNET_free (pg_start_ctx);
792 /* Read topology related options from the configuration file */
795 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology",
798 GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str)))
800 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
801 "Invalid topology `%s' given for section %s option %s\n",
802 temp_str, "TESTING", "TOPOLOGY");
803 pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
805 GNUNET_free_non_null (temp_str);
808 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
809 "topology_output_file", &temp_str))
811 pg_start_ctx->topology_output_file =
812 GNUNET_DISK_file_open (temp_str,
813 GNUNET_DISK_OPEN_READWRITE |
814 GNUNET_DISK_OPEN_CREATE,
815 GNUNET_DISK_PERM_USER_READ |
816 GNUNET_DISK_PERM_USER_WRITE);
817 if (pg_start_ctx->topology_output_file != NULL)
819 GNUNET_free (temp_str);
820 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
822 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
825 GNUNET_free (temp_str);
829 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage",
831 pg_start_ctx->topology_percentage = 0.5;
834 pg_start_ctx->topology_percentage = atof (temp_str);
835 GNUNET_free (temp_str);
839 GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability",
841 pg_start_ctx->topology_probability = 0.5;
844 pg_start_ctx->topology_probability = atof (temp_str);
845 GNUNET_free (temp_str);
849 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
850 "connect_topology", &temp_str)) &&
852 GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str)))
854 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
855 "Invalid connect topology `%s' given for section %s option %s\n",
856 temp_str, "TESTING", "CONNECT_TOPOLOGY");
858 GNUNET_free_non_null (temp_str);
861 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
862 "connect_topology_option",
865 GNUNET_TESTING_topology_option_get
866 (&pg_start_ctx->connect_topology_option, temp_str)))
868 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
869 "Invalid connect topology option `%s' given for section %s option %s\n",
870 temp_str, "TESTING", "CONNECT_TOPOLOGY_OPTION");
871 pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
873 GNUNET_free_non_null (temp_str);
876 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
877 "connect_topology_option_modifier",
881 (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1)
883 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
885 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
886 temp_str, "connect_topology_option_modifier", "TESTING");
887 GNUNET_free (temp_str);
888 GNUNET_free (pg_start_ctx);
891 GNUNET_free (temp_str);
895 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
896 "blacklist_transports",
897 &pg_start_ctx->restrict_transports))
898 pg_start_ctx->restrict_transports = NULL;
900 pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE;
902 GNUNET_CONFIGURATION_get_value_string (cfg, "testing",
903 "blacklist_topology", &temp_str))
905 GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology,
908 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
909 "Invalid topology `%s' given for section %s option %s\n",
910 temp_str, "TESTING", "BLACKLIST_TOPOLOGY");
913 GNUNET_free_non_null (temp_str);
915 pg_start_ctx->cfg = cfg;
916 pg_start_ctx->total = total;
917 pg_start_ctx->peers_left = total;
918 pg_start_ctx->connect_cb = connect_cb;
919 pg_start_ctx->peergroup_cb = peergroup_cb;
920 pg_start_ctx->cls = peergroup_cls;
921 pg_start_ctx->hostnames = hostnames;
922 pg_start_ctx->hostkey_meter =
923 create_meter (pg_start_ctx->peers_left, "Hostkeys created ",
924 pg_start_ctx->verbose);
925 pg_start_ctx->peer_start_meter =
926 create_meter (pg_start_ctx->peers_left, "Peers started ",
927 pg_start_ctx->verbose);
928 /* Make compilers happy */
929 reset_meter (pg_start_ctx->peer_start_meter);
930 pg_start_ctx->fail_reason =
932 ("didn't generate all hostkeys within allowed startup time!");
933 pg_start_ctx->die_task =
934 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
935 (pg_start_ctx->timeout), &end_badly,
939 GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left,
940 pg_start_ctx->max_concurrent_connections,
941 pg_start_ctx->max_concurrent_ssh,
942 GNUNET_TIME_absolute_get_remaining
943 (pg_start_ctx->timeout),
944 &internal_hostkey_callback, pg_start_ctx,
945 &internal_peers_started_callback,
946 pg_start_ctx, &internal_topology_callback,
947 pg_start_ctx, pg_start_ctx->hostnames);
949 return pg_start_ctx->pg;
952 /* end of testing_peergroup.c */