summaryrefslogtreecommitdiff
path: root/src/testing
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-07-29 08:05:52 +0000
committerChristian Grothoff <christian@grothoff.org>2009-07-29 08:05:52 +0000
commitb80e650bad570e01b5600aab2a667d177fc17770 (patch)
treeae5b933796c34f8c0e56f54448da98c4174f683c /src/testing
parent673dda8cec9a607d77543abd697982fc1fe9e271 (diff)
travelhacking
Diffstat (limited to 'src/testing')
-rw-r--r--src/testing/Makefile.am29
-rw-r--r--src/testing/test_testing.c116
-rw-r--r--src/testing/test_testing_data.conf29
-rw-r--r--src/testing/testing.c186
-rw-r--r--src/testing/testing_group.c315
5 files changed, 547 insertions, 128 deletions
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 635570482..9ac831a88 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -15,17 +15,20 @@ libgnunettesting_la_SOURCES = \
testing.c \
testing_group.c \
testing_testbed.c
-libgnunettesting_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la $(XLIB)
-
-#check_PROGRAMS = \
-# test_testing
-#
-#TESTS = $(check_PROGRAMS)
-#
-#test_testing_SOURCES = \
-# test_testing.c
-#test_testing_LDADD = \
-# $(top_builddir)/src/testing/libgnunettesting.la \
-# $(top_builddir)/src/util/libgnunetutil.la
+libgnunettesting_la_LIBADD = $(XLIB) \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+check_PROGRAMS = \
+ test_testing
+
+TESTS = $(check_PROGRAMS)
+
+test_testing_SOURCES = \
+ test_testing.c
+test_testing_LDADD = \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+EXTRA_DIST = test_testing_data.conf
diff --git a/src/testing/test_testing.c b/src/testing/test_testing.c
new file mode 100644
index 000000000..cbedf60fb
--- /dev/null
+++ b/src/testing/test_testing.c
@@ -0,0 +1,116 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file testing/test_testing.c
+ * @brief testcase for testing.c
+ */
+#include "platform.h"
+#include "gnunet_testing_lib.h"
+
+#define VERBOSE GNUNET_YES
+
+static int ok;
+
+static void end_cb(void *cls,
+ const char *emsg)
+{
+ GNUNET_assert (emsg == NULL);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Daemon terminated, will now exit.\n");
+#endif
+ ok = 0;
+}
+
+static void my_cb(void *cls,
+ const struct GNUNET_PeerIdentity *id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct GNUNET_TESTING_Daemon *d,
+ const char *emsg)
+{
+ GNUNET_assert (id != NULL);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Daemon started, will now stop it.\n");
+#endif
+ GNUNET_TESTING_daemon_stop (d, &end_cb, NULL);
+}
+
+
+static void
+run (void *cls,
+ struct GNUNET_SCHEDULER_Handle *sched,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct GNUNET_TESTING_Daemon *d;
+
+ ok = 1;
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Starting daemon.\n");
+#endif
+ d = GNUNET_TESTING_daemon_start (sched,
+ cfg,
+ NULL,
+ &my_cb,
+ NULL);
+ GNUNET_assert (d != NULL);
+}
+
+static int
+check ()
+{
+ char *const argv[] = { "test-testing",
+ "-c",
+ "test_testing_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+ argv, "test-tesing", "nohelp",
+ options, &run, &ok);
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_log_setup ("test-testing",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+ ret = check ();
+
+ return ret;
+}
+
+/* end of test_testing.c */
diff --git a/src/testing/test_testing_data.conf b/src/testing/test_testing_data.conf
new file mode 100644
index 000000000..7c46fdf34
--- /dev/null
+++ b/src/testing/test_testing_data.conf
@@ -0,0 +1,29 @@
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-testing/
+DEFAULTCONFIG = test_testing_data.conf
+
+[resolver]
+PORT = 2564
+
+[transport]
+PORT = 2565
+PLUGINS = tcp
+
+[arm]
+PORT = 2566
+DEFAULTSERVICES = transport core
+
+[statistics]
+PORT = 2567
+
+[tcp]
+PORT = 2568
+
+[peerinfo]
+PORT = 2569
+
+[core]
+PORT = 2570
+
+[testing]
+WEAKRANDOM = YES
diff --git a/src/testing/testing.c b/src/testing/testing.c
index 3406355c5..5d465e05f 100644
--- a/src/testing/testing.c
+++ b/src/testing/testing.c
@@ -85,7 +85,7 @@ struct GNUNET_TESTING_Daemon
/**
* Our configuration.
*/
- const struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Host to run GNUnet on.
@@ -202,10 +202,11 @@ testing_init (void *cls,
d->cb = NULL;
if (server == NULL)
{
- cb (d->cb_cls, NULL, d->cfg, d,
- _("Failed to connect to core service\n"));
if (GNUNET_YES == d->dead)
GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
+ else if (NULL != cb)
+ cb (d->cb_cls, NULL, d->cfg, d,
+ _("Failed to connect to core service\n"));
return;
}
#if DEBUG_TESTING
@@ -216,7 +217,7 @@ testing_init (void *cls,
d->id = *my_identity;
if (GNUNET_YES == d->dead)
GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
- else
+ else if (NULL != cb)
cb (d->cb_cls, my_identity, d->cfg, d, NULL);
d->server = server;
}
@@ -240,6 +241,11 @@ start_fsm (void *cls,
unsigned long code;
char *dst;
+#if DEBUG_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer FSM is in phase %u.\n",
+ d->phase);
+#endif
d->task = GNUNET_SCHEDULER_NO_TASK;
switch (d->phase)
{
@@ -255,11 +261,12 @@ start_fsm (void *cls,
{
cb = d->cb;
d->cb = NULL;
- cb (d->cb_cls,
- NULL,
- d->cfg,
- d,
- _("`scp' does not seem to terminate.\n"));
+ if (NULL != cb)
+ cb (d->cb_cls,
+ NULL,
+ d->cfg,
+ d,
+ _("`scp' does not seem to terminate.\n"));
return;
}
/* wait some more */
@@ -278,11 +285,12 @@ start_fsm (void *cls,
{
cb = d->cb;
d->cb = NULL;
- cb (d->cb_cls,
- NULL,
- d->cfg,
- d,
- _("`scp' did not complete cleanly.\n"));
+ if (NULL != cb)
+ cb (d->cb_cls,
+ NULL,
+ d->cfg,
+ d,
+ _("`scp' did not complete cleanly.\n"));
return;
}
#if DEBUG_TESTING
@@ -299,7 +307,11 @@ start_fsm (void *cls,
"gnunet-service-arm",
"-c",
d->cfgfile,
+#if DEBUG_TESTING
+ "-L", "DEBUG",
+#else
"-d",
+#endif
NULL);
}
else
@@ -328,16 +340,31 @@ start_fsm (void *cls,
(NULL == d->hostname) ? "gnunet-service-arm" : "ssh");
cb = d->cb;
d->cb = NULL;
- cb (d->cb_cls,
- NULL,
- d->cfg,
- d,
- (NULL == d->hostname)
- ? _("Failed to start `gnunet-service-arm' process.\n")
- : _("Failed to start `ssh' process.\n"));
+ if (NULL != cb)
+ cb (d->cb_cls,
+ NULL,
+ d->cfg,
+ d,
+ (NULL == d->hostname)
+ ? _("Failed to start `gnunet-service-arm' process.\n")
+ : _("Failed to start `ssh' process.\n"));
}
+#if DEBUG_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Started `%s', waiting for `%s' to be up.\n",
+ "gnunet-service-arm",
+ "gnunet-service-core");
+#endif
d->phase = SP_START_ARMING;
d->wait_runs = 0;
+ d->task
+ = GNUNET_SCHEDULER_add_delayed (d->sched,
+ GNUNET_NO,
+ GNUNET_SCHEDULER_PRIORITY_KEEP,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_CONSTANTS_EXEC_WAIT,
+ &start_fsm,
+ d);
break;
case SP_START_ARMING:
if (GNUNET_OK !=
@@ -350,13 +377,14 @@ start_fsm (void *cls,
{
cb = d->cb;
d->cb = NULL;
- cb (d->cb_cls,
- NULL,
- d->cfg,
- d,
- (NULL == d->hostname)
- ? _("`gnunet-service-arm' does not seem to terminate.\n")
- : _("`ssh' does not seem to terminate.\n"));
+ if (NULL != cb)
+ cb (d->cb_cls,
+ NULL,
+ d->cfg,
+ d,
+ (NULL == d->hostname)
+ ? _("`gnunet-service-arm' does not seem to terminate.\n")
+ : _("`ssh' does not seem to terminate.\n"));
return;
}
/* wait some more */
@@ -424,18 +452,24 @@ start_fsm (void *cls,
if ( (type != GNUNET_OS_PROCESS_EXITED) ||
(code != 0) )
{
- d->dead_cb (d->dead_cb_cls,
- _("`sshp' did not complete cleanly.\n"));
+ if (NULL != d->dead_cb)
+ d->dead_cb (d->dead_cb_cls,
+ _("`ssh' did not complete cleanly.\n"));
GNUNET_free (d->cfgfile);
GNUNET_free_non_null (d->hostname);
GNUNET_free_non_null (d->username);
GNUNET_free (d);
return;
}
+#if DEBUG_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer shutdown complete.\n");
+#endif
GNUNET_free (d->cfgfile);
GNUNET_free_non_null (d->hostname);
GNUNET_free_non_null (d->username);
- d->dead_cb (d->dead_cb_cls, NULL);
+ if (NULL != d->dead_cb)
+ d->dead_cb (d->dead_cb_cls, NULL);
GNUNET_free (d);
break;
case SP_CONFIG_UPDATE:
@@ -450,11 +484,12 @@ start_fsm (void *cls,
{
cb = d->cb;
d->cb = NULL;
- cb (d->cb_cls,
- NULL,
- d->cfg,
- d,
- _("`scp' does not seem to terminate.\n"));
+ if (NULL != cb)
+ cb (d->cb_cls,
+ NULL,
+ d->cfg,
+ d,
+ _("`scp' does not seem to terminate.\n"));
return;
}
/* wait some more */
@@ -471,15 +506,17 @@ start_fsm (void *cls,
if ( (type != GNUNET_OS_PROCESS_EXITED) ||
(code != 0) )
{
- d->update_cb (d->update_cb_cls,
- _("`scp' did not complete cleanly.\n"));
+ if (NULL != d->update_cb)
+ d->update_cb (d->update_cb_cls,
+ _("`scp' did not complete cleanly.\n"));
return;
}
#if DEBUG_TESTING
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Successfully copied configuration file.\n");
#endif
- d->update_cb (d->update_cb_cls, NULL);
+ if (NULL != d->update_cb)
+ d->update_cb (d->update_cb_cls, NULL);
d->phase = SP_START_DONE;
break;
}
@@ -502,7 +539,7 @@ start_fsm (void *cls,
*/
struct GNUNET_TESTING_Daemon *
GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
- struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *hostname,
GNUNET_TESTING_NotifyDaemonRunning cb,
void *cb_cls)
@@ -513,9 +550,13 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
ret = GNUNET_malloc (sizeof(struct GNUNET_TESTING_Daemon));
ret->sched = sched;
- ret->cfg = cfg;
ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
ret->cfgfile = GNUNET_DISK_mktemp ("gnunet-testing-config");
+#if DEBUG_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Setting up peer with configuration file `%s'.\n",
+ ret->cfgfile);
+#endif
if (NULL == ret->cfgfile)
{
GNUNET_free_non_null (ret->hostname);
@@ -524,15 +565,21 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
}
ret->cb = cb;
ret->cb_cls = cb_cls;
+ ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ GNUNET_CONFIGURATION_set_value_string (ret->cfg,
+ "PATHS",
+ "DEFAULTCONFIG",
+ ret->cfgfile);
/* 1) write configuration to temporary file */
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_write (cfg,
+ GNUNET_CONFIGURATION_write (ret->cfg,
ret->cfgfile))
{
if (0 != UNLINK (ret->cfgfile))
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
"unlink",
ret->cfgfile);
+ GNUNET_CONFIGURATION_destroy (ret->cfg);
GNUNET_free_non_null (ret->hostname);
GNUNET_free (ret->cfgfile);
GNUNET_free (ret);
@@ -581,6 +628,7 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
"unlink",
ret->cfgfile);
+ GNUNET_CONFIGURATION_destroy (ret->cfg);
GNUNET_free_non_null (ret->hostname);
GNUNET_free_non_null (ret->username);
GNUNET_free (ret->cfgfile);
@@ -589,7 +637,7 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
}
ret->task
= GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_NO,
+ GNUNET_YES,
GNUNET_SCHEDULER_PRIORITY_KEEP,
GNUNET_SCHEDULER_NO_TASK,
GNUNET_CONSTANTS_EXEC_WAIT,
@@ -597,6 +645,10 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
ret);
return ret;
}
+#if DEBUG_TESTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No need to copy configuration file since we are running locally.\n");
+#endif
ret->phase = SP_COPIED;
GNUNET_SCHEDULER_add_continuation (sched,
GNUNET_NO,
@@ -687,7 +739,7 @@ void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
d->dead_cb_cls = cb_cls;
d->task
= GNUNET_SCHEDULER_add_delayed (d->sched,
- GNUNET_NO,
+ GNUNET_YES,
GNUNET_SCHEDULER_PRIORITY_KEEP,
GNUNET_SCHEDULER_NO_TASK,
GNUNET_CONSTANTS_EXEC_WAIT,
@@ -695,11 +747,13 @@ void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
d);
return;
}
+ GNUNET_CONFIGURATION_destroy (d->cfg);
GNUNET_free (d->cfgfile);
GNUNET_free_non_null (d->hostname);
GNUNET_free_non_null (d->username);
GNUNET_free (d);
- cb (cb_cls, NULL);
+ if (NULL != cb)
+ cb (cb_cls, NULL);
}
@@ -720,8 +774,9 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
if (d->phase != SP_START_DONE)
{
- cb (cb_cls,
- _("Peer not yet running, can not change configuration at this point."));
+ if (NULL != cb)
+ cb (cb_cls,
+ _("Peer not yet running, can not change configuration at this point."));
return;
}
@@ -730,7 +785,8 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
GNUNET_CONFIGURATION_write (cfg,
d->cfgfile))
{
- cb (cb_cls,
+ if (NULL != cb)
+ cb (cb_cls,
_("Failed to write new configuration to disk."));
return;
}
@@ -739,7 +795,8 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
if (NULL == d->hostname)
{
/* signal success */
- cb (cb_cls, NULL);
+ if (NULL != cb)
+ cb (cb_cls, NULL);
return;
}
d->phase = SP_CONFIG_UPDATE;
@@ -765,8 +822,9 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Could not start `%s' process to copy configuration file.\n"),
"scp");
- cb (cb_cls,
- _("Failed to copy new configuration to remote machine."));
+ if (NULL != cb)
+ cb (cb_cls,
+ _("Failed to copy new configuration to remote machine."));
d->phase = SP_START_DONE;
return;
}
@@ -802,10 +860,14 @@ static size_t
transmit_ready (void *cls, size_t size, void *buf)
{
struct ConnectContext *ctx = cls;
- if (buf == NULL)
- ctx->cb (ctx->cb_cls, _("Peers failed to connect"));
- else
- ctx->cb (ctx->cb_cls, NULL);
+
+ if (NULL != ctx->cb)
+ {
+ if (buf == NULL)
+ ctx->cb (ctx->cb_cls, _("Peers failed to connect"));
+ else
+ ctx->cb (ctx->cb_cls, NULL);
+ }
GNUNET_free (ctx);
return 0;
}
@@ -831,8 +893,9 @@ process_hello (void *cls,
if (peer == NULL)
{
/* signal error */
- ctx->cb (ctx->cb_cls,
- _("Failed to receive `HELLO' from peer\n"));
+ if (NULL != ctx->cb)
+ ctx->cb (ctx->cb_cls,
+ _("Failed to receive `HELLO' from peer\n"));
GNUNET_TRANSPORT_disconnect (ctx->d1th);
GNUNET_TRANSPORT_disconnect (ctx->d2th);
GNUNET_free (ctx);
@@ -873,7 +936,8 @@ void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
if ( (d1->server == NULL) ||
(d2->server == NULL) )
{
- cb (cb_cls, _("Peers are not fully running yet, can not connect!\n"));
+ if (NULL != cb)
+ cb (cb_cls, _("Peers are not fully running yet, can not connect!\n"));
return;
}
ctx = GNUNET_malloc (sizeof(struct ConnectContext));
@@ -886,7 +950,8 @@ void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
if (ctx->d1th == NULL)
{
GNUNET_free (ctx);
- cb (cb_cls, _("Failed to connect to transport service!\n"));
+ if (NULL != cb)
+ cb (cb_cls, _("Failed to connect to transport service!\n"));
return;
}
ctx->d2th = GNUNET_TRANSPORT_connect (d2->sched, d2->cfg, d2, NULL, NULL, NULL);
@@ -894,7 +959,8 @@ void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
{
GNUNET_TRANSPORT_disconnect (ctx->d1th);
GNUNET_free (ctx);
- cb (cb_cls, _("Failed to connect to transport service!\n"));
+ if (NULL != cb)
+ cb (cb_cls, _("Failed to connect to transport service!\n"));
return;
}
GNUNET_TRANSPORT_get_hello (ctx->d1th,
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c
index 917a524de..b87507364 100644
--- a/src/testing/testing_group.c
+++ b/src/testing/testing_group.c
@@ -27,6 +27,58 @@
#include "gnunet_arm_service.h"
#include "gnunet_testing_lib.h"
+/**
+ * Lowest port used for GNUnet testing. Should be high enough to not
+ * conflict with other applications running on the hosts but be low
+ * enough to not conflict with client-ports (typically starting around
+ * 32k).
+ */
+#define LOW_PORT 10000
+
+/**
+ * Highest port used for GNUnet testing. Should be low enough to not
+ * conflict with the port range for "local" ports (client apps; see
+ * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
+ */
+#define HIGH_PORT 32000
+
+/**
+ * Data we keep per peer.
+ */
+struct PeerData
+{
+ /**
+ * (Initial) configuration of the host.
+ * (initial because clients could change
+ * it and we would not know about those
+ * updates).
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Handle for controlling the daemon.
+ */
+ struct GNUNET_TESTING_Daemon *daemon;
+};
+
+
+/**
+ * Data we keep per host.
+ */
+struct HostData
+{
+ /**
+ * Name of the host.
+ */
+ char *hostname;
+
+ /**
+ * Lowest port that we have not yet used
+ * for GNUnet.
+ */
+ uint16_t minport;
+};
+
/**
* Handle to a group of GNUnet peers.
@@ -41,7 +93,7 @@ struct GNUNET_TESTING_PeerGroup
/**
* Configuration template.
*/
- struct GNUNET_CONFIGURATION_Handle *cfg;
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
* Function to call on each started daemon.
@@ -54,14 +106,15 @@ struct GNUNET_TESTING_PeerGroup
void *cb_cls;
/**
- * NULL-terminated array of hostnames.
+ * NULL-terminated array of information about
+ * hosts.
*/
- char **hostnames;
+ struct HostData *hosts;
/**
* Array of "total" peers.
*/
- struct GNUNET_TESTING_Daemon **peers;
+ struct PeerData *peers;
/**
* Number of peers in this group.
@@ -71,79 +124,212 @@ struct GNUNET_TESTING_PeerGroup
};
+struct UpdateContext
+{
+ struct GNUNET_CONFIGURATION_Handle *ret;
+ unsigned int nport;
+};
+
/**
- * Start count gnunetd processes with the same set of transports and
- * applications. The port numbers (any option called "PORT") will be
- * adjusted to ensure that no two peers running on the same system
- * have the same port(s) in their respective configurations.
+ * Function to iterate over options. Copies
+ * the options to the target configuration,
+ * updating PORT values as needed.
*
- * @param sched scheduler to use
- * @param cfg configuration template to use
- * @param total number of daemons to start
- * @param cb function to call on each daemon that was started
- * @param cb_cls closure for cb
- * @param hostname where to run the peers; can be NULL (to run
- * everything on localhost).
- * @param va Additional hosts can be specified using a NULL-terminated list of
- * varargs, hosts will then be used round-robin from that
- * list; va only contains anything if hostname != NULL.
- * @return NULL on error, otherwise handle to control peer group
+ * @param cls closure
+ * @param section name of the section
+ * @param option name of the option
+ * @param value value of the option
*/
-struct GNUNET_TESTING_PeerGroup *
-GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- unsigned int total,
- GNUNET_TESTING_NotifyDaemonRunning cb,
- void *cb_cls,
- const char *hostname,
- va_list va)
+static void
+update_config(void *cls,
+ const char *section,
+ const char *option,
+ const char *value)
{
- struct GNUNET_TESTING_PeerGroup *pg;
-
- pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup));
- return pg;
+ struct UpdateContext *ctx = cls;
+ unsigned int ival;
+ char cval[12];
+
+ if ( (0 == strcmp (option, "PORT")) &&
+ (1 == sscanf (value, "%u", &ival)) )
+ {
+ GNUNET_snprintf (cval,
+ sizeof(cval),
+ "%u",
+ ctx->nport++);
+ value = cval;
+ }
+ GNUNET_CONFIGURATION_set_value_string (ctx->ret,
+ section,
+ option,
+ value);
}
/**
- * Start count gnunetd processes with the same set of
- * transports and applications. The port numbers will
- * be computed by adding delta each time (zero
- * times for the first peer).
+ * Create a new configuration using the given configuration
+ * as a template; however, each PORT in the existing cfg
+ * must be renumbered by incrementing "*port". If we run
+ * out of "*port" numbers, return NULL.
+ *
+ * @param cfg template configuration
+ * @param port port numbers to use, update to reflect
+ * port numbers that were used
+ * @return new configuration, NULL on error
+ */
+static struct GNUNET_CONFIGURATION_Handle*
+make_config (const struct GNUNET_CONFIGURATION_Handle*cfg,
+ uint16_t *port)
+{
+ struct UpdateContext uc;
+ uint16_t orig;
+
+ orig = *port;
+ uc.nport = *port;
+ uc.ret = GNUNET_CONFIGURATION_create ();
+ GNUNET_CONFIGURATION_iterate (cfg,
+ &update_config,
+ &uc);
+ if (uc.nport >= HIGH_PORT)
+ {
+ *port = orig;
+ GNUNET_CONFIGURATION_destroy (uc.ret);
+ return NULL;
+ }
+ *port = (uint16_t) uc.nport;
+ return uc.ret;
+}
+
+
+/**
+ * Start count gnunetd processes with the same set of transports and
+ * applications. The port numbers (any option called "PORT") will be
+ * adjusted to ensure that no two peers running on the same system
+ * have the same port(s) in their respective configurations.
*
* @param sched scheduler to use
* @param cfg configuration template to use
* @param total number of daemons to start
- * @param timeout how long is this allowed to take?
* @param cb function to call on each daemon that was started
* @param cb_cls closure for cb
- * @param hostname where to run the peers; can be NULL (to run
- * everything on localhost). Additional
- * hosts can be specified using a NULL-terminated list of
- * varargs, hosts will then be used round-robin from that
- * list.
+ * @param hostnames space-separated list of hostnames to use; can be NULL (to run
+ * everything on localhost).
* @return NULL on error, otherwise handle to control peer group
*/
struct GNUNET_TESTING_PeerGroup *
GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
- struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
unsigned int total,
GNUNET_TESTING_NotifyDaemonRunning cb,
void *cb_cls,
- const char *hostname,
- ...)
+ const char *hostnames)
{
- struct GNUNET_TESTING_PeerGroup * ret;
- va_list va;
-
- va_start (va, hostname);
- ret = GNUNET_TESTING_daemons_start_va (sched, cfg,
- total, cb, cb_cls, hostname,
- va);
- va_end (va);
- return ret;
-}
+ struct GNUNET_TESTING_PeerGroup *pg;
+ const char *rpos;
+ char *pos;
+ char *start;
+ const char *hostname;
+ struct GNUNET_CONFIGURATION_Handle *pcfg;
+ unsigned int off;
+ unsigned int hostcnt;
+ uint16_t minport;
+ if (0 == total)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup));
+ pg->sched = sched;
+ pg->cfg = cfg;
+ pg->cb = cb;
+ pg->cb_cls = cb_cls;
+ pg->total = total;
+ pg->peers = GNUNET_malloc (total * sizeof(struct PeerData));
+ if (NULL != hostnames)
+ {
+ off = 2;
+ /* skip leading spaces */
+ while ( (0 != *hostnames) &&
+ (isspace(*hostnames)))
+ hostnames++;
+ rpos = hostnames;
+ while ('\0' != *rpos)
+ {
+ if (isspace (*rpos))
+ off++;
+ rpos++;
+ }
+ pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
+ off = 0;
+ start = GNUNET_strdup (hostnames);
+ pos = start;
+ while ('\0' != *pos)
+ {
+ if (isspace (*pos))
+ {
+ *pos = '\0';
+ if (strlen(start) > 0)
+ {
+ pg->hosts[off].minport = LOW_PORT;
+ pg->hosts[off++].hostname = start;
+ }
+ start = pos+1;
+ }
+ pos++;
+ }
+ if (strlen(start) > 0)
+ {
+ pg->hosts[off].minport = LOW_PORT;
+ pg->hosts[off++].hostname = start;
+ }
+ if (off == 0)
+ {
+ GNUNET_free (start);
+ GNUNET_free (pg->hosts);
+ pg->hosts = NULL;
+ }
+ hostcnt = off;
+ minport = 0; /* make gcc happy */
+ }
+ else
+ {
+ hostcnt = 0;
+ minport = LOW_PORT;
+ }
+ for (off = 0; off < total; off++)
+ {
+ if (hostcnt > 0)
+ {
+ hostname = pg->hosts[off % hostcnt].hostname;
+ pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport);
+ }
+ else
+ {
+ hostname = NULL;
+ pcfg = make_config (cfg, &minport);
+ }
+ if (NULL == pcfg)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not create configuration for peer number %u on `%s'!\n"),
+ off,
+ hostname == NULL ? "localhost" : hostname);
+ continue;
+ }
+ pg->peers[off].cfg = pcfg;
+ pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
+ pcfg,
+ hostname,
+ cb,
+ cb_cls);
+ if (NULL == pg->peers[off].daemon)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Could not start peer number %u!\n"),
+ off);
+ }
+ return pg;
+}
/**
@@ -154,7 +340,26 @@ GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
void
GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
{
-
+ unsigned int off;
+
+ for (off = 0; off < pg->total; off++)
+ {
+ /* FIXME: should we wait for our
+ continuations to be called here? This
+ would require us to take a continuation
+ as well... */
+ if (NULL != pg->peers[off].daemon)
+ GNUNET_TESTING_daemon_stop (pg->peers[off].daemon,
+ NULL, NULL);
+ if (NULL != pg->peers[off].cfg)
+ GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
+ }
+ GNUNET_free (pg->peers);
+ if (NULL != pg->hosts)
+ {
+ GNUNET_free (pg->hosts[0].hostname);
+ GNUNET_free (pg->hosts);
+ }
GNUNET_free (pg);
}