aboutsummaryrefslogtreecommitdiff
path: root/src/testing_old/testing_peergroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing_old/testing_peergroup.c')
-rw-r--r--src/testing_old/testing_peergroup.c1017
1 files changed, 0 insertions, 1017 deletions
diff --git a/src/testing_old/testing_peergroup.c b/src/testing_old/testing_peergroup.c
deleted file mode 100644
index acd68dd3c..000000000
--- a/src/testing_old/testing_peergroup.c
+++ /dev/null
@@ -1,1017 +0,0 @@
1/*
2 This file is part of GNUnet
3 (C) 2008-2011 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21/**
22 * @file testing_old/testing_peergroup.c
23 * @brief API implementation for easy peer group creation
24 * @author Nathan Evans
25 * @author Christian Grothoff
26 *
27 */
28#include "platform.h"
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"
34
35/** Globals **/
36#define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
37
38#define DEFAULT_CONNECT_ATTEMPTS 2
39
40/** Struct definitions **/
41
42struct PeerGroupStartupContext
43{
44 struct GNUNET_TESTING_PeerGroup *pg;
45 const struct GNUNET_CONFIGURATION_Handle *cfg;
46 unsigned int total;
47 unsigned int peers_left;
48 unsigned long long max_concurrent_connections;
49
50 /**
51 * Maximum attemps to connect two daemons.
52 */
53 unsigned long long connect_attempts;
54
55 /**
56 * How long to spend trying to establish all the connections?
57 */
58 struct GNUNET_TIME_Relative connect_timeout;
59
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;
64
65 /**
66 * Closure for all peergroup callbacks.
67 */
68 void *cls;
69
70 const struct GNUNET_TESTING_Host *hostnames;
71
72 /**
73 * FIXME document
74 */
75 enum GNUNET_TESTING_Topology topology;
76
77 float topology_percentage;
78
79 float topology_probability;
80
81 /**
82 * FIXME document
83 */
84 enum GNUNET_TESTING_Topology restrict_topology;
85
86 /**
87 * FIXME document
88 */
89 char *restrict_transports;
90
91 /**
92 * Initial connections
93 */
94 enum GNUNET_TESTING_Topology connect_topology;
95 enum GNUNET_TESTING_TopologyOption connect_topology_option;
96 double connect_topology_option_modifier;
97 int verbose;
98
99 struct ProgressMeter *hostkey_meter;
100 struct ProgressMeter *peer_start_meter;
101 struct ProgressMeter *connect_meter;
102
103 /**
104 * Task used to kill the peergroup.
105 */
106 GNUNET_SCHEDULER_TaskIdentifier die_task;
107
108 char *fail_reason;
109
110 /**
111 * Variable used to store the number of connections we should wait for.
112 */
113 unsigned int expected_connections;
114
115 /**
116 * Time when the connecting peers was started.
117 */
118 struct GNUNET_TIME_Absolute connect_start_time;
119
120 /**
121 * The total number of connections that have been created so far.
122 */
123 unsigned int total_connections;
124
125 /**
126 * The total number of connections that have failed so far.
127 */
128 unsigned int failed_connections;
129
130 /**
131 * File handle to write out topology in dot format.
132 */
133 struct GNUNET_DISK_FileHandle *topology_output_file;
134};
135
136struct TopologyOutputContext
137{
138 struct GNUNET_DISK_FileHandle *file;
139 GNUNET_TESTING_NotifyCompletion notify_cb;
140 void *notify_cb_cls;
141};
142
143/**
144 * Simple struct to keep track of progress, and print a
145 * percentage meter for long running tasks.
146 */
147struct ProgressMeter
148{
149 /**
150 * Total number of tasks to complete.
151 */
152 unsigned int total;
153
154 /**
155 * Print percentage done after modnum tasks.
156 */
157 unsigned int modnum;
158
159 /**
160 * Print a . each dotnum tasks.
161 */
162 unsigned int dotnum;
163
164 /**
165 * Total number completed thus far.
166 */
167 unsigned int completed;
168
169 /**
170 * Whether or not to print.
171 */
172 int print;
173
174 /**
175 * Startup string for progress meter.
176 */
177 char *startup_string;
178};
179
180
181/** Utility functions **/
182
183/**
184 * Create a meter to keep track of the progress of some task.
185 *
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
189 * internally only
190 *
191 * @return the progress meter
192 */
193static struct ProgressMeter *
194create_meter (unsigned int total, char *start_string, int print)
195{
196 struct ProgressMeter *ret;
197
198 ret = GNUNET_malloc (sizeof (struct ProgressMeter));
199 ret->print = print;
200 ret->total = total;
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);
205 else
206 ret->startup_string = GNUNET_strdup ("");
207
208 return ret;
209}
210
211/**
212 * Update progress meter (increment by one).
213 *
214 * @param meter the meter to update and print info for
215 *
216 * @return GNUNET_YES if called the total requested,
217 * GNUNET_NO if more items expected
218 */
219static int
220update_meter (struct ProgressMeter *meter)
221{
222 if (meter->print == GNUNET_YES)
223 {
224 if (meter->completed % meter->modnum == 0)
225 {
226 if (meter->completed == 0)
227 {
228 FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string);
229 }
230 else
231 FPRINTF (stdout, "%d%%",
232 (int) (((float) meter->completed / meter->total) * 100));
233 }
234 else if (meter->completed % meter->dotnum == 0)
235 FPRINTF (stdout, "%s", ".");
236
237 if (meter->completed + 1 == meter->total)
238 FPRINTF (stdout, "%d%%]\n", 100);
239 fflush (stdout);
240 }
241 meter->completed++;
242
243 if (meter->completed == meter->total)
244 return GNUNET_YES;
245 return GNUNET_NO;
246}
247
248/**
249 * Reset progress meter.
250 *
251 * @param meter the meter to reset
252 *
253 * @return GNUNET_YES if meter reset,
254 * GNUNET_SYSERR on error
255 */
256static int
257reset_meter (struct ProgressMeter *meter)
258{
259 if (meter == NULL)
260 return GNUNET_SYSERR;
261
262 meter->completed = 0;
263 return GNUNET_YES;
264}
265
266/**
267 * Release resources for meter
268 *
269 * @param meter the meter to free
270 */
271static void
272free_meter (struct ProgressMeter *meter)
273{
274 GNUNET_free_non_null (meter->startup_string);
275 GNUNET_free (meter);
276}
277
278
279/** Functions for creating, starting and connecting the peergroup **/
280
281/**
282 * Check whether peers successfully shut down.
283 */
284static void
285internal_shutdown_callback (void *cls, const char *emsg)
286{
287 struct PeerGroupStartupContext *pg_start_ctx = cls;
288
289 if (emsg != NULL)
290 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg);
291 else
292 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason);
293}
294
295/**
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
298 * test.
299 */
300static void
301end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
302{
303 struct PeerGroupStartupContext *pg_start_ctx = cls;
304
305 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
306 "Failing peer group startup with error: `%s'!\n",
307 pg_start_ctx->fail_reason);
308
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);
313
314 if (pg_start_ctx->hostkey_meter != NULL)
315 {
316 free_meter (pg_start_ctx->hostkey_meter);
317 pg_start_ctx->hostkey_meter = NULL;
318 }
319 if (pg_start_ctx->peer_start_meter != NULL)
320 {
321 free_meter (pg_start_ctx->peer_start_meter);
322 pg_start_ctx->peer_start_meter = NULL;
323 }
324 if (pg_start_ctx->connect_meter != NULL)
325 {
326 free_meter (pg_start_ctx->connect_meter);
327 pg_start_ctx->connect_meter = NULL;
328 }
329}
330
331/**
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.
336 *
337 * The emsg variable is NULL on success (peers connected), and non-NULL on
338 * failure (peers failed to connect).
339 */
340static void
341internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first,
342 const struct GNUNET_PeerIdentity *second,
343 uint32_t distance,
344 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
345 const struct GNUNET_CONFIGURATION_Handle
346 *second_cfg,
347 struct GNUNET_TESTING_Daemon *first_daemon,
348 struct GNUNET_TESTING_Daemon *second_daemon,
349 const char *emsg)
350{
351 struct PeerGroupStartupContext *pg_start_ctx = cls;
352 char *temp_str;
353 char *second_str;
354 int temp;
355
356#if TIMING
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;
365#endif
366
367#if TIMING
368 if (GNUNET_TIME_absolute_get_difference
369 (connect_last_time,
370 GNUNET_TIME_absolute_get ()).rel_value >
371 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
372 CONN_UPDATE_DURATION).rel_value)
373 {
374 /* Get number of new connections */
375 new_connections = total_connections - previous_connections;
376
377 /* Get number of new FAILED connections */
378 new_failed_connections = failed_connections - previous_failed_connections;
379
380 /* Get duration in seconds */
381 duration =
382 GNUNET_TIME_absolute_get_difference (connect_last_time,
383 GNUNET_TIME_absolute_get
384 ()).rel_value / 1000;
385 total_duration =
386 GNUNET_TIME_absolute_get_difference (connect_start_time,
387 GNUNET_TIME_absolute_get
388 ()).rel_value / 1000;
389
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,
403 failed_connections);
404 }
405#endif
406
407
408 if (emsg == NULL)
409 {
410 pg_start_ctx->total_connections++;
411#if VERBOSE > 1
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);
415#endif
416 if (pg_start_ctx->topology_output_file != NULL)
417 {
418 second_str = GNUNET_strdup (GNUNET_i2s (second));
419 temp =
420 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n",
421 GNUNET_i2s (first), second_str);
422 GNUNET_free (second_str);
423 if (temp > 0)
424 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
425 temp);
426 GNUNET_free (temp_str);
427 }
428 }
429 else
430 {
431 pg_start_ctx->failed_connections++;
432#if VERBOSE
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);
436
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);
440#endif
441 }
442
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))
449 {
450 /* No finished yet */
451 return;
452 }
453#if VERBOSE
454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455 "Created %d total connections, which is our target number! Starting next phase of testing.\n",
456 pg_start_ctx->total_connections);
457#endif
458
459#if TIMING
460 total_duration =
461 GNUNET_TIME_absolute_get_difference (connect_start_time,
462 GNUNET_TIME_absolute_get
463 ()).rel_value / 1000;
464 failed_conns_per_sec_total = (double) failed_connections / total_duration;
465 conns_per_sec_total = (double) total_connections / total_duration;
466 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
467 "Overall connection info --- Total: %u, Total Failed %u/s\n",
468 total_connections, failed_connections);
469 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
470 "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n",
471 conns_per_sec_total, failed_conns_per_sec_total);
472#endif
473
474 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
475 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
476
477 /* Call final callback, signifying that the peer group has been started and connected */
478 if (pg_start_ctx->peergroup_cb != NULL)
479 pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL);
480
481 if (pg_start_ctx->topology_output_file != NULL)
482 {
483 temp = GNUNET_asprintf (&temp_str, "}\n");
484 if (temp > 0)
485 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
486 temp);
487 GNUNET_free (temp_str);
488 GNUNET_DISK_file_close (pg_start_ctx->topology_output_file);
489 }
490 GNUNET_free_non_null (pg_start_ctx->fail_reason);
491 if (NULL != pg_start_ctx->hostkey_meter)
492 free_meter(pg_start_ctx->hostkey_meter);
493 if (NULL != pg_start_ctx->peer_start_meter)
494 free_meter(pg_start_ctx->peer_start_meter);
495 if (NULL != pg_start_ctx->connect_meter)
496 free_meter(pg_start_ctx->connect_meter);
497 GNUNET_free (pg_start_ctx);
498}
499
500
501/**
502 * Callback called for each started daemon.
503 *
504 * @param cls Clause (PG Context).
505 * @param id PeerIdentidy of started daemon.
506 * @param cfg Configuration used by the daemon.
507 * @param d Handle for the daemon.
508 * @param emsg Error message, NULL on success.
509 */
510static void
511internal_peers_started_callback (void *cls,
512 const struct GNUNET_PeerIdentity *id,
513 const struct GNUNET_CONFIGURATION_Handle *cfg,
514 struct GNUNET_TESTING_Daemon *d,
515 const char *emsg)
516{
517 struct PeerGroupStartupContext *pg_start_ctx = cls;
518
519 if (emsg != NULL)
520 {
521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522 "Failed to start daemon with error: `%s'\n", emsg);
523 return;
524 }
525 GNUNET_assert (id != NULL);
526
527#if VERBOSE > 1
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n",
529 (pg_start_ctx->total - pg_start_ctx->peers_left) + 1,
530 pg_start_ctx->total);
531#endif
532
533 pg_start_ctx->peers_left--;
534
535 if (NULL == pg_start_ctx->peer_start_meter)
536 {
537 /* Cancelled Ctrl-C or error */
538 return;
539 }
540 if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter))
541 {
542#if VERBOSE
543 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544 "All %d daemons started, now connecting peers!\n",
545 pg_start_ctx->total);
546#endif
547 GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK);
548 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
549
550 pg_start_ctx->expected_connections = UINT_MAX;
551 // FIXME: why whould peers_left be != 0?? Or pg NULL?
552 if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0))
553 {
554 pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get ();
555 pg_start_ctx->expected_connections =
556 GNUNET_TESTING_connect_topology (pg_start_ctx->pg,
557 pg_start_ctx->connect_topology,
558 pg_start_ctx->connect_topology_option,
559 pg_start_ctx->connect_topology_option_modifier,
560 pg_start_ctx->connect_timeout,
561 pg_start_ctx->connect_attempts, NULL,
562 NULL);
563
564 pg_start_ctx->connect_meter =
565 create_meter (pg_start_ctx->expected_connections, "Peer connection ",
566 pg_start_ctx->verbose);
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n",
568 pg_start_ctx->expected_connections);
569 }
570
571 if (pg_start_ctx->expected_connections == 0)
572 {
573 GNUNET_free_non_null (pg_start_ctx->fail_reason);
574 pg_start_ctx->fail_reason =
575 GNUNET_strdup ("from connect topology (bad return)");
576 pg_start_ctx->die_task =
577 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
578 return;
579 }
580
581 GNUNET_free_non_null (pg_start_ctx->fail_reason);
582 pg_start_ctx->fail_reason =
583 GNUNET_strdup ("from connect topology (timeout)");
584 pg_start_ctx->die_task =
585 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
586 (pg_start_ctx->timeout), &end_badly,
587 pg_start_ctx);
588 }
589}
590
591/**
592 * Callback indicating that the hostkey was created for a peer.
593 *
594 * @param cls NULL
595 * @param id the peer identity
596 * @param d the daemon handle (pretty useless at this point, remove?)
597 * @param emsg non-null on failure
598 */
599static void
600internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id,
601 struct GNUNET_TESTING_Daemon *d, const char *emsg)
602{
603 struct PeerGroupStartupContext *pg_start_ctx = cls;
604 unsigned int create_expected_connections;
605
606 if (emsg != NULL)
607 {
608 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
609 "Hostkey callback received error: %s\n", emsg);
610 }
611
612#if VERBOSE > 1
613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
614 "Hostkey (%d/%d) created for peer `%s'\n",
615 pg_start_ctx->total - pg_start_ctx->peers_left + 1,
616 pg_start_ctx->total, GNUNET_i2s (id));
617#endif
618
619 pg_start_ctx->peers_left--;
620 if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter))
621 {
622 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
623 GNUNET_free_non_null (pg_start_ctx->fail_reason);
624 /* Set up task in case topology creation doesn't finish
625 * within a reasonable amount of time */
626 pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology");
627 pg_start_ctx->die_task =
628 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
629 (pg_start_ctx->timeout), &end_badly,
630 pg_start_ctx);
631 pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */
632 create_expected_connections =
633 GNUNET_TESTING_create_topology (pg_start_ctx->pg,
634 pg_start_ctx->topology,
635 pg_start_ctx->restrict_topology,
636 pg_start_ctx->restrict_transports);
637 if (create_expected_connections > 0)
638 {
639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640 "Topology set up, have %u expected connections, now starting peers!\n",
641 create_expected_connections);
642 GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg);
643 }
644 else
645 {
646 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
647 GNUNET_free_non_null (pg_start_ctx->fail_reason);
648 pg_start_ctx->fail_reason =
649 GNUNET_strdup ("from create topology (bad return)");
650 pg_start_ctx->die_task =
651 GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx);
652 return;
653 }
654
655 GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task);
656 GNUNET_free_non_null (pg_start_ctx->fail_reason);
657 pg_start_ctx->fail_reason =
658 GNUNET_strdup ("from continue startup (timeout)");
659 pg_start_ctx->die_task =
660 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
661 (pg_start_ctx->timeout), &end_badly,
662 pg_start_ctx);
663 }
664}
665
666
667/**
668 * Prototype of a callback function indicating that two peers
669 * are currently connected.
670 *
671 * @param cls closure
672 * @param first peer id for first daemon
673 * @param second peer id for the second daemon
674 * @param emsg error message (NULL on success)
675 */
676void
677write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first,
678 const struct GNUNET_PeerIdentity *second, const char *emsg)
679{
680 struct TopologyOutputContext *topo_ctx;
681 int temp;
682 char *temp_str;
683 char *temp_pid2;
684
685 topo_ctx = (struct TopologyOutputContext *) cls;
686 GNUNET_assert (topo_ctx->file != NULL);
687 if ((emsg == NULL) && (first != NULL) && (second != NULL))
688 {
689 GNUNET_assert (first != NULL);
690 GNUNET_assert (second != NULL);
691 temp_pid2 = GNUNET_strdup (GNUNET_i2s (second));
692 temp =
693 GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first),
694 temp_pid2);
695 GNUNET_free (temp_pid2);
696 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
697 }
698 else if ((emsg == NULL) && (first == NULL) && (second == NULL))
699 {
700 temp = GNUNET_asprintf (&temp_str, "}\n");
701 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
702 GNUNET_DISK_file_close (topo_ctx->file);
703 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL);
704 GNUNET_free (topo_ctx);
705 }
706 else
707 {
708 temp = GNUNET_asprintf (&temp_str, "}\n");
709 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
710 GNUNET_DISK_file_close (topo_ctx->file);
711 topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg);
712 GNUNET_free (topo_ctx);
713 }
714}
715
716/**
717 * Print current topology to a graphviz readable file.
718 *
719 * @param pg a currently running peergroup to print to file
720 * @param output_filename the file to write the topology to
721 * @param notify_cb callback to call upon completion or failure
722 * @param notify_cb_cls closure for notify_cb
723 *
724 */
725void
726GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg,
727 const char *output_filename,
728 GNUNET_TESTING_NotifyCompletion
729 notify_cb, void *notify_cb_cls)
730{
731 struct TopologyOutputContext *topo_ctx;
732 int temp;
733 char *temp_str;
734
735 topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext));
736
737 topo_ctx->notify_cb = notify_cb;
738 topo_ctx->notify_cb_cls = notify_cb_cls;
739 topo_ctx->file =
740 GNUNET_DISK_file_open (output_filename,
741 GNUNET_DISK_OPEN_READWRITE |
742 GNUNET_DISK_OPEN_CREATE,
743 GNUNET_DISK_PERM_USER_READ |
744 GNUNET_DISK_PERM_USER_WRITE);
745 if (topo_ctx->file == NULL)
746 {
747 notify_cb (notify_cb_cls, "Failed to open output file!");
748 GNUNET_free (topo_ctx);
749 return;
750 }
751
752 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
753 if (temp > 0)
754 GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp);
755 GNUNET_free_non_null (temp_str);
756 GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx);
757}
758
759/**
760 * Start a peer group with a given number of peers. Notify
761 * on completion of peer startup and connection based on given
762 * topological constraints. Optionally notify on each
763 * established connection.
764 *
765 * @param cfg configuration template to use
766 * @param total number of daemons to start
767 * @param timeout total time allowed for peers to start
768 * @param connect_cb function to call each time two daemons are connected
769 * @param peergroup_cb function to call once all peers are up and connected
770 * @param peergroup_cls closure for peergroup callbacks
771 * @param hostnames linked list of host structs to use to start peers on
772 * (NULL to run on localhost only)
773 *
774 * @return NULL on error, otherwise handle to control peer group
775 */
776struct GNUNET_TESTING_PeerGroup *
777GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
778 unsigned int total,
779 struct GNUNET_TIME_Relative timeout,
780 GNUNET_TESTING_NotifyConnection connect_cb,
781 GNUNET_TESTING_NotifyCompletion peergroup_cb,
782 void *peergroup_cls,
783 const struct GNUNET_TESTING_Host *hostnames)
784{
785 struct PeerGroupStartupContext *pg_start_ctx;
786 char *temp_str;
787 int temp;
788 struct GNUNET_TIME_Relative rtimeout;
789
790 GNUNET_assert (total > 0);
791 GNUNET_assert (cfg != NULL);
792
793 pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext));
794
795 if (GNUNET_OK !=
796 GNUNET_CONFIGURATION_get_value_number (cfg, "testing_old", "connect_attempts",
797 &pg_start_ctx->connect_attempts))
798 {
799 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
800 "testing_old", "connect_attempts");
801 GNUNET_free (pg_start_ctx);
802 return NULL;
803 }
804
805 if (GNUNET_OK !=
806 GNUNET_CONFIGURATION_get_value_time (cfg, "testing_old", "CONNECT_TIMEOUT",
807 &pg_start_ctx->connect_timeout))
808 {
809 pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT;
810 }
811
812 if (GNUNET_OK !=
813 GNUNET_CONFIGURATION_get_value_number (cfg, "testing_old",
814 "max_outstanding_connections",
815 &pg_start_ctx->max_concurrent_connections))
816 {
817 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
818 "testing_old", "max_outstanding_connections");
819 GNUNET_free (pg_start_ctx);
820 return NULL;
821 }
822
823 if (GNUNET_OK !=
824 GNUNET_CONFIGURATION_get_value_number (cfg, "testing_old",
825 "max_concurrent_ssh",
826 &pg_start_ctx->max_concurrent_ssh))
827 {
828 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
829 "testing_old", "max_concurrent_ssh");
830 GNUNET_free (pg_start_ctx);
831 return NULL;
832 }
833
834 if (GNUNET_SYSERR ==
835 (pg_start_ctx->verbose =
836 GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing_old",
837 "use_progressbars")))
838 {
839 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
840 "testing_old", "use_progressbars");
841 GNUNET_free (pg_start_ctx);
842 return NULL;
843 }
844
845 if (GNUNET_OK !=
846 GNUNET_CONFIGURATION_get_value_time (cfg, "testing_old", "PEERGROUP_TIMEOUT",
847 &rtimeout))
848 {
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n",
850 "testing_old", "PEERGROUP_TIMEOUT");
851 GNUNET_free (pg_start_ctx);
852 return NULL;
853 }
854 pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout);
855
856
857 /* Read topology related options from the configuration file */
858 temp_str = NULL;
859 if ((GNUNET_YES ==
860 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", "topology",
861 &temp_str)) &&
862 (GNUNET_NO ==
863 GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str)))
864 {
865 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
866 "Invalid topology `%s' given for section %s option %s\n",
867 temp_str, "TESTING_old", "TOPOLOGY");
868 pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */
869 }
870 GNUNET_free_non_null (temp_str);
871
872 if (GNUNET_YES ==
873 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old",
874 "topology_output_file", &temp_str))
875 {
876 pg_start_ctx->topology_output_file =
877 GNUNET_DISK_file_open (temp_str,
878 GNUNET_DISK_OPEN_READWRITE |
879 GNUNET_DISK_OPEN_CREATE,
880 GNUNET_DISK_PERM_USER_READ |
881 GNUNET_DISK_PERM_USER_WRITE);
882 if (pg_start_ctx->topology_output_file != NULL)
883 {
884 GNUNET_free (temp_str);
885 temp = GNUNET_asprintf (&temp_str, "strict graph G {\n");
886 if (temp > 0)
887 GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str,
888 temp);
889 }
890 GNUNET_free (temp_str);
891 }
892
893 if (GNUNET_OK !=
894 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", "percentage",
895 &temp_str))
896 pg_start_ctx->topology_percentage = 0.5;
897 else
898 {
899 pg_start_ctx->topology_percentage = atof (temp_str);
900 GNUNET_free (temp_str);
901 }
902
903 if (GNUNET_OK !=
904 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", "probability",
905 &temp_str))
906 pg_start_ctx->topology_probability = 0.5;
907 else
908 {
909 pg_start_ctx->topology_probability = atof (temp_str);
910 GNUNET_free (temp_str);
911 }
912
913 if ((GNUNET_YES ==
914 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old",
915 "connect_topology", &temp_str)) &&
916 (GNUNET_NO ==
917 GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str)))
918 {
919 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
920 "Invalid connect topology `%s' given for section %s option %s\n",
921 temp_str, "TESTING_old", "CONNECT_TOPOLOGY");
922 }
923 GNUNET_free_non_null (temp_str);
924
925 if ((GNUNET_YES ==
926 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old",
927 "connect_topology_option",
928 &temp_str)) &&
929 (GNUNET_NO ==
930 GNUNET_TESTING_topology_option_get
931 (&pg_start_ctx->connect_topology_option, temp_str)))
932 {
933 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
934 "Invalid connect topology option `%s' given for section %s option %s\n",
935 temp_str, "TESTING_old", "CONNECT_TOPOLOGY_OPTION");
936 pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */
937 }
938 GNUNET_free_non_null (temp_str);
939
940 if (GNUNET_YES ==
941 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old",
942 "connect_topology_option_modifier",
943 &temp_str))
944 {
945 if (SSCANF
946 (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1)
947 {
948 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
949 _
950 ("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
951 temp_str, "connect_topology_option_modifier", "TESTING_old");
952 GNUNET_free (temp_str);
953 GNUNET_free (pg_start_ctx);
954 return NULL;
955 }
956 GNUNET_free (temp_str);
957 }
958
959 if (GNUNET_YES !=
960 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old",
961 "blacklist_transports",
962 &pg_start_ctx->restrict_transports))
963 pg_start_ctx->restrict_transports = NULL;
964
965 pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE;
966 if ((GNUNET_YES ==
967 GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old",
968 "blacklist_topology", &temp_str))
969 && (GNUNET_NO ==
970 GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology,
971 temp_str)))
972 {
973 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
974 "Invalid topology `%s' given for section %s option %s\n",
975 temp_str, "TESTING_OLD", "BLACKLIST_TOPOLOGY");
976 }
977
978 GNUNET_free_non_null (temp_str);
979
980 pg_start_ctx->cfg = cfg;
981 pg_start_ctx->total = total;
982 pg_start_ctx->peers_left = total;
983 pg_start_ctx->connect_cb = connect_cb;
984 pg_start_ctx->peergroup_cb = peergroup_cb;
985 pg_start_ctx->cls = peergroup_cls;
986 pg_start_ctx->hostnames = hostnames;
987 pg_start_ctx->hostkey_meter =
988 create_meter (pg_start_ctx->peers_left, "Hostkeys created ",
989 pg_start_ctx->verbose);
990 pg_start_ctx->peer_start_meter =
991 create_meter (pg_start_ctx->peers_left, "Peers started ",
992 pg_start_ctx->verbose);
993 /* Make compilers happy */
994 reset_meter (pg_start_ctx->peer_start_meter);
995 pg_start_ctx->fail_reason =
996 GNUNET_strdup
997 ("didn't generate all hostkeys within allowed startup time!");
998 pg_start_ctx->die_task =
999 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
1000 (pg_start_ctx->timeout), &end_badly,
1001 pg_start_ctx);
1002
1003 pg_start_ctx->pg =
1004 GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left,
1005 pg_start_ctx->max_concurrent_connections,
1006 pg_start_ctx->max_concurrent_ssh,
1007 GNUNET_TIME_absolute_get_remaining
1008 (pg_start_ctx->timeout),
1009 &internal_hostkey_callback, pg_start_ctx,
1010 &internal_peers_started_callback,
1011 pg_start_ctx, &internal_topology_callback,
1012 pg_start_ctx, pg_start_ctx->hostnames);
1013
1014 return pg_start_ctx->pg;
1015}
1016
1017/* end of testing_peergroup.c */