aboutsummaryrefslogtreecommitdiff
path: root/src/testbed
diff options
context:
space:
mode:
Diffstat (limited to 'src/testbed')
-rw-r--r--src/testbed/Makefile.am268
-rw-r--r--src/testbed/Makefile.in989
-rw-r--r--src/testbed/gnunet-helper-testbed.c489
-rw-r--r--src/testbed/gnunet-service-testbed.c2227
-rw-r--r--src/testbed/gnunet-service-testbed.h911
-rw-r--r--src/testbed/gnunet-service-testbed_cache.c1048
-rw-r--r--src/testbed/gnunet-service-testbed_oc.c1595
-rw-r--r--src/testbed/gnunet-testbed-profiler.c283
-rw-r--r--src/testbed/gnunet_mpi_test.c107
-rw-r--r--src/testbed/ll_master.c92
-rw-r--r--src/testbed/ll_monitor.c76
-rw-r--r--src/testbed/overlay_topology.txt5
-rwxr-xr-xsrc/testbed/sample.job16
-rw-r--r--src/testbed/sample_hosts.txt15
-rw-r--r--src/testbed/test_gnunet_helper_testbed.c249
-rw-r--r--src/testbed/test_testbed_api.c464
-rw-r--r--src/testbed/test_testbed_api.conf91
-rw-r--r--src/testbed/test_testbed_api_2peers_1controller.c532
-rw-r--r--src/testbed/test_testbed_api_3peers_3controllers.c946
-rw-r--r--src/testbed/test_testbed_api_controllerlink.c749
-rw-r--r--src/testbed/test_testbed_api_hosts.c130
-rw-r--r--src/testbed/test_testbed_api_operations.c430
-rw-r--r--src/testbed/test_testbed_api_test.c241
-rw-r--r--src/testbed/test_testbed_api_testbed_run.c223
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf79
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyclique.conf79
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf80
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyline.conf79
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyrandom.conf79
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyring.conf79
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf79
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf83
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf83
-rw-r--r--src/testbed/test_testbed_api_topology.c172
-rw-r--r--src/testbed/test_testbed_api_topology_clique.c168
-rw-r--r--src/testbed/testbed.conf0
-rw-r--r--src/testbed/testbed.conf.in18
-rw-r--r--src/testbed/testbed.h272
-rw-r--r--src/testbed/testbed_api.c2702
-rw-r--r--src/testbed/testbed_api.h590
-rw-r--r--src/testbed/testbed_api_hosts.c566
-rw-r--r--src/testbed/testbed_api_hosts.h130
-rw-r--r--src/testbed/testbed_api_operations.c386
-rw-r--r--src/testbed/testbed_api_operations.h88
-rw-r--r--src/testbed/testbed_api_peers.c640
-rw-r--r--src/testbed/testbed_api_peers.h245
-rw-r--r--src/testbed/testbed_api_services.c245
-rw-r--r--src/testbed/testbed_api_statistics.c56
-rw-r--r--src/testbed/testbed_api_test.c111
-rw-r--r--src/testbed/testbed_api_testbed.c1207
-rw-r--r--src/testbed/testbed_api_topology.c1000
-rw-r--r--src/testbed/testbed_api_topology.h70
-rw-r--r--src/testbed/testbed_helper.h89
53 files changed, 21021 insertions, 630 deletions
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am
index b7b9360..5977740 100644
--- a/src/testbed/Makefile.am
+++ b/src/testbed/Makefile.am
@@ -9,31 +9,289 @@ if USE_COVERAGE
XLIB = -lgcov
endif
+if WITH_LL
+ CC = mpcc
+ ll_noinst_binaries = \
+ ll-master \
+ ll-monitor
+ ll_binaries = \
+ gnunet-mpi-test
+endif
+
+libexecdir= $(pkglibdir)/libexec/
+
pkgcfgdir= $(pkgdatadir)/config.d/
-dist_pkgcfg_DATA = \
+pkgcfg_DATA = \
testbed.conf
+libexec_PROGRAMS = \
+ gnunet-service-testbed \
+ gnunet-helper-testbed
+
+bin_PROGRAMS = \
+ $(ll_binaries)
+
+noinst_PROGRAMS = \
+ gnunet-testbed-profiler \
+ $(ll_noinst_binaries)
+
+gnunet_service_testbed_SOURCES = \
+ gnunet-service-testbed.c \
+ gnunet-service-testbed.h \
+ gnunet-service-testbed_cache.c \
+ gnunet-service-testbed_oc.c
+gnunet_service_testbed_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ $(LTLIBINTL) -lz
+gnunet_service_testbed_DEPENDENCIES = \
+ libgnunettestbed.la
+
+gnunet_testbed_profiler_SOURCES = \
+ gnunet-testbed-profiler.c
+gnunet_testbed_profiler_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+gnunet_helper_testbed_SOURCES = \
+ gnunet-helper-testbed.c
+gnunet_helper_testbed_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la \
+ $(LTLIBINTL) -lz
+gnunet_helper_testbed_DEPENDENCIES = \
+ gnunet-service-testbed.$(OBJEXT) \
+ libgnunettestbed.la
+
+ll_master_SOURCES = \
+ ll_master.c
+ll_master_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(LTLIBINTL) -lz -lllapi
+
+ll_monitor_SOURCES = \
+ ll_monitor.c
+ll_monitor_LDADD = $(XLIB) \
+ $(LTLIBINTL) -lz -lllapi
+
+gnunet_mpi_test_SOURCES = gnunet_mpi_test.c
+gnunet_mpi_test_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
lib_LTLIBRARIES = \
libgnunettestbed.la
libgnunettestbed_la_SOURCES = \
- testbed_api.c testbed.h \
- testbed_api_hosts.c testbed_api_hosts.h \
+ testbed_api.c testbed_api.h testbed.h \
+ testbed_api_hosts.c testbed_api_hosts.h testbed_helper.h \
testbed_api_operations.c testbed_api_operations.h \
testbed_api_peers.c testbed_api_peers.h \
testbed_api_services.c \
+ testbed_api_statistics.c \
testbed_api_testbed.c \
testbed_api_test.c \
- testbed_api_topology.c
+ testbed_api_topology.c testbed_api_topology.h
libgnunettestbed_la_LIBADD = $(XLIB) \
$(top_builddir)/src/core/libgnunetcore.la \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/transport/libgnunettransport.la \
$(top_builddir)/src/hello/libgnunethello.la \
-lm \
- $(top_builddir)/src/util/libgnunetutil.la
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(LTLIBINTL)
libgnunettestbed_la_LDFLAGS = \
$(GN_LIB_LDFLAGS) \
-version-info 0:0:0
+check_PROGRAMS = \
+ test_testbed_api_hosts \
+ test_testbed_api_controllerlink \
+ test_testbed_api_2peers_1controller \
+ test_testbed_api_3peers_3controllers \
+ test_testbed_api \
+ test_testbed_api_operations \
+ test_testbed_api_testbed_run \
+ test_testbed_api_test \
+ test_gnunet_helper_testbed \
+ test_testbed_api_topology \
+ test_testbed_api_topology_clique \
+ test_testbed_api_testbed_run_topologyrandom \
+ test_testbed_api_testbed_run_topologyline \
+ test_testbed_api_testbed_run_topologyclique \
+ test_testbed_api_testbed_run_topologyring \
+ test_testbed_api_testbed_run_topologysmallworldring \
+ test_testbed_api_testbed_run_topology2dtorus \
+ test_testbed_api_testbed_run_topologysmallworld \
+ test_testbed_api_testbed_run_topologyfromfile \
+ test_testbed_api_testbed_run_topologyscalefree
+
+if ENABLE_TEST_RUN
+ TESTS = \
+ test_testbed_api \
+ test_testbed_api_hosts \
+ test_testbed_api_2peers_1controller \
+ test_testbed_api_3peers_3controllers \
+ test_testbed_api_operations \
+ test_gnunet_helper_testbed \
+ test_testbed_api_controllerlink \
+ test_testbed_api_testbed_run \
+ test_testbed_api_test \
+ test_testbed_api_topology \
+ test_testbed_api_topology_clique \
+ test_testbed_api_testbed_run_topologyrandom \
+ test_testbed_api_testbed_run_topologyline \
+ test_testbed_api_testbed_run_topologyclique \
+ test_testbed_api_testbed_run_topologyring \
+ test_testbed_api_testbed_run_topologysmallworldring \
+ test_testbed_api_testbed_run_topology2dtorus \
+ test_testbed_api_testbed_run_topologysmallworld \
+ test_testbed_api_testbed_run_topologyfromfile \
+ test_testbed_api_testbed_run_topologyscalefree
+endif
+
+test_testbed_api_hosts_SOURCES = \
+ test_testbed_api_hosts.c
+test_testbed_api_hosts_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_SOURCES = \
+ test_testbed_api.c
+test_testbed_api_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/dht/libgnunetdht.la \
+ libgnunettestbed.la
+
+test_testbed_api_2peers_1controller_SOURCES = \
+ test_testbed_api_2peers_1controller.c
+test_testbed_api_2peers_1controller_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la
+
+test_testbed_api_3peers_3controllers_SOURCES = \
+ test_testbed_api_3peers_3controllers.c
+test_testbed_api_3peers_3controllers_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la
+
+test_testbed_api_operations_SOURCES = \
+ test_testbed_api_operations.c
+test_testbed_api_operations_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_controllerlink_SOURCES = \
+ test_testbed_api_controllerlink.c
+test_testbed_api_controllerlink_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_test_SOURCES = \
+ test_testbed_api_test.c
+test_testbed_api_test_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_topology_SOURCES = \
+ test_testbed_api_topology.c
+test_testbed_api_topology_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_topology_clique_SOURCES = \
+ test_testbed_api_topology_clique.c
+test_testbed_api_topology_clique_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_gnunet_helper_testbed_SOURCES = \
+ test_gnunet_helper_testbed.c
+test_gnunet_helper_testbed_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la \
+ -lz
+
+test_testbed_api_testbed_run_topologyrandom_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologyrandom_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyline_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologyline_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyclique_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologyclique_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyring_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologyring_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologysmallworldring_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologysmallworldring_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topology2dtorus_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topology2dtorus_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologysmallworld_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologysmallworld_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyfromfile_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologyfromfile_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyscalefree_SOURCES = \
+ test_testbed_api_testbed_run.c
+test_testbed_api_testbed_run_topologyscalefree_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+EXTRA_DIST = \
+ test_testbed_api.conf \
+ test_testbed_api_testbed_run_topologyring.conf \
+ test_testbed_api_testbed_run_topologyclique.conf \
+ test_testbed_api_testbed_run_topologyline.conf \
+ test_testbed_api_testbed_run_topologyrandom.conf \
+ test_testbed_api_testbed_run_topologysmallworldring.conf \
+ test_testbed_api_testbed_run_topology2dtorus.conf \
+ test_testbed_api_testbed_run_topologysmallworld.conf \
+ test_testbed_api_testbed_run_topologyfromfile.conf \
+ test_testbed_api_testbed_run_topologyscalefree.conf \
+ overlay_topology.txt \
+ sample_hosts.txt \
+ sample.job
diff --git a/src/testbed/Makefile.in b/src/testbed/Makefile.in
index 3b08315..1b3c3e2 100644
--- a/src/testbed/Makefile.in
+++ b/src/testbed/Makefile.in
@@ -1,9 +1,9 @@
-# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
-# Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -16,7 +16,25 @@
@SET_MAKE@
+
VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -36,27 +54,71 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
+libexec_PROGRAMS = gnunet-service-testbed$(EXEEXT) \
+ gnunet-helper-testbed$(EXEEXT)
+bin_PROGRAMS = $(am__EXEEXT_1)
+noinst_PROGRAMS = gnunet-testbed-profiler$(EXEEXT) $(am__EXEEXT_2)
+check_PROGRAMS = test_testbed_api_hosts$(EXEEXT) \
+ test_testbed_api_controllerlink$(EXEEXT) \
+ test_testbed_api_2peers_1controller$(EXEEXT) \
+ test_testbed_api_3peers_3controllers$(EXEEXT) \
+ test_testbed_api$(EXEEXT) test_testbed_api_operations$(EXEEXT) \
+ test_testbed_api_testbed_run$(EXEEXT) \
+ test_testbed_api_test$(EXEEXT) \
+ test_gnunet_helper_testbed$(EXEEXT) \
+ test_testbed_api_topology$(EXEEXT) \
+ test_testbed_api_topology_clique$(EXEEXT) \
+ test_testbed_api_testbed_run_topologyrandom$(EXEEXT) \
+ test_testbed_api_testbed_run_topologyline$(EXEEXT) \
+ test_testbed_api_testbed_run_topologyclique$(EXEEXT) \
+ test_testbed_api_testbed_run_topologyring$(EXEEXT) \
+ test_testbed_api_testbed_run_topologysmallworldring$(EXEEXT) \
+ test_testbed_api_testbed_run_topology2dtorus$(EXEEXT) \
+ test_testbed_api_testbed_run_topologysmallworld$(EXEEXT) \
+ test_testbed_api_testbed_run_topologyfromfile$(EXEEXT) \
+ test_testbed_api_testbed_run_topologyscalefree$(EXEEXT)
+@ENABLE_TEST_RUN_TRUE@TESTS = test_testbed_api$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_hosts$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_2peers_1controller$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_3peers_3controllers$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_operations$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_gnunet_helper_testbed$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_controllerlink$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_test$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_topology$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_topology_clique$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologyrandom$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologyline$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologyclique$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologyring$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologysmallworldring$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topology2dtorus$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologysmallworld$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologyfromfile$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_testbed_api_testbed_run_topologyscalefree$(EXEEXT)
subdir = src/testbed
-DIST_COMMON = $(dist_pkgcfg_DATA) $(srcdir)/Makefile.am \
- $(srcdir)/Makefile.in
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/testbed.conf.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \
$(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \
- $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \
- $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
- $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \
- $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \
- $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \
- $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
- $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glib-2.0.m4 \
+ $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
+ $(top_srcdir)/m4/libcurl.m4 $(top_srcdir)/m4/libgcrypt.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libunistring.m4 \
+ $(top_srcdir)/m4/ltdl.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/m4/po.m4 \
$(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/gnunet_config.h
-CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_FILES = testbed.conf
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
@@ -79,7 +141,14 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgcfgdir)"
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(pkgcfgdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
am__DEPENDENCIES_1 =
libgnunettestbed_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
@@ -87,19 +156,168 @@ libgnunettestbed_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(top_builddir)/src/statistics/libgnunetstatistics.la \
$(top_builddir)/src/transport/libgnunettransport.la \
$(top_builddir)/src/hello/libgnunethello.la \
- $(top_builddir)/src/util/libgnunetutil.la
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(am__DEPENDENCIES_1)
am_libgnunettestbed_la_OBJECTS = testbed_api.lo testbed_api_hosts.lo \
testbed_api_operations.lo testbed_api_peers.lo \
- testbed_api_services.lo testbed_api_testbed.lo \
- testbed_api_test.lo testbed_api_topology.lo
+ testbed_api_services.lo testbed_api_statistics.lo \
+ testbed_api_testbed.lo testbed_api_test.lo \
+ testbed_api_topology.lo
libgnunettestbed_la_OBJECTS = $(am_libgnunettestbed_la_OBJECTS)
-AM_V_lt = $(am__v_lt_$(V))
-am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
libgnunettestbed_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(AM_CFLAGS) $(CFLAGS) $(libgnunettestbed_la_LDFLAGS) \
$(LDFLAGS) -o $@
+@WITH_LL_TRUE@am__EXEEXT_1 = gnunet-mpi-test$(EXEEXT)
+@WITH_LL_TRUE@am__EXEEXT_2 = ll-master$(EXEEXT) ll-monitor$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(noinst_PROGRAMS)
+am_gnunet_helper_testbed_OBJECTS = gnunet-helper-testbed.$(OBJEXT)
+gnunet_helper_testbed_OBJECTS = $(am_gnunet_helper_testbed_OBJECTS)
+am_gnunet_mpi_test_OBJECTS = gnunet_mpi_test.$(OBJEXT)
+gnunet_mpi_test_OBJECTS = $(am_gnunet_mpi_test_OBJECTS)
+gnunet_mpi_test_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_gnunet_service_testbed_OBJECTS = gnunet-service-testbed.$(OBJEXT) \
+ gnunet-service-testbed_cache.$(OBJEXT) \
+ gnunet-service-testbed_oc.$(OBJEXT)
+gnunet_service_testbed_OBJECTS = $(am_gnunet_service_testbed_OBJECTS)
+am_gnunet_testbed_profiler_OBJECTS = \
+ gnunet-testbed-profiler.$(OBJEXT)
+gnunet_testbed_profiler_OBJECTS = \
+ $(am_gnunet_testbed_profiler_OBJECTS)
+gnunet_testbed_profiler_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_ll_master_OBJECTS = ll_master.$(OBJEXT)
+ll_master_OBJECTS = $(am_ll_master_OBJECTS)
+ll_master_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(am__DEPENDENCIES_1)
+am_ll_monitor_OBJECTS = ll_monitor.$(OBJEXT)
+ll_monitor_OBJECTS = $(am_ll_monitor_OBJECTS)
+ll_monitor_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am_test_gnunet_helper_testbed_OBJECTS = \
+ test_gnunet_helper_testbed.$(OBJEXT)
+test_gnunet_helper_testbed_OBJECTS = \
+ $(am_test_gnunet_helper_testbed_OBJECTS)
+test_gnunet_helper_testbed_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_OBJECTS = test_testbed_api.$(OBJEXT)
+test_testbed_api_OBJECTS = $(am_test_testbed_api_OBJECTS)
+test_testbed_api_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/dht/libgnunetdht.la libgnunettestbed.la
+am_test_testbed_api_2peers_1controller_OBJECTS = \
+ test_testbed_api_2peers_1controller.$(OBJEXT)
+test_testbed_api_2peers_1controller_OBJECTS = \
+ $(am_test_testbed_api_2peers_1controller_OBJECTS)
+test_testbed_api_2peers_1controller_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la
+am_test_testbed_api_3peers_3controllers_OBJECTS = \
+ test_testbed_api_3peers_3controllers.$(OBJEXT)
+test_testbed_api_3peers_3controllers_OBJECTS = \
+ $(am_test_testbed_api_3peers_3controllers_OBJECTS)
+test_testbed_api_3peers_3controllers_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la
+am_test_testbed_api_controllerlink_OBJECTS = \
+ test_testbed_api_controllerlink.$(OBJEXT)
+test_testbed_api_controllerlink_OBJECTS = \
+ $(am_test_testbed_api_controllerlink_OBJECTS)
+test_testbed_api_controllerlink_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_hosts_OBJECTS = test_testbed_api_hosts.$(OBJEXT)
+test_testbed_api_hosts_OBJECTS = $(am_test_testbed_api_hosts_OBJECTS)
+test_testbed_api_hosts_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_operations_OBJECTS = \
+ test_testbed_api_operations.$(OBJEXT)
+test_testbed_api_operations_OBJECTS = \
+ $(am_test_testbed_api_operations_OBJECTS)
+test_testbed_api_operations_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_test_OBJECTS = test_testbed_api_test.$(OBJEXT)
+test_testbed_api_test_OBJECTS = $(am_test_testbed_api_test_OBJECTS)
+test_testbed_api_test_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_OBJECTS)
+test_testbed_api_testbed_run_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topology2dtorus_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topology2dtorus_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topology2dtorus_OBJECTS)
+test_testbed_api_testbed_run_topology2dtorus_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologyclique_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologyclique_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topologyclique_OBJECTS)
+test_testbed_api_testbed_run_topologyclique_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologyfromfile_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologyfromfile_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topologyfromfile_OBJECTS)
+test_testbed_api_testbed_run_topologyfromfile_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologyline_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologyline_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topologyline_OBJECTS)
+test_testbed_api_testbed_run_topologyline_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologyrandom_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologyrandom_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topologyrandom_OBJECTS)
+test_testbed_api_testbed_run_topologyrandom_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologyring_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologyring_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topologyring_OBJECTS)
+test_testbed_api_testbed_run_topologyring_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologyscalefree_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologyscalefree_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topologyscalefree_OBJECTS)
+test_testbed_api_testbed_run_topologyscalefree_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologysmallworld_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologysmallworld_OBJECTS = \
+ $(am_test_testbed_api_testbed_run_topologysmallworld_OBJECTS)
+test_testbed_api_testbed_run_topologysmallworld_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_testbed_run_topologysmallworldring_OBJECTS = \
+ test_testbed_api_testbed_run.$(OBJEXT)
+test_testbed_api_testbed_run_topologysmallworldring_OBJECTS = $(am_test_testbed_api_testbed_run_topologysmallworldring_OBJECTS)
+test_testbed_api_testbed_run_topologysmallworldring_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_topology_OBJECTS = \
+ test_testbed_api_topology.$(OBJEXT)
+test_testbed_api_topology_OBJECTS = \
+ $(am_test_testbed_api_topology_OBJECTS)
+test_testbed_api_topology_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
+am_test_testbed_api_topology_clique_OBJECTS = \
+ test_testbed_api_topology_clique.$(OBJEXT)
+test_testbed_api_topology_clique_OBJECTS = \
+ $(am_test_testbed_api_topology_clique_OBJECTS)
+test_testbed_api_topology_clique_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la libgnunettestbed.la
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -110,27 +328,80 @@ LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
-AM_V_CC = $(am__v_CC_$(V))
-am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
-AM_V_at = $(am__v_at_$(V))
-am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
-AM_V_CCLD = $(am__v_CCLD_$(V))
-am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
-AM_V_GEN = $(am__v_GEN_$(V))
-am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
-SOURCES = $(libgnunettestbed_la_SOURCES)
-DIST_SOURCES = $(libgnunettestbed_la_SOURCES)
-DATA = $(dist_pkgcfg_DATA)
+SOURCES = $(libgnunettestbed_la_SOURCES) \
+ $(gnunet_helper_testbed_SOURCES) $(gnunet_mpi_test_SOURCES) \
+ $(gnunet_service_testbed_SOURCES) \
+ $(gnunet_testbed_profiler_SOURCES) $(ll_master_SOURCES) \
+ $(ll_monitor_SOURCES) $(test_gnunet_helper_testbed_SOURCES) \
+ $(test_testbed_api_SOURCES) \
+ $(test_testbed_api_2peers_1controller_SOURCES) \
+ $(test_testbed_api_3peers_3controllers_SOURCES) \
+ $(test_testbed_api_controllerlink_SOURCES) \
+ $(test_testbed_api_hosts_SOURCES) \
+ $(test_testbed_api_operations_SOURCES) \
+ $(test_testbed_api_test_SOURCES) \
+ $(test_testbed_api_testbed_run_SOURCES) \
+ $(test_testbed_api_testbed_run_topology2dtorus_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyclique_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyfromfile_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyline_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyrandom_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyring_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyscalefree_SOURCES) \
+ $(test_testbed_api_testbed_run_topologysmallworld_SOURCES) \
+ $(test_testbed_api_testbed_run_topologysmallworldring_SOURCES) \
+ $(test_testbed_api_topology_SOURCES) \
+ $(test_testbed_api_topology_clique_SOURCES)
+DIST_SOURCES = $(libgnunettestbed_la_SOURCES) \
+ $(gnunet_helper_testbed_SOURCES) $(gnunet_mpi_test_SOURCES) \
+ $(gnunet_service_testbed_SOURCES) \
+ $(gnunet_testbed_profiler_SOURCES) $(ll_master_SOURCES) \
+ $(ll_monitor_SOURCES) $(test_gnunet_helper_testbed_SOURCES) \
+ $(test_testbed_api_SOURCES) \
+ $(test_testbed_api_2peers_1controller_SOURCES) \
+ $(test_testbed_api_3peers_3controllers_SOURCES) \
+ $(test_testbed_api_controllerlink_SOURCES) \
+ $(test_testbed_api_hosts_SOURCES) \
+ $(test_testbed_api_operations_SOURCES) \
+ $(test_testbed_api_test_SOURCES) \
+ $(test_testbed_api_testbed_run_SOURCES) \
+ $(test_testbed_api_testbed_run_topology2dtorus_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyclique_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyfromfile_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyline_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyrandom_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyring_SOURCES) \
+ $(test_testbed_api_testbed_run_topologyscalefree_SOURCES) \
+ $(test_testbed_api_testbed_run_topologysmallworld_SOURCES) \
+ $(test_testbed_api_testbed_run_topologysmallworldring_SOURCES) \
+ $(test_testbed_api_topology_SOURCES) \
+ $(test_testbed_api_topology_clique_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(pkgcfg_DATA)
ETAGS = etags
CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -143,6 +414,7 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
+@WITH_LL_TRUE@CC = mpcc
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
@@ -167,6 +439,10 @@ EXEEXT = @EXEEXT@
EXT_LIBS = @EXT_LIBS@
EXT_LIB_PATH = @EXT_LIB_PATH@
FGREP = @FGREP@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
GMSGFMT = @GMSGFMT@
GMSGFMT_015 = @GMSGFMT_015@
GNUNETDNS_GROUP = @GNUNETDNS_GROUP@
@@ -177,6 +453,7 @@ GN_LIBINTL = @GN_LIBINTL@
GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@
GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@
GN_USER_HOME_DIR = @GN_USER_HOME_DIR@
+GOBJECT_QUERY = @GOBJECT_QUERY@
GREP = @GREP@
HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@
INCLTDL = @INCLTDL@
@@ -199,6 +476,8 @@ LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBGTOP_CFLAGS = @LIBGTOP_CFLAGS@
+LIBGTOP_LIBS = @LIBGTOP_LIBS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBLTDL = @LIBLTDL@
@@ -220,6 +499,7 @@ LT_CONFIG_H = @LT_CONFIG_H@
LT_DLLOADERS = @LT_DLLOADERS@
LT_DLPREOPEN = @LT_DLPREOPEN@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MONKEYPREFIX = @MONKEYPREFIX@
MSGFMT = @MSGFMT@
@@ -229,6 +509,7 @@ MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
NM = @NM@
NMEDIT = @NMEDIT@
+NSS_DIR = @NSS_DIR@
OBJC = @OBJC@
OBJCDEPMODE = @OBJCDEPMODE@
OBJCFLAGS = @OBJCFLAGS@
@@ -244,6 +525,7 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@
POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@
POSUB = @POSUB@
@@ -275,6 +557,7 @@ abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
@@ -297,6 +580,7 @@ datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
+gitcommand = @gitcommand@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
@@ -307,10 +591,9 @@ includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
-libexecdir = @libexecdir@
+libexecdir = $(pkglibdir)/libexec/
localedir = @localedir@
localstatedir = @localstatedir@
-lt_ECHO = @lt_ECHO@
ltdl_LIBOBJS = @ltdl_LIBOBJS@
ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@
mandir = @mandir@
@@ -328,6 +611,7 @@ sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
+svnversioncommand = @svnversioncommand@
sys_symbol_underscore = @sys_symbol_underscore@
sysconfdir = @sysconfdir@
target = @target@
@@ -342,22 +626,85 @@ INCLUDES = -I$(top_srcdir)/src/include
@MINGW_TRUE@WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0
@USE_COVERAGE_TRUE@XLIB = -lgcov
+@WITH_LL_TRUE@ll_noinst_binaries = \
+@WITH_LL_TRUE@ ll-master \
+@WITH_LL_TRUE@ ll-monitor
+
+@WITH_LL_TRUE@ll_binaries = \
+@WITH_LL_TRUE@ gnunet-mpi-test
+
pkgcfgdir = $(pkgdatadir)/config.d/
-dist_pkgcfg_DATA = \
+pkgcfg_DATA = \
testbed.conf
+gnunet_service_testbed_SOURCES = \
+ gnunet-service-testbed.c \
+ gnunet-service-testbed.h \
+ gnunet-service-testbed_cache.c \
+ gnunet-service-testbed_oc.c
+
+gnunet_service_testbed_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ $(LTLIBINTL) -lz
+
+gnunet_service_testbed_DEPENDENCIES = \
+ libgnunettestbed.la
+
+gnunet_testbed_profiler_SOURCES = \
+ gnunet-testbed-profiler.c
+
+gnunet_testbed_profiler_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+gnunet_helper_testbed_SOURCES = \
+ gnunet-helper-testbed.c
+
+gnunet_helper_testbed_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la \
+ $(LTLIBINTL) -lz
+
+gnunet_helper_testbed_DEPENDENCIES = \
+ gnunet-service-testbed.$(OBJEXT) \
+ libgnunettestbed.la
+
+ll_master_SOURCES = \
+ ll_master.c
+
+ll_master_LDADD = $(XLIB) \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(LTLIBINTL) -lz -lllapi
+
+ll_monitor_SOURCES = \
+ ll_monitor.c
+
+ll_monitor_LDADD = $(XLIB) \
+ $(LTLIBINTL) -lz -lllapi
+
+gnunet_mpi_test_SOURCES = gnunet_mpi_test.c
+gnunet_mpi_test_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
lib_LTLIBRARIES = \
libgnunettestbed.la
libgnunettestbed_la_SOURCES = \
- testbed_api.c testbed.h \
- testbed_api_hosts.c testbed_api_hosts.h \
+ testbed_api.c testbed_api.h testbed.h \
+ testbed_api_hosts.c testbed_api_hosts.h testbed_helper.h \
testbed_api_operations.c testbed_api_operations.h \
testbed_api_peers.c testbed_api_peers.h \
testbed_api_services.c \
+ testbed_api_statistics.c \
testbed_api_testbed.c \
testbed_api_test.c \
- testbed_api_topology.c
+ testbed_api_topology.c testbed_api_topology.h
libgnunettestbed_la_LIBADD = $(XLIB) \
$(top_builddir)/src/core/libgnunetcore.la \
@@ -365,12 +712,174 @@ libgnunettestbed_la_LIBADD = $(XLIB) \
$(top_builddir)/src/transport/libgnunettransport.la \
$(top_builddir)/src/hello/libgnunethello.la \
-lm \
- $(top_builddir)/src/util/libgnunetutil.la
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(LTLIBINTL)
libgnunettestbed_la_LDFLAGS = \
$(GN_LIB_LDFLAGS) \
-version-info 0:0:0
+test_testbed_api_hosts_SOURCES = \
+ test_testbed_api_hosts.c
+
+test_testbed_api_hosts_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_SOURCES = \
+ test_testbed_api.c
+
+test_testbed_api_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/dht/libgnunetdht.la \
+ libgnunettestbed.la
+
+test_testbed_api_2peers_1controller_SOURCES = \
+ test_testbed_api_2peers_1controller.c
+
+test_testbed_api_2peers_1controller_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la
+
+test_testbed_api_3peers_3controllers_SOURCES = \
+ test_testbed_api_3peers_3controllers.c
+
+test_testbed_api_3peers_3controllers_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ libgnunettestbed.la
+
+test_testbed_api_operations_SOURCES = \
+ test_testbed_api_operations.c
+
+test_testbed_api_operations_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_controllerlink_SOURCES = \
+ test_testbed_api_controllerlink.c
+
+test_testbed_api_controllerlink_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_test_SOURCES = \
+ test_testbed_api_test.c
+
+test_testbed_api_test_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_topology_SOURCES = \
+ test_testbed_api_topology.c
+
+test_testbed_api_topology_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_topology_clique_SOURCES = \
+ test_testbed_api_topology_clique.c
+
+test_testbed_api_topology_clique_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_gnunet_helper_testbed_SOURCES = \
+ test_gnunet_helper_testbed.c
+
+test_gnunet_helper_testbed_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la \
+ -lz
+
+test_testbed_api_testbed_run_topologyrandom_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologyrandom_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyline_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologyline_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyclique_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologyclique_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyring_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologyring_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologysmallworldring_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologysmallworldring_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topology2dtorus_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topology2dtorus_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologysmallworld_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologysmallworld_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyfromfile_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologyfromfile_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+test_testbed_api_testbed_run_topologyscalefree_SOURCES = \
+ test_testbed_api_testbed_run.c
+
+test_testbed_api_testbed_run_topologyscalefree_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ libgnunettestbed.la
+
+EXTRA_DIST = \
+ test_testbed_api.conf \
+ test_testbed_api_testbed_run_topologyring.conf \
+ test_testbed_api_testbed_run_topologyclique.conf \
+ test_testbed_api_testbed_run_topologyline.conf \
+ test_testbed_api_testbed_run_topologyrandom.conf \
+ test_testbed_api_testbed_run_topologysmallworldring.conf \
+ test_testbed_api_testbed_run_topology2dtorus.conf \
+ test_testbed_api_testbed_run_topologysmallworld.conf \
+ test_testbed_api_testbed_run_topologyfromfile.conf \
+ test_testbed_api_testbed_run_topologyscalefree.conf \
+ overlay_topology.txt \
+ sample_hosts.txt \
+ sample.job
+
all: all-am
.SUFFIXES:
@@ -405,9 +914,10 @@ $(top_srcdir)/configure: $(am__configure_deps)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
+testbed.conf: $(top_builddir)/config.status $(srcdir)/testbed.conf.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
- test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
@@ -415,6 +925,8 @@ install-libLTLIBRARIES: $(lib_LTLIBRARIES)
else :; fi; \
done; \
test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
@@ -436,8 +948,196 @@ clean-libLTLIBRARIES:
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
-libgnunettestbed.la: $(libgnunettestbed_la_OBJECTS) $(libgnunettestbed_la_DEPENDENCIES)
+libgnunettestbed.la: $(libgnunettestbed_la_OBJECTS) $(libgnunettestbed_la_DEPENDENCIES) $(EXTRA_libgnunettestbed_la_DEPENDENCIES)
$(AM_V_CCLD)$(libgnunettestbed_la_LINK) -rpath $(libdir) $(libgnunettestbed_la_OBJECTS) $(libgnunettestbed_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+gnunet-helper-testbed$(EXEEXT): $(gnunet_helper_testbed_OBJECTS) $(gnunet_helper_testbed_DEPENDENCIES) $(EXTRA_gnunet_helper_testbed_DEPENDENCIES)
+ @rm -f gnunet-helper-testbed$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_helper_testbed_OBJECTS) $(gnunet_helper_testbed_LDADD) $(LIBS)
+gnunet-mpi-test$(EXEEXT): $(gnunet_mpi_test_OBJECTS) $(gnunet_mpi_test_DEPENDENCIES) $(EXTRA_gnunet_mpi_test_DEPENDENCIES)
+ @rm -f gnunet-mpi-test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_mpi_test_OBJECTS) $(gnunet_mpi_test_LDADD) $(LIBS)
+gnunet-service-testbed$(EXEEXT): $(gnunet_service_testbed_OBJECTS) $(gnunet_service_testbed_DEPENDENCIES) $(EXTRA_gnunet_service_testbed_DEPENDENCIES)
+ @rm -f gnunet-service-testbed$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_service_testbed_OBJECTS) $(gnunet_service_testbed_LDADD) $(LIBS)
+gnunet-testbed-profiler$(EXEEXT): $(gnunet_testbed_profiler_OBJECTS) $(gnunet_testbed_profiler_DEPENDENCIES) $(EXTRA_gnunet_testbed_profiler_DEPENDENCIES)
+ @rm -f gnunet-testbed-profiler$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_testbed_profiler_OBJECTS) $(gnunet_testbed_profiler_LDADD) $(LIBS)
+ll-master$(EXEEXT): $(ll_master_OBJECTS) $(ll_master_DEPENDENCIES) $(EXTRA_ll_master_DEPENDENCIES)
+ @rm -f ll-master$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ll_master_OBJECTS) $(ll_master_LDADD) $(LIBS)
+ll-monitor$(EXEEXT): $(ll_monitor_OBJECTS) $(ll_monitor_DEPENDENCIES) $(EXTRA_ll_monitor_DEPENDENCIES)
+ @rm -f ll-monitor$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ll_monitor_OBJECTS) $(ll_monitor_LDADD) $(LIBS)
+test_gnunet_helper_testbed$(EXEEXT): $(test_gnunet_helper_testbed_OBJECTS) $(test_gnunet_helper_testbed_DEPENDENCIES) $(EXTRA_test_gnunet_helper_testbed_DEPENDENCIES)
+ @rm -f test_gnunet_helper_testbed$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_gnunet_helper_testbed_OBJECTS) $(test_gnunet_helper_testbed_LDADD) $(LIBS)
+test_testbed_api$(EXEEXT): $(test_testbed_api_OBJECTS) $(test_testbed_api_DEPENDENCIES) $(EXTRA_test_testbed_api_DEPENDENCIES)
+ @rm -f test_testbed_api$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_OBJECTS) $(test_testbed_api_LDADD) $(LIBS)
+test_testbed_api_2peers_1controller$(EXEEXT): $(test_testbed_api_2peers_1controller_OBJECTS) $(test_testbed_api_2peers_1controller_DEPENDENCIES) $(EXTRA_test_testbed_api_2peers_1controller_DEPENDENCIES)
+ @rm -f test_testbed_api_2peers_1controller$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_2peers_1controller_OBJECTS) $(test_testbed_api_2peers_1controller_LDADD) $(LIBS)
+test_testbed_api_3peers_3controllers$(EXEEXT): $(test_testbed_api_3peers_3controllers_OBJECTS) $(test_testbed_api_3peers_3controllers_DEPENDENCIES) $(EXTRA_test_testbed_api_3peers_3controllers_DEPENDENCIES)
+ @rm -f test_testbed_api_3peers_3controllers$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_3peers_3controllers_OBJECTS) $(test_testbed_api_3peers_3controllers_LDADD) $(LIBS)
+test_testbed_api_controllerlink$(EXEEXT): $(test_testbed_api_controllerlink_OBJECTS) $(test_testbed_api_controllerlink_DEPENDENCIES) $(EXTRA_test_testbed_api_controllerlink_DEPENDENCIES)
+ @rm -f test_testbed_api_controllerlink$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_controllerlink_OBJECTS) $(test_testbed_api_controllerlink_LDADD) $(LIBS)
+test_testbed_api_hosts$(EXEEXT): $(test_testbed_api_hosts_OBJECTS) $(test_testbed_api_hosts_DEPENDENCIES) $(EXTRA_test_testbed_api_hosts_DEPENDENCIES)
+ @rm -f test_testbed_api_hosts$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_hosts_OBJECTS) $(test_testbed_api_hosts_LDADD) $(LIBS)
+test_testbed_api_operations$(EXEEXT): $(test_testbed_api_operations_OBJECTS) $(test_testbed_api_operations_DEPENDENCIES) $(EXTRA_test_testbed_api_operations_DEPENDENCIES)
+ @rm -f test_testbed_api_operations$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_operations_OBJECTS) $(test_testbed_api_operations_LDADD) $(LIBS)
+test_testbed_api_test$(EXEEXT): $(test_testbed_api_test_OBJECTS) $(test_testbed_api_test_DEPENDENCIES) $(EXTRA_test_testbed_api_test_DEPENDENCIES)
+ @rm -f test_testbed_api_test$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_test_OBJECTS) $(test_testbed_api_test_LDADD) $(LIBS)
+test_testbed_api_testbed_run$(EXEEXT): $(test_testbed_api_testbed_run_OBJECTS) $(test_testbed_api_testbed_run_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_OBJECTS) $(test_testbed_api_testbed_run_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topology2dtorus$(EXEEXT): $(test_testbed_api_testbed_run_topology2dtorus_OBJECTS) $(test_testbed_api_testbed_run_topology2dtorus_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topology2dtorus_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topology2dtorus$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topology2dtorus_OBJECTS) $(test_testbed_api_testbed_run_topology2dtorus_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologyclique$(EXEEXT): $(test_testbed_api_testbed_run_topologyclique_OBJECTS) $(test_testbed_api_testbed_run_topologyclique_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologyclique_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologyclique$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologyclique_OBJECTS) $(test_testbed_api_testbed_run_topologyclique_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologyfromfile$(EXEEXT): $(test_testbed_api_testbed_run_topologyfromfile_OBJECTS) $(test_testbed_api_testbed_run_topologyfromfile_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologyfromfile_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologyfromfile$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologyfromfile_OBJECTS) $(test_testbed_api_testbed_run_topologyfromfile_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologyline$(EXEEXT): $(test_testbed_api_testbed_run_topologyline_OBJECTS) $(test_testbed_api_testbed_run_topologyline_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologyline_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologyline$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologyline_OBJECTS) $(test_testbed_api_testbed_run_topologyline_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologyrandom$(EXEEXT): $(test_testbed_api_testbed_run_topologyrandom_OBJECTS) $(test_testbed_api_testbed_run_topologyrandom_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologyrandom_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologyrandom$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologyrandom_OBJECTS) $(test_testbed_api_testbed_run_topologyrandom_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologyring$(EXEEXT): $(test_testbed_api_testbed_run_topologyring_OBJECTS) $(test_testbed_api_testbed_run_topologyring_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologyring_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologyring$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologyring_OBJECTS) $(test_testbed_api_testbed_run_topologyring_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologyscalefree$(EXEEXT): $(test_testbed_api_testbed_run_topologyscalefree_OBJECTS) $(test_testbed_api_testbed_run_topologyscalefree_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologyscalefree_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologyscalefree$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologyscalefree_OBJECTS) $(test_testbed_api_testbed_run_topologyscalefree_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologysmallworld$(EXEEXT): $(test_testbed_api_testbed_run_topologysmallworld_OBJECTS) $(test_testbed_api_testbed_run_topologysmallworld_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologysmallworld_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologysmallworld$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologysmallworld_OBJECTS) $(test_testbed_api_testbed_run_topologysmallworld_LDADD) $(LIBS)
+test_testbed_api_testbed_run_topologysmallworldring$(EXEEXT): $(test_testbed_api_testbed_run_topologysmallworldring_OBJECTS) $(test_testbed_api_testbed_run_topologysmallworldring_DEPENDENCIES) $(EXTRA_test_testbed_api_testbed_run_topologysmallworldring_DEPENDENCIES)
+ @rm -f test_testbed_api_testbed_run_topologysmallworldring$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_testbed_run_topologysmallworldring_OBJECTS) $(test_testbed_api_testbed_run_topologysmallworldring_LDADD) $(LIBS)
+test_testbed_api_topology$(EXEEXT): $(test_testbed_api_topology_OBJECTS) $(test_testbed_api_topology_DEPENDENCIES) $(EXTRA_test_testbed_api_topology_DEPENDENCIES)
+ @rm -f test_testbed_api_topology$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_topology_OBJECTS) $(test_testbed_api_topology_LDADD) $(LIBS)
+test_testbed_api_topology_clique$(EXEEXT): $(test_testbed_api_topology_clique_OBJECTS) $(test_testbed_api_topology_clique_DEPENDENCIES) $(EXTRA_test_testbed_api_topology_clique_DEPENDENCIES)
+ @rm -f test_testbed_api_topology_clique$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_testbed_api_topology_clique_OBJECTS) $(test_testbed_api_topology_clique_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -445,11 +1145,31 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-testbed.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-testbed.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-testbed_cache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-testbed_oc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-testbed-profiler.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet_mpi_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ll_master.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ll_monitor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_gnunet_helper_testbed.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_2peers_1controller.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_3peers_3controllers.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_controllerlink.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_hosts.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_operations.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_testbed_run.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_topology.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_testbed_api_topology_clique.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_hosts.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_operations.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_peers.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_services.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_statistics.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_test.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_testbed.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testbed_api_topology.Plo@am__quote@
@@ -457,36 +1177,36 @@ distclean-compile:
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
-@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
-@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
-install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA)
+install-pkgcfgDATA: $(pkgcfg_DATA)
@$(NORMAL_INSTALL)
- test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)"
- @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgcfgdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)" || exit 1; \
+ fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -496,13 +1216,11 @@ install-dist_pkgcfgDATA: $(dist_pkgcfg_DATA)
$(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \
done
-uninstall-dist_pkgcfgDATA:
+uninstall-pkgcfgDATA:
@$(NORMAL_UNINSTALL)
- @list='$(dist_pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- test -n "$$files" || exit 0; \
- echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \
- cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files
+ dir='$(DESTDIR)$(pkgcfgdir)'; $(am__uninstall_files_from_dir)
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
@@ -556,6 +1274,99 @@ GTAGS:
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -587,10 +1398,14 @@ distdir: $(DISTFILES)
fi; \
done
check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
check: check-am
-all-am: Makefile $(LTLIBRARIES) $(DATA)
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
+install-binPROGRAMS: install-libLTLIBRARIES
+
installdirs:
- for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgcfgdir)"; do \
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(pkgcfgdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -603,10 +1418,15 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
- $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
- install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
- `test -z '$(STRIP)' || \
- echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
mostlyclean-generic:
clean-generic:
@@ -620,8 +1440,9 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
-clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
- mostlyclean-am
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libexecPROGRAMS clean-libtool \
+ clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
@@ -641,13 +1462,14 @@ info: info-am
info-am:
-install-data-am: install-dist_pkgcfgDATA
+install-data-am: install-pkgcfgDATA
install-dvi: install-dvi-am
install-dvi-am:
-install-exec-am: install-libLTLIBRARIES
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \
+ install-libexecPROGRAMS
install-html: install-html-am
@@ -687,25 +1509,28 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-dist_pkgcfgDATA uninstall-libLTLIBRARIES
-
-.MAKE: install-am install-strip
-
-.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
- clean-libLTLIBRARIES clean-libtool ctags distclean \
- distclean-compile distclean-generic distclean-libtool \
- distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-data install-data-am \
- install-dist_pkgcfgDATA install-dvi install-dvi-am \
- install-exec install-exec-am install-html install-html-am \
- install-info install-info-am install-libLTLIBRARIES \
- install-man install-pdf install-pdf-am install-ps \
+uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-libexecPROGRAMS uninstall-pkgcfgDATA
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libexecPROGRAMS clean-libtool \
+ clean-noinstPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-libexecPROGRAMS install-man \
+ install-pdf install-pdf-am install-pkgcfgDATA install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
- uninstall-am uninstall-dist_pkgcfgDATA \
- uninstall-libLTLIBRARIES
+ uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-libexecPROGRAMS uninstall-pkgcfgDATA
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/src/testbed/gnunet-helper-testbed.c b/src/testbed/gnunet-helper-testbed.c
new file mode 100644
index 0000000..7d0bf87
--- /dev/null
+++ b/src/testbed/gnunet-helper-testbed.c
@@ -0,0 +1,489 @@
+/*
+ This file is part of GNUnet
+ (C) 2012 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 3, 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 testbed/gnunet-helper-testbed.c
+ * @brief Helper binary that is started from a remote controller to start
+ * gnunet-service-testbed. This binary also receives configuration
+ * from the remove controller which is put in a temporary location
+ * with ports and paths fixed so that gnunet-service-testbed runs
+ * without any hurdles. This binary also kills the testbed service
+ * should the connection from the remote controller is dropped
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_testbed_service.h"
+#include "testbed_helper.h"
+#include "testbed_api.h"
+#include <zlib.h>
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind, ...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Debug logging shorthand
+ */
+#define LOG_DEBUG(...) \
+ LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
+
+
+/**
+ * We need pipe control only on WINDOWS
+ */
+#if WINDOWS
+#define PIPE_CONTROL GNUNET_YES
+#else
+#define PIPE_CONTROL GNUNET_NO
+#endif
+
+
+/**
+ * Context for a single write on a chunk of memory
+ */
+struct WriteContext
+{
+ /**
+ * The data to write
+ */
+ void *data;
+
+ /**
+ * The length of the data
+ */
+ size_t length;
+
+ /**
+ * The current position from where the write operation should begin
+ */
+ size_t pos;
+};
+
+
+/**
+ * Handle to the testing system
+ */
+static struct GNUNET_TESTING_System *test_system;
+
+/**
+ * Our message stream tokenizer
+ */
+struct GNUNET_SERVER_MessageStreamTokenizer *tokenizer;
+
+/**
+ * Disk handle from stdin
+ */
+static struct GNUNET_DISK_FileHandle *stdin_fd;
+
+/**
+ * Disk handle for stdout
+ */
+static struct GNUNET_DISK_FileHandle *stdout_fd;
+
+/**
+ * The process handle to the testbed service
+ */
+static struct GNUNET_OS_Process *testbed;
+
+/**
+ * Task identifier for the read task
+ */
+static GNUNET_SCHEDULER_TaskIdentifier read_task_id;
+
+/**
+ * Task identifier for the write task
+ */
+static GNUNET_SCHEDULER_TaskIdentifier write_task_id;
+
+/**
+ * Are we done reading messages from stdin?
+ */
+static int done_reading;
+
+/**
+ * Result to return in case we fail
+ */
+static int status;
+
+
+/**
+ * Are we shutting down
+ */
+static int in_shutdown;
+
+
+/**
+ * Task to shutting down nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG_DEBUG ("Shutting down\n");
+ in_shutdown = GNUNET_YES;
+ if (GNUNET_SCHEDULER_NO_TASK != read_task_id)
+ {
+ GNUNET_SCHEDULER_cancel (read_task_id);
+ read_task_id = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != write_task_id)
+ {
+ GNUNET_SCHEDULER_cancel (write_task_id);
+ write_task_id = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != stdin_fd)
+ (void) GNUNET_DISK_file_close (stdin_fd);
+ if (NULL != stdout_fd)
+ (void) GNUNET_DISK_file_close (stdout_fd);
+ GNUNET_SERVER_mst_destroy (tokenizer);
+ tokenizer = NULL;
+ if (NULL != testbed)
+ {
+ LOG_DEBUG ("Killing testbed\n");
+ GNUNET_break (0 == GNUNET_OS_process_kill (testbed, SIGTERM));
+ GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (testbed));
+ GNUNET_OS_process_destroy (testbed);
+ testbed = NULL;
+ }
+ if (NULL != test_system)
+ {
+ GNUNET_TESTING_system_destroy (test_system, GNUNET_YES);
+ test_system = NULL;
+ }
+}
+
+
+/**
+ * Task to write to the standard out
+ *
+ * @param cls the WriteContext
+ * @param tc the TaskContext
+ */
+static void
+write_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct WriteContext *wc = cls;
+ ssize_t bytes_wrote;
+
+ GNUNET_assert (NULL != wc);
+ write_task_id = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ {
+ GNUNET_free (wc->data);
+ GNUNET_free (wc);
+ return;
+ }
+ bytes_wrote =
+ GNUNET_DISK_file_write (stdout_fd, wc->data + wc->pos,
+ wc->length - wc->pos);
+ if (GNUNET_SYSERR == bytes_wrote)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Cannot reply back configuration\n");
+ GNUNET_free (wc->data);
+ GNUNET_free (wc);
+ return;
+ }
+ wc->pos += bytes_wrote;
+ if (wc->pos == wc->length)
+ {
+ GNUNET_free (wc->data);
+ GNUNET_free (wc);
+ return;
+ }
+ write_task_id =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_fd,
+ &write_task, wc);
+}
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * Do not call GNUNET_SERVER_mst_destroy in callback
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
+ */
+static int
+tokenizer_cb (void *cls, void *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_HelperInit *msg;
+ struct GNUNET_TESTBED_HelperReply *reply;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct WriteContext *wc;
+ char *binary;
+ char *trusted_ip;
+ char *hostname;
+ char *config;
+ char *xconfig;
+ size_t config_size;
+ uLongf ul_config_size;
+ size_t xconfig_size;
+ uint16_t trusted_ip_size;
+ uint16_t hostname_size;
+ uint16_t msize;
+
+ msize = ntohs (message->size);
+ if ((sizeof (struct GNUNET_TESTBED_HelperInit) >= msize) ||
+ (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT != ntohs (message->type)))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
+ goto error;
+ }
+ msg = (const struct GNUNET_TESTBED_HelperInit *) message;
+ trusted_ip_size = ntohs (msg->trusted_ip_size);
+ trusted_ip = (char *) &msg[1];
+ if ('\0' != trusted_ip[trusted_ip_size])
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Trusted IP cannot be empty -- exiting\n");
+ goto error;
+ }
+ hostname_size = ntohs (msg->hostname_size);
+ if ((sizeof (struct GNUNET_TESTBED_HelperInit) + trusted_ip_size + 1 +
+ hostname_size) >= msize)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
+ goto error;
+ }
+ ul_config_size = (uLongf) ntohs (msg->config_size);
+ config = GNUNET_malloc (ul_config_size);
+ xconfig_size =
+ ntohs (message->size) - (trusted_ip_size + 1 +
+ sizeof (struct GNUNET_TESTBED_HelperInit));
+ if (Z_OK !=
+ uncompress ((Bytef *) config, &ul_config_size,
+ (const Bytef *) (trusted_ip + trusted_ip_size + 1 +
+ hostname_size), (uLongf) xconfig_size))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Error while uncompressing config -- exiting\n");
+ GNUNET_free (config);
+ goto error;
+ }
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_deserialize (cfg, config, ul_config_size, GNUNET_NO))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Unable to deserialize config -- exiting\n");
+ GNUNET_free (config);
+ goto error;
+ }
+ GNUNET_free (config);
+ hostname = NULL;
+ if (0 != hostname_size)
+ {
+ hostname = GNUNET_malloc (hostname_size + 1);
+ (void) strncpy (hostname, ((char *) &msg[1]) + trusted_ip_size + 1,
+ hostname_size);
+ hostname[hostname_size] = '\0';
+ }
+ test_system =
+ GNUNET_TESTING_system_create ("testbed-helper", trusted_ip, hostname);
+ GNUNET_free_non_null (hostname);
+ hostname = NULL;
+ GNUNET_assert (NULL != test_system);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_TESTING_configuration_create (test_system, cfg));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
+ "DEFAULTCONFIG",
+ &config));
+ if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Unable to write config file: %s -- exiting\n", config);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_free (config);
+ goto error;
+ }
+ LOG_DEBUG ("Staring testbed with config: %s\n", config);
+ binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-testbed");
+ testbed =
+ GNUNET_OS_start_process (PIPE_CONTROL,
+ GNUNET_OS_INHERIT_STD_ERR /*verbose? */ , NULL,
+ NULL, binary, "gnunet-service-testbed", "-c",
+ config, NULL);
+ GNUNET_free (binary);
+ GNUNET_free (config);
+ if (NULL == testbed)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Error starting gnunet-service-testbed -- exiting\n");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ goto error;
+ }
+ done_reading = GNUNET_YES;
+ config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ cfg = NULL;
+ xconfig_size =
+ GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
+ GNUNET_free (config);
+ wc = GNUNET_malloc (sizeof (struct WriteContext));
+ wc->length = xconfig_size + sizeof (struct GNUNET_TESTBED_HelperReply);
+ reply = GNUNET_realloc (xconfig, wc->length);
+ memmove (&reply[1], reply, xconfig_size);
+ reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY);
+ reply->header.size = htons ((uint16_t) wc->length);
+ reply->config_size = htons ((uint16_t) config_size);
+ wc->data = reply;
+ write_task_id =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_fd,
+ &write_task, wc);
+ return GNUNET_OK;
+
+error:
+ status = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_shutdown ();
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Task to read from stdin
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
+ ssize_t sread;
+
+ read_task_id = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+ sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof (buf));
+ if ((GNUNET_SYSERR == sread) || (0 == sread))
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_YES == done_reading)
+ {
+ /* didn't expect any more data! */
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ LOG_DEBUG ("Read %u bytes\n", sread);
+ if (GNUNET_OK !=
+ GNUNET_SERVER_mst_receive (tokenizer, NULL, buf, sread, GNUNET_NO,
+ GNUNET_NO))
+ {
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ read_task_id = /* No timeout while reading */
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdin_fd,
+ &read_task, NULL);
+}
+
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ LOG_DEBUG ("Starting testbed helper...\n");
+ tokenizer = GNUNET_SERVER_mst_create (&tokenizer_cb, NULL);
+ stdin_fd = GNUNET_DISK_get_handle_from_native (stdin);
+ stdout_fd = GNUNET_DISK_get_handle_from_native (stdout);
+ read_task_id =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdin_fd,
+ &read_task, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+ NULL);
+}
+
+
+/**
+ * Signal handler called for SIGCHLD.
+ */
+static void
+sighandler_child_death ()
+{
+ if ((NULL != testbed) && (GNUNET_NO == in_shutdown))
+ {
+ LOG_DEBUG ("Child died\n");
+ GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (testbed));
+ GNUNET_OS_process_destroy (testbed);
+ testbed = NULL;
+ GNUNET_SCHEDULER_shutdown (); /* We are done too! */
+ }
+}
+
+
+/**
+ * Main function
+ *
+ * @param argc the number of command line arguments
+ * @param argv command line arg array
+ * @return return code
+ */
+int
+main (int argc, char **argv)
+{
+ struct GNUNET_SIGNAL_Context *shc_chld;
+
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ status = GNUNET_OK;
+ in_shutdown = GNUNET_NO;
+ shc_chld =
+ GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
+ ret =
+ GNUNET_PROGRAM_run (argc, argv, "gnunet-helper-testbed",
+ "Helper for starting gnunet-service-testbed", options,
+ &run, NULL);
+ GNUNET_SIGNAL_handler_uninstall (shc_chld);
+ shc_chld = NULL;
+ if (GNUNET_OK != ret)
+ return 1;
+ return (GNUNET_OK == status) ? 0 : 1;
+}
+
+/* end of gnunet-helper-testbed.c */
diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c
new file mode 100644
index 0000000..f1dc3fa
--- /dev/null
+++ b/src/testbed/gnunet-service-testbed.c
@@ -0,0 +1,2227 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 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 testbed/gnunet-service-testbed.c
+ * @brief implementation of the TESTBED service
+ * @author Sree Harsha Totakura
+ */
+
+#include "gnunet-service-testbed.h"
+
+#include <zlib.h>
+
+
+/***********/
+/* Globals */
+/***********/
+
+/**
+ * Our configuration
+ */
+struct GNUNET_CONFIGURATION_Handle *our_config;
+
+/**
+ * The master context; generated with the first INIT message
+ */
+struct Context *GST_context;
+
+/**
+ * A list of directly linked neighbours
+ */
+struct Slave **GST_slave_list;
+
+/**
+ * A list of peers we know about
+ */
+struct Peer **GST_peer_list;
+
+/**
+ * Array of hosts
+ */
+struct GNUNET_TESTBED_Host **GST_host_list;
+
+/**
+ * DLL head for forwarded operation contexts
+ */
+struct ForwardedOperationContext *fopcq_head;
+
+/**
+ * DLL tail for forwarded operation contexts
+ */
+struct ForwardedOperationContext *fopcq_tail;
+
+/**
+ * Operation queue for open file descriptors
+ */
+struct OperationQueue *GST_opq_openfds;
+
+/**
+ * The size of the host list
+ */
+unsigned int GST_host_list_size;
+
+/**
+ * The size of directly linked neighbours list
+ */
+unsigned int GST_slave_list_size;
+
+/**
+ * The size of the peer list
+ */
+unsigned int GST_peer_list_size;
+
+
+/***********************************/
+/* Local definitions and variables */
+/***********************************/
+
+/**
+ * The message queue for sending messages to clients
+ */
+struct MessageQueue
+{
+ /**
+ * The message to be sent
+ */
+ struct GNUNET_MessageHeader *msg;
+
+ /**
+ * The client to send the message to
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * next pointer for DLL
+ */
+ struct MessageQueue *next;
+
+ /**
+ * prev pointer for DLL
+ */
+ struct MessageQueue *prev;
+};
+
+/**
+ * Our hostname; we give this to all the peers we start
+ */
+static char *hostname;
+
+/**
+ * Current Transmit Handle; NULL if no notify transmit exists currently
+ */
+static struct GNUNET_SERVER_TransmitHandle *transmit_handle;
+
+/**
+ * The head for the LCF queue
+ */
+static struct LCFContextQueue *lcfq_head;
+
+/**
+ * The tail for the LCF queue
+ */
+static struct LCFContextQueue *lcfq_tail;
+
+/**
+ * The message queue head
+ */
+static struct MessageQueue *mq_head;
+
+/**
+ * The message queue tail
+ */
+static struct MessageQueue *mq_tail;
+
+/**
+ * The hashmap of shared services
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *ss_map;
+
+/**
+ * A list of routes
+ */
+static struct Route **route_list;
+
+/**
+ * The event mask for the events we listen from sub-controllers
+ */
+static uint64_t event_mask;
+
+/**
+ * The size of the route list
+ */
+static unsigned int route_list_size;
+
+/**
+ * The lcf_task handle
+ */
+static GNUNET_SCHEDULER_TaskIdentifier lcf_proc_task_id;
+
+/**
+ * The shutdown task handle
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
+
+
+/**
+ * Function called to notify a client about the connection begin ready to queue
+ * more data. "buf" will be NULL and "size" zero if the connection was closed
+ * for writing in the meantime.
+ *
+ * @param cls NULL
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_ready_notify (void *cls, size_t size, void *buf)
+{
+ struct MessageQueue *mq_entry;
+
+ transmit_handle = NULL;
+ mq_entry = mq_head;
+ GNUNET_assert (NULL != mq_entry);
+ if (0 == size)
+ return 0;
+ GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
+ size = ntohs (mq_entry->msg->size);
+ memcpy (buf, mq_entry->msg, size);
+ GNUNET_free (mq_entry->msg);
+ GNUNET_SERVER_client_drop (mq_entry->client);
+ GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
+ GNUNET_free (mq_entry);
+ mq_entry = mq_head;
+ if (NULL != mq_entry)
+ transmit_handle =
+ GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
+ ntohs (mq_entry->msg->size),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_ready_notify, NULL);
+ return size;
+}
+
+
+/**
+ * Queues a message in send queue for sending to the service
+ *
+ * @param client the client to whom the queued message has to be sent
+ * @param msg the message to queue
+ */
+void
+GST_queue_message (struct GNUNET_SERVER_Client *client,
+ struct GNUNET_MessageHeader *msg)
+{
+ struct MessageQueue *mq_entry;
+ uint16_t type;
+ uint16_t size;
+
+ type = ntohs (msg->type);
+ size = ntohs (msg->size);
+ GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
+ (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
+ mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
+ mq_entry->msg = msg;
+ mq_entry->client = client;
+ GNUNET_SERVER_client_keep (client);
+ LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
+ ntohs (msg->size));
+ GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
+ if (NULL == transmit_handle)
+ transmit_handle =
+ GNUNET_SERVER_notify_transmit_ready (client, size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_ready_notify, NULL);
+}
+
+
+/**
+ * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
+ * several times we call it only once. The array is also made to grow in steps
+ * of LIST_GROW_STEP.
+ *
+ * @param ptr the array pointer to grow
+ * @param size the size of array
+ * @param accommodate_size the size which the array has to accommdate; after
+ * this call the array will be big enough to accommdate sizes upto
+ * accommodate_size
+ */
+#define array_grow_large_enough(ptr, size, accommodate_size) \
+ do \
+ { \
+ unsigned int growth_size; \
+ GNUNET_assert (size <= accommodate_size); \
+ growth_size = size; \
+ while (growth_size <= accommodate_size) \
+ growth_size += LIST_GROW_STEP; \
+ GNUNET_array_grow (ptr, size, growth_size); \
+ GNUNET_assert (size > accommodate_size); \
+ } while (0)
+
+
+/**
+ * Function to add a host to the current list of known hosts
+ *
+ * @param host the host to add
+ * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
+ * already in use
+ */
+static int
+host_list_add (struct GNUNET_TESTBED_Host *host)
+{
+ uint32_t host_id;
+
+ host_id = GNUNET_TESTBED_host_get_id_ (host);
+ if (GST_host_list_size <= host_id)
+ array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
+ if (NULL != GST_host_list[host_id])
+ {
+ LOG_DEBUG ("A host with id: %u already exists\n", host_id);
+ return GNUNET_SYSERR;
+ }
+ GST_host_list[host_id] = host;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Adds a route to the route list
+ *
+ * @param route the route to add
+ */
+static void
+route_list_add (struct Route *route)
+{
+ if (route->dest >= route_list_size)
+ array_grow_large_enough (route_list, route_list_size, route->dest);
+ GNUNET_assert (NULL == route_list[route->dest]);
+ route_list[route->dest] = route;
+}
+
+
+/**
+ * Adds a slave to the slave array
+ *
+ * @param slave the slave controller to add
+ */
+static void
+slave_list_add (struct Slave *slave)
+{
+ if (slave->host_id >= GST_slave_list_size)
+ array_grow_large_enough (GST_slave_list, GST_slave_list_size,
+ slave->host_id);
+ GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
+ GST_slave_list[slave->host_id] = slave;
+}
+
+
+/**
+ * Adds a peer to the peer array
+ *
+ * @param peer the peer to add
+ */
+static void
+peer_list_add (struct Peer *peer)
+{
+ if (peer->id >= GST_peer_list_size)
+ array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
+ GNUNET_assert (NULL == GST_peer_list[peer->id]);
+ GST_peer_list[peer->id] = peer;
+}
+
+
+/**
+ * Removes a the give peer from the peer array
+ *
+ * @param peer the peer to be removed
+ */
+static void
+peer_list_remove (struct Peer *peer)
+{
+ unsigned int orig_size;
+ uint32_t id;
+
+ GST_peer_list[peer->id] = NULL;
+ orig_size = GST_peer_list_size;
+ while (GST_peer_list_size >= LIST_GROW_STEP)
+ {
+ for (id = GST_peer_list_size - 1;
+ (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
+ id--)
+ if (NULL != GST_peer_list[id])
+ break;
+ if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
+ break;
+ GST_peer_list_size -= LIST_GROW_STEP;
+ }
+ if (orig_size == GST_peer_list_size)
+ return;
+ GST_peer_list =
+ GNUNET_realloc (GST_peer_list,
+ sizeof (struct Peer *) * GST_peer_list_size);
+}
+
+
+/**
+ * Finds the route with directly connected host as destination through which
+ * the destination host can be reached
+ *
+ * @param host_id the id of the destination host
+ * @return the route with directly connected destination host; NULL if no route
+ * is found
+ */
+struct Route *
+GST_find_dest_route (uint32_t host_id)
+{
+ struct Route *route;
+
+ if (route_list_size <= host_id)
+ return NULL;
+ while (NULL != (route = route_list[host_id]))
+ {
+ if (route->thru == GST_context->host_id)
+ break;
+ host_id = route->thru;
+ }
+ return route;
+}
+
+
+/**
+ * Routes message to a host given its host_id
+ *
+ * @param host_id the id of the destination host
+ * @param msg the message to be routed
+ */
+static void
+route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
+{
+ GNUNET_break (0);
+}
+
+
+/**
+ * Send operation failure message to client
+ *
+ * @param client the client to which the failure message has to be sent to
+ * @param operation_id the id of the failed operation
+ * @param emsg the error message; can be NULL
+ */
+void
+GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
+ uint64_t operation_id, const char *emsg)
+{
+ struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
+ uint16_t msize;
+ uint16_t emsg_len;
+
+ msize = sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
+ emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
+ msize += emsg_len;
+ msg = GNUNET_malloc (msize);
+ msg->header.size = htons (msize);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
+ msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ msg->operation_id = GNUNET_htonll (operation_id);
+ if (0 != emsg_len)
+ memcpy (&msg[1], emsg, emsg_len);
+ GST_queue_message (client, &msg->header);
+}
+
+
+/**
+ * Function to send generic operation success message to given client
+ *
+ * @param client the client to send the message to
+ * @param operation_id the id of the operation which was successful
+ */
+static void
+send_operation_success_msg (struct GNUNET_SERVER_Client *client,
+ uint64_t operation_id)
+{
+ struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
+ uint16_t msize;
+
+ msize = sizeof (struct GNUNET_TESTBED_GenericOperationSuccessEventMessage);
+ msg = GNUNET_malloc (msize);
+ msg->header.size = htons (msize);
+ msg->header.type =
+ htons (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
+ msg->operation_id = GNUNET_htonll (operation_id);
+ msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ GST_queue_message (client, &msg->header);
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the handle to the slave at which the registration is completed
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+hr_completion (void *cls, const char *emsg);
+
+
+/**
+ * Attempts to register the next host in the host registration queue
+ *
+ * @param slave the slave controller whose host registration queue is checked
+ * for host registrations
+ */
+static void
+register_next_host (struct Slave *slave)
+{
+ struct HostRegistration *hr;
+
+ hr = slave->hr_dll_head;
+ GNUNET_assert (NULL != hr);
+ GNUNET_assert (NULL == slave->rhandle);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
+ GNUNET_TESTBED_host_get_id_ (hr->host),
+ GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
+ slave->rhandle =
+ GNUNET_TESTBED_register_host (slave->controller, hr->host, hr_completion,
+ slave);
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the handle to the slave at which the registration is completed
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+hr_completion (void *cls, const char *emsg)
+{
+ struct Slave *slave = cls;
+ struct HostRegistration *hr;
+
+ slave->rhandle = NULL;
+ hr = slave->hr_dll_head;
+ GNUNET_assert (NULL != hr);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u successful\n",
+ GNUNET_TESTBED_host_get_id_ (hr->host),
+ GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
+ GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail, hr);
+ if (NULL != hr->cb)
+ hr->cb (hr->cb_cls, emsg);
+ GNUNET_free (hr);
+ if (NULL != slave->hr_dll_head)
+ register_next_host (slave);
+}
+
+
+/**
+ * Adds a host registration's request to a slave's registration queue
+ *
+ * @param slave the slave controller at which the given host has to be
+ * registered
+ * @param cb the host registration completion callback
+ * @param cb_cls the closure for the host registration completion callback
+ * @param host the host which has to be registered
+ */
+void
+GST_queue_host_registration (struct Slave *slave,
+ GNUNET_TESTBED_HostRegistrationCompletion cb,
+ void *cb_cls, struct GNUNET_TESTBED_Host *host)
+{
+ struct HostRegistration *hr;
+ int call_register;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Queueing host registration for host %u at %u\n",
+ GNUNET_TESTBED_host_get_id_ (host),
+ GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
+ hr = GNUNET_malloc (sizeof (struct HostRegistration));
+ hr->cb = cb;
+ hr->cb_cls = cb_cls;
+ hr->host = host;
+ call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
+ GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head, slave->hr_dll_tail, hr);
+ if (GNUNET_YES == call_register)
+ register_next_host (slave);
+}
+
+
+/**
+ * The Link Controller forwarding task
+ *
+ * @param cls the LCFContext
+ * @param tc the Task context from scheduler
+ */
+static void
+lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Completion callback for host registrations while forwarding Link Controller messages
+ *
+ * @param cls the LCFContext
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+lcf_proc_cc (void *cls, const char *emsg)
+{
+ struct LCFContext *lcf = cls;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
+ switch (lcf->state)
+ {
+ case INIT:
+ if (NULL != emsg)
+ goto registration_error;
+ lcf->state = DELEGATED_HOST_REGISTERED;
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+ break;
+ case DELEGATED_HOST_REGISTERED:
+ if (NULL != emsg)
+ goto registration_error;
+ lcf->state = SLAVE_HOST_REGISTERED;
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+ break;
+ default:
+ GNUNET_assert (0); /* Shouldn't reach here */
+ }
+ return;
+
+registration_error:
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Host registration failed with message: %s\n",
+ emsg);
+ lcf->state = FINISHED;
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+}
+
+
+/**
+ * Callback to relay the reply msg of a forwarded operation back to the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the message to relay
+ */
+void
+GST_forwarded_operation_reply_relay (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct ForwardedOperationContext *fopc = cls;
+ struct GNUNET_MessageHeader *dup_msg;
+ uint16_t msize;
+
+ msize = ntohs (msg->size);
+ LOG_DEBUG ("Relaying message with type: %u, size: %u\n", ntohs (msg->type),
+ msize);
+ dup_msg = GNUNET_copy_message (msg);
+ GST_queue_message (fopc->client, dup_msg);
+ GNUNET_SERVER_client_drop (fopc->client);
+ GNUNET_SCHEDULER_cancel (fopc->timeout_task);
+ GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
+ GNUNET_free (fopc);
+}
+
+
+/**
+ * Task to free resources when forwarded operation has been timedout
+ *
+ * @param cls the ForwardedOperationContext
+ * @param tc the task context from scheduler
+ */
+void
+GST_forwarded_operation_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ForwardedOperationContext *fopc = cls;
+
+ GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
+ LOG (GNUNET_ERROR_TYPE_WARNING, "A forwarded operation has timed out\n");
+ GST_send_operation_fail_msg (fopc->client, fopc->operation_id, "Timeout");
+ GNUNET_SERVER_client_drop (fopc->client);
+ GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
+ GNUNET_free (fopc);
+}
+
+
+/**
+ * The Link Controller forwarding task
+ *
+ * @param cls the LCFContext
+ * @param tc the Task context from scheduler
+ */
+static void
+lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Callback to be called when forwarded link controllers operation is
+ * successfull. We have to relay the reply msg back to the client
+ *
+ * @param cls the LCFContext
+ * @param msg the message to relay
+ */
+static void
+lcf_forwarded_operation_reply_relay (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct LCFContext *lcf = cls;
+
+ GNUNET_assert (NULL != lcf->fopc);
+ GST_forwarded_operation_reply_relay (lcf->fopc, msg);
+ lcf->fopc = NULL;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+}
+
+
+/**
+ * Task to free resources when forwarded link controllers has been timedout
+ *
+ * @param cls the LCFContext
+ * @param tc the task context from scheduler
+ */
+static void
+lcf_forwarded_operation_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct LCFContext *lcf = cls;
+
+ GNUNET_assert (NULL != lcf->fopc);
+ lcf->fopc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GST_forwarded_operation_timeout (lcf->fopc, tc);
+ lcf->fopc = NULL;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+}
+
+
+/**
+ * The Link Controller forwarding task
+ *
+ * @param cls the LCFContext
+ * @param tc the Task context from scheduler
+ */
+static void
+lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct LCFContext *lcf = cls;
+ struct LCFContextQueue *lcfq;
+
+ lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
+ switch (lcf->state)
+ {
+ case INIT:
+ if (GNUNET_NO ==
+ GNUNET_TESTBED_is_host_registered_ (GST_host_list
+ [lcf->delegated_host_id],
+ lcf->gateway->controller))
+ {
+ GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
+ GST_host_list[lcf->delegated_host_id]);
+ }
+ else
+ {
+ lcf->state = DELEGATED_HOST_REGISTERED;
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+ }
+ break;
+ case DELEGATED_HOST_REGISTERED:
+ if (GNUNET_NO ==
+ GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
+ lcf->gateway->controller))
+ {
+ GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
+ GST_host_list[lcf->slave_host_id]);
+ }
+ else
+ {
+ lcf->state = SLAVE_HOST_REGISTERED;
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+ }
+ break;
+ case SLAVE_HOST_REGISTERED:
+ lcf->fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ lcf->fopc->client = lcf->client;
+ lcf->fopc->operation_id = lcf->operation_id;
+ lcf->fopc->type = OP_LINK_CONTROLLERS;
+ lcf->fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (lcf->gateway->controller,
+ lcf->operation_id,
+ &lcf->msg->header,
+ &lcf_forwarded_operation_reply_relay,
+ lcf);
+ lcf->fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &lcf_forwarded_operation_timeout,
+ lcf);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, lcf->fopc);
+ lcf->state = FINISHED;
+ break;
+ case FINISHED:
+ lcfq = lcfq_head;
+ GNUNET_assert (lcfq->lcf == lcf);
+ GNUNET_free (lcf->msg);
+ GNUNET_free (lcf);
+ GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
+ GNUNET_free (lcfq);
+ if (NULL != lcfq_head)
+ lcf_proc_task_id =
+ GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
+ }
+}
+
+
+/**
+ * Callback for event from slave controllers
+ *
+ * @param cls struct Slave *
+ * @param event information about the event
+ */
+static void
+slave_event_callback (void *cls,
+ const struct GNUNET_TESTBED_EventInformation *event)
+{
+ struct RegisteredHostContext *rhc;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct GNUNET_TESTBED_Operation *old_op;
+
+ /* We currently only get here when working on RegisteredHostContexts */
+ GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
+ rhc = event->details.operation_finished.op_cls;
+ GNUNET_assert (rhc->sub_op == event->details.operation_finished.operation);
+ switch (rhc->state)
+ {
+ case RHC_GET_CFG:
+ cfg = event->details.operation_finished.generic;
+ old_op = rhc->sub_op;
+ rhc->state = RHC_LINK;
+ rhc->sub_op =
+ GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
+ rhc->reg_host, rhc->host, cfg,
+ GNUNET_NO);
+ GNUNET_TESTBED_operation_done (old_op);
+ break;
+ case RHC_LINK:
+ LOG_DEBUG ("OL: Linking controllers successfull\n");
+ GNUNET_TESTBED_operation_done (rhc->sub_op);
+ rhc->sub_op = NULL;
+ rhc->state = RHC_OL_CONNECT;
+ GST_process_next_focc (rhc);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Callback to signal successfull startup of the controller process
+ *
+ * @param cls the handle to the slave whose status is to be found here
+ * @param cfg the configuration with which the controller has been started;
+ * NULL if status is not GNUNET_OK
+ * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
+ * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
+ */
+static void
+slave_status_callback (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
+ int status)
+{
+ struct Slave *slave = cls;
+ struct LinkControllersContext *lcc;
+
+ lcc = slave->lcc;
+ if (GNUNET_SYSERR == status)
+ {
+ slave->controller_proc = NULL;
+ GST_slave_list[slave->host_id] = NULL;
+ if (NULL != slave->cfg)
+ GNUNET_CONFIGURATION_destroy (slave->cfg);
+ GNUNET_free (slave);
+ slave = NULL;
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
+ GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
+ goto clean_lcc;
+ }
+ slave->controller =
+ GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
+ event_mask, &slave_event_callback,
+ slave);
+ if (NULL != slave->controller)
+ {
+ send_operation_success_msg (lcc->client, lcc->operation_id);
+ slave->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ }
+ else
+ {
+ GST_send_operation_fail_msg (lcc->client, lcc->operation_id,
+ "Could not connect to delegated controller");
+ GNUNET_TESTBED_controller_stop (slave->controller_proc);
+ GST_slave_list[slave->host_id] = NULL;
+ GNUNET_free (slave);
+ slave = NULL;
+ }
+
+clean_lcc:
+ if (NULL != lcc)
+ {
+ if (NULL != lcc->client)
+ {
+ GNUNET_SERVER_receive_done (lcc->client, GNUNET_OK);
+ GNUNET_SERVER_client_drop (lcc->client);
+ lcc->client = NULL;
+ }
+ GNUNET_free (lcc);
+ }
+ if (NULL != slave)
+ slave->lcc = NULL;
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_init (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_InitMessage *msg;
+ struct GNUNET_TESTBED_Host *host;
+ const char *controller_hostname;
+ uint16_t msize;
+
+ if (NULL != GST_context)
+ {
+ LOG_DEBUG ("We are being connected to laterally\n");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ msg = (const struct GNUNET_TESTBED_InitMessage *) message;
+ msize = ntohs (message->size);
+ if (msize <= sizeof (struct GNUNET_TESTBED_InitMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msize -= sizeof (struct GNUNET_TESTBED_InitMessage);
+ controller_hostname = (const char *) &msg[1];
+ if ('\0' != controller_hostname[msize - 1])
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GST_context = GNUNET_malloc (sizeof (struct Context));
+ GNUNET_SERVER_client_keep (client);
+ GST_context->client = client;
+ GST_context->host_id = ntohl (msg->host_id);
+ GST_context->master_ip = GNUNET_strdup (controller_hostname);
+ LOG_DEBUG ("Our IP: %s\n", GST_context->master_ip);
+ GST_context->system =
+ GNUNET_TESTING_system_create ("testbed", GST_context->master_ip,
+ hostname);
+ host =
+ GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
+ GST_context->master_ip, NULL, 0);
+ host_list_add (host);
+ LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_TESTBED_Host *host;
+ const struct GNUNET_TESTBED_AddHostMessage *msg;
+ struct GNUNET_TESTBED_HostConfirmedMessage *reply;
+ char *username;
+ char *hostname;
+ char *emsg;
+ uint32_t host_id;
+ uint16_t username_length;
+ uint16_t hostname_length;
+ uint16_t reply_size;
+ uint16_t msize;
+
+ msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
+ msize = ntohs (msg->header.size);
+ username = (char *) &msg[1];
+ username_length = ntohs (msg->user_name_length);
+ if (0 != username_length)
+ username_length++;
+ /* msg must contain hostname */
+ GNUNET_assert (msize >
+ (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
+ username_length + 1));
+ if (0 != username_length)
+ GNUNET_assert ('\0' == username[username_length - 1]);
+ hostname = username + username_length;
+ hostname_length =
+ msize - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
+ GNUNET_assert ('\0' == hostname[hostname_length - 1]);
+ GNUNET_assert (strlen (hostname) == hostname_length - 1);
+ host_id = ntohl (msg->host_id);
+ LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
+ LOG_DEBUG ("-------host id: %u\n", host_id);
+ LOG_DEBUG ("-------hostname: %s\n", hostname);
+ if (0 != username_length)
+ LOG_DEBUG ("-------username: %s\n", username);
+ else
+ {
+ LOG_DEBUG ("-------username: NULL\n");
+ username = NULL;
+ }
+ LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
+ host =
+ GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
+ ntohs (msg->ssh_port));
+ GNUNET_assert (NULL != host);
+ reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage);
+ if (GNUNET_OK != host_list_add (host))
+ {
+ /* We are unable to add a host */
+ emsg = "A host exists with given host-id";
+ LOG_DEBUG ("%s: %u", emsg, host_id);
+ GNUNET_TESTBED_host_destroy (host);
+ reply_size += strlen (emsg) + 1;
+ reply = GNUNET_malloc (reply_size);
+ memcpy (&reply[1], emsg, strlen (emsg) + 1);
+ }
+ else
+ {
+ LOG_DEBUG ("Added host %u at %u\n", host_id, GST_context->host_id);
+ reply = GNUNET_malloc (reply_size);
+ }
+ reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
+ reply->header.size = htons (reply_size);
+ reply->host_id = htonl (host_id);
+ GST_queue_message (client, &reply->header);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+int
+ss_exists_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct SharedService *queried_ss = cls;
+ struct SharedService *ss = value;
+
+ if (0 == strcmp (ss->name, queried_ss->name))
+ return GNUNET_NO;
+ else
+ return GNUNET_YES;
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_configure_shared_service (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
+ struct SharedService *ss;
+ char *service_name;
+ struct GNUNET_HashCode hash;
+ uint16_t msg_size;
+ uint16_t service_name_size;
+
+ msg = (const struct GNUNET_TESTBED_ConfigureSharedServiceMessage *) message;
+ msg_size = ntohs (message->size);
+ if (msg_size <= sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ service_name_size =
+ msg_size - sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage);
+ service_name = (char *) &msg[1];
+ if ('\0' != service_name[service_name_size - 1])
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ LOG_DEBUG ("Received service sharing request for %s, with %d peers\n",
+ service_name, ntohl (msg->num_peers));
+ if (ntohl (msg->host_id) != GST_context->host_id)
+ {
+ route_message (ntohl (msg->host_id), message);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ ss = GNUNET_malloc (sizeof (struct SharedService));
+ ss->name = strdup (service_name);
+ ss->num_shared = ntohl (msg->num_peers);
+ GNUNET_CRYPTO_hash (ss->name, service_name_size, &hash);
+ if (GNUNET_SYSERR ==
+ GNUNET_CONTAINER_multihashmap_get_multiple (ss_map, &hash,
+ &ss_exists_iterator, ss))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Service %s already configured as a shared service. "
+ "Ignoring service sharing request \n", ss->name);
+ GNUNET_free (ss->name);
+ GNUNET_free (ss);
+ return;
+ }
+ GNUNET_CONTAINER_multihashmap_put (ss_map, &hash, ss,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct LCFContextQueue *lcfq;
+ struct Route *route;
+ struct Route *new_route;
+ char *config;
+ uLongf dest_size;
+ size_t config_size;
+ uint32_t delegated_host_id;
+ uint32_t slave_host_id;
+ uint16_t msize;
+
+ if (NULL == GST_context)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msize = ntohs (message->size);
+ if (sizeof (struct GNUNET_TESTBED_ControllerLinkMessage) >= msize)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msg = (const struct GNUNET_TESTBED_ControllerLinkMessage *) message;
+ delegated_host_id = ntohl (msg->delegated_host_id);
+ if (delegated_host_id == GST_context->host_id)
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Trying to link ourselves\n");
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if ((delegated_host_id >= GST_host_list_size) ||
+ (NULL == GST_host_list[delegated_host_id]))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Delegated host %u not registered with us\n", delegated_host_id);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ slave_host_id = ntohl (msg->slave_host_id);
+ if ((slave_host_id >= GST_host_list_size) ||
+ (NULL == GST_host_list[slave_host_id]))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
+ slave_host_id);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (slave_host_id == delegated_host_id)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Slave and delegated host are same\n");
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ if (slave_host_id == GST_context->host_id) /* Link from us */
+ {
+ struct Slave *slave;
+ struct LinkControllersContext *lcc;
+
+ msize -= sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
+ config_size = ntohs (msg->config_size);
+ if ((delegated_host_id < GST_slave_list_size) && (NULL != GST_slave_list[delegated_host_id])) /* We have already added */
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
+ delegated_host_id);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ config = GNUNET_malloc (config_size);
+ dest_size = (uLongf) config_size;
+ if (Z_OK !=
+ uncompress ((Bytef *) config, &dest_size, (const Bytef *) &msg[1],
+ (uLong) msize))
+ {
+ GNUNET_break (0); /* Compression error */
+ GNUNET_free (config);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (config_size != dest_size)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Uncompressed config size mismatch\n");
+ GNUNET_free (config);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ cfg = GNUNET_CONFIGURATION_create (); /* Free here or in lcfcontext */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
+ {
+ GNUNET_break (0); /* Configuration parsing error */
+ GNUNET_free (config);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_free (config);
+ if ((delegated_host_id < GST_slave_list_size) &&
+ (NULL != GST_slave_list[delegated_host_id]))
+ {
+ GNUNET_break (0); /* Configuration parsing error */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ slave = GNUNET_malloc (sizeof (struct Slave));
+ slave->host_id = delegated_host_id;
+ slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100, GNUNET_NO);
+ slave_list_add (slave);
+ if (1 != msg->is_subordinate)
+ {
+ slave->controller =
+ GNUNET_TESTBED_controller_connect (cfg, GST_host_list[slave->host_id],
+ event_mask, &slave_event_callback,
+ slave);
+ slave->cfg = cfg;
+ if (NULL != slave->controller)
+ send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
+ else
+ GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+ "Could not connect to delegated controller");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ lcc = GNUNET_malloc (sizeof (struct LinkControllersContext));
+ lcc->operation_id = GNUNET_ntohll (msg->operation_id);
+ GNUNET_SERVER_client_keep (client);
+ lcc->client = client;
+ slave->lcc = lcc;
+ slave->controller_proc =
+ GNUNET_TESTBED_controller_start (GST_context->master_ip,
+ GST_host_list[slave->host_id], cfg,
+ &slave_status_callback, slave);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ new_route = GNUNET_malloc (sizeof (struct Route));
+ new_route->dest = delegated_host_id;
+ new_route->thru = GST_context->host_id;
+ route_list_add (new_route);
+ return;
+ }
+
+ /* Route the request */
+ if (slave_host_id >= route_list_size)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "No route towards slave host");
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
+ lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
+ lcfq->lcf->delegated_host_id = delegated_host_id;
+ lcfq->lcf->slave_host_id = slave_host_id;
+ route = GST_find_dest_route (slave_host_id);
+ GNUNET_assert (NULL != route); /* because we add routes carefully */
+ GNUNET_assert (route->dest < GST_slave_list_size);
+ GNUNET_assert (NULL != GST_slave_list[route->dest]);
+ lcfq->lcf->state = INIT;
+ lcfq->lcf->operation_id = GNUNET_ntohll (msg->operation_id);
+ lcfq->lcf->gateway = GST_slave_list[route->dest];
+ lcfq->lcf->msg = GNUNET_malloc (msize);
+ (void) memcpy (lcfq->lcf->msg, msg, msize);
+ GNUNET_SERVER_client_keep (client);
+ lcfq->lcf->client = client;
+ if (NULL == lcfq_head)
+ {
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
+ GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
+ lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq->lcf);
+ }
+ else
+ GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
+ /* FIXME: Adding a new route should happen after the controllers are linked
+ * successfully */
+ if (1 != msg->is_subordinate)
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ if ((delegated_host_id < route_list_size) &&
+ (NULL != route_list[delegated_host_id]))
+ {
+ GNUNET_break_op (0); /* Are you trying to link delegated host twice
+ * with is subordinate flag set to GNUNET_YES? */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ new_route = GNUNET_malloc (sizeof (struct Route));
+ new_route->dest = delegated_host_id;
+ new_route->thru = route->dest;
+ route_list_add (new_route);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * The task to be executed if the forwarded peer create operation has been
+ * timed out
+ *
+ * @param cls the FowardedOperationContext
+ * @param tc the TaskContext from the scheduler
+ */
+static void
+peer_create_forward_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ForwardedOperationContext *fopc = cls;
+
+ GNUNET_free (fopc->cls);
+ GST_forwarded_operation_timeout (fopc, tc);
+}
+
+
+/**
+ * Callback to be called when forwarded peer create operation is successfull. We
+ * have to relay the reply msg back to the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the peer create success message
+ */
+static void
+peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct ForwardedOperationContext *fopc = cls;
+ struct Peer *remote_peer;
+
+ if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
+ {
+ GNUNET_assert (NULL != fopc->cls);
+ remote_peer = fopc->cls;
+ peer_list_add (remote_peer);
+ }
+ GST_forwarded_operation_reply_relay (fopc, msg);
+}
+
+
+/**
+ * Function to destroy a peer
+ *
+ * @param peer the peer structure to destroy
+ */
+void
+GST_destroy_peer (struct Peer *peer)
+{
+ GNUNET_break (0 == peer->reference_cnt);
+ if (GNUNET_YES == peer->is_remote)
+ {
+ peer_list_remove (peer);
+ GNUNET_free (peer);
+ return;
+ }
+ if (GNUNET_YES == peer->details.local.is_running)
+ {
+ GNUNET_TESTING_peer_stop (peer->details.local.peer);
+ peer->details.local.is_running = GNUNET_NO;
+ }
+ GNUNET_TESTING_peer_destroy (peer->details.local.peer);
+ GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
+ peer_list_remove (peer);
+ GNUNET_free (peer);
+}
+
+
+/**
+ * Callback to be called when forwarded peer destroy operation is successfull. We
+ * have to relay the reply msg back to the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the peer create success message
+ */
+static void
+peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct ForwardedOperationContext *fopc = cls;
+ struct Peer *remote_peer;
+
+ if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
+ ntohs (msg->type))
+ {
+ remote_peer = fopc->cls;
+ GNUNET_assert (NULL != remote_peer);
+ remote_peer->destroy_flag = GNUNET_YES;
+ if (0 == remote_peer->reference_cnt)
+ GST_destroy_peer (remote_peer);
+ }
+ GST_forwarded_operation_reply_relay (fopc, msg);
+}
+
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_PeerCreateMessage *msg;
+ struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct ForwardedOperationContext *fo_ctxt;
+ struct Route *route;
+ struct Peer *peer;
+ char *config;
+ size_t dest_size;
+ int ret;
+ uint32_t config_size;
+ uint32_t host_id;
+ uint32_t peer_id;
+ uint16_t msize;
+
+
+ msize = ntohs (message->size);
+ if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
+ {
+ GNUNET_break (0); /* We need configuration */
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
+ host_id = ntohl (msg->host_id);
+ peer_id = ntohl (msg->peer_id);
+ if (UINT32_MAX == peer_id)
+ {
+ GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+ "Cannot create peer with given ID");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ if (host_id == GST_context->host_id)
+ {
+ char *emsg;
+
+ /* We are responsible for this peer */
+ msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
+ config_size = ntohl (msg->config_size);
+ config = GNUNET_malloc (config_size);
+ dest_size = config_size;
+ if (Z_OK !=
+ (ret =
+ uncompress ((Bytef *) config, (uLongf *) & dest_size,
+ (const Bytef *) &msg[1], (uLong) msize)))
+ {
+ GNUNET_break (0); /* uncompression error */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (config_size != dest_size)
+ {
+ GNUNET_break (0); /* Uncompressed config size mismatch */
+ GNUNET_free (config);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
+ {
+ GNUNET_break (0); /* Configuration parsing error */
+ GNUNET_free (config);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_free (config);
+ GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
+ (unsigned long long) peer_id);
+ peer = GNUNET_malloc (sizeof (struct Peer));
+ peer->is_remote = GNUNET_NO;
+ peer->details.local.cfg = cfg;
+ peer->id = peer_id;
+ LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
+ peer->details.local.peer =
+ GNUNET_TESTING_peer_configure (GST_context->system,
+ peer->details.local.cfg, peer->id,
+ NULL /* Peer id */ ,
+ &emsg);
+ if (NULL == peer->details.local.peer)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
+ GNUNET_free (emsg);
+ GNUNET_free (peer);
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ peer->details.local.is_running = GNUNET_NO;
+ peer_list_add (peer);
+ reply =
+ GNUNET_malloc (sizeof
+ (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
+ reply->header.size =
+ htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
+ reply->header.type =
+ htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
+ reply->peer_id = msg->peer_id;
+ reply->operation_id = msg->operation_id;
+ GST_queue_message (client, &reply->header);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ /* Forward peer create request */
+ route = GST_find_dest_route (host_id);
+ if (NULL == route)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ peer = GNUNET_malloc (sizeof (struct Peer));
+ peer->is_remote = GNUNET_YES;
+ peer->id = peer_id;
+ peer->details.remote.slave = GST_slave_list[route->dest];
+ peer->details.remote.remote_host_id = host_id;
+ fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fo_ctxt->client = client;
+ fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
+ fo_ctxt->cls = peer; //GST_slave_list[route->dest]->controller;
+ fo_ctxt->type = OP_PEER_CREATE;
+ fo_ctxt->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
+ [route->dest]->controller,
+ fo_ctxt->operation_id,
+ &msg->header,
+ peer_create_success_cb, fo_ctxt);
+ fo_ctxt->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &peer_create_forward_timeout,
+ fo_ctxt);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
+ struct ForwardedOperationContext *fopc;
+ struct Peer *peer;
+ uint32_t peer_id;
+
+ msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
+ peer_id = ntohl (msg->peer_id);
+ LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
+ peer_id, GNUNET_ntohll (msg->operation_id));
+ if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id]))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Asked to destroy a non existent peer with id: %u\n", peer_id);
+ GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+ "Peer doesn't exist");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ peer = GST_peer_list[peer_id];
+ if (GNUNET_YES == peer->is_remote)
+ {
+ /* Forward the destory message to sub controller */
+ fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fopc->client = client;
+ fopc->cls = peer;
+ fopc->type = OP_PEER_DESTROY;
+ fopc->operation_id = GNUNET_ntohll (msg->operation_id);
+ fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
+ slave->controller,
+ fopc->operation_id, &msg->header,
+ &peer_destroy_success_cb, fopc);
+ fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &GST_forwarded_operation_timeout,
+ fopc);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ peer->destroy_flag = GNUNET_YES;
+ if (0 == peer->reference_cnt)
+ GST_destroy_peer (peer);
+ else
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Delaying peer destroy as peer is currently in use\n");
+ send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_PeerStartMessage *msg;
+ struct GNUNET_TESTBED_PeerEventMessage *reply;
+ struct ForwardedOperationContext *fopc;
+ struct Peer *peer;
+ uint32_t peer_id;
+
+ msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
+ peer_id = ntohl (msg->peer_id);
+ if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
+ {
+ GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Asked to start a non existent peer with id: %u\n", peer_id);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ peer = GST_peer_list[peer_id];
+ if (GNUNET_YES == peer->is_remote)
+ {
+ fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fopc->client = client;
+ fopc->operation_id = GNUNET_ntohll (msg->operation_id);
+ fopc->type = OP_PEER_START;
+ fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
+ slave->controller,
+ fopc->operation_id, &msg->header,
+ &GST_forwarded_operation_reply_relay,
+ fopc);
+ fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &GST_forwarded_operation_timeout,
+ fopc);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
+ {
+ GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+ "Failed to start");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ peer->details.local.is_running = GNUNET_YES;
+ reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
+ reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
+ reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
+ reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
+ reply->host_id = htonl (GST_context->host_id);
+ reply->peer_id = msg->peer_id;
+ reply->operation_id = msg->operation_id;
+ GST_queue_message (client, &reply->header);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_PeerStopMessage *msg;
+ struct GNUNET_TESTBED_PeerEventMessage *reply;
+ struct ForwardedOperationContext *fopc;
+ struct Peer *peer;
+ uint32_t peer_id;
+
+ msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
+ peer_id = ntohl (msg->peer_id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
+ if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
+ {
+ GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+ "Peer not found");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ peer = GST_peer_list[peer_id];
+ if (GNUNET_YES == peer->is_remote)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
+ peer_id);
+ fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fopc->client = client;
+ fopc->operation_id = GNUNET_ntohll (msg->operation_id);
+ fopc->type = OP_PEER_STOP;
+ fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
+ slave->controller,
+ fopc->operation_id, &msg->header,
+ &GST_forwarded_operation_reply_relay,
+ fopc);
+ fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &GST_forwarded_operation_timeout,
+ fopc);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer->details.local.peer))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
+ GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+ "Peer not running");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
+ peer->details.local.is_running = GNUNET_NO;
+ reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
+ reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
+ reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
+ reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
+ reply->host_id = htonl (GST_context->host_id);
+ reply->peer_id = msg->peer_id;
+ reply->operation_id = msg->operation_id;
+ GST_queue_message (client, &reply->header);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
+ struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
+ struct Peer *peer;
+ char *config;
+ char *xconfig;
+ size_t c_size;
+ size_t xc_size;
+ uint32_t peer_id;
+ uint16_t msize;
+
+ msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
+ peer_id = ntohl (msg->peer_id);
+ if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
+ {
+ GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
+ "Peer not found");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ peer = GST_peer_list[peer_id];
+ if (GNUNET_YES == peer->is_remote)
+ {
+ struct ForwardedOperationContext *fopc;
+
+ LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
+ fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fopc->client = client;
+ fopc->operation_id = GNUNET_ntohll (msg->operation_id);
+ fopc->type = OP_PEER_INFO;
+ fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
+ slave->controller,
+ fopc->operation_id, &msg->header,
+ &GST_forwarded_operation_reply_relay,
+ fopc);
+ fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &GST_forwarded_operation_timeout,
+ fopc);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
+ config =
+ GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
+ &c_size);
+ xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
+ GNUNET_free (config);
+ msize =
+ xc_size +
+ sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
+ reply = GNUNET_realloc (xconfig, msize);
+ (void) memmove (&reply[1], reply, xc_size);
+ reply->header.size = htons (msize);
+ reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
+ reply->peer_id = msg->peer_id;
+ reply->operation_id = msg->operation_id;
+ GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
+ &reply->peer_identity);
+ reply->config_size = htons ((uint16_t) c_size);
+ GST_queue_message (client, &reply->header);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
+ struct Slave *slave;
+ struct GNUNET_TESTBED_SlaveConfiguration *reply;
+ char *config;
+ char *xconfig;
+ size_t config_size;
+ size_t xconfig_size;
+ size_t reply_size;
+ uint64_t op_id;
+ uint32_t slave_id;
+
+ msg = (struct GNUNET_TESTBED_SlaveGetConfigurationMessage *) message;
+ slave_id = ntohl (msg->slave_id);
+ op_id = GNUNET_ntohll (msg->operation_id);
+ if ((GST_slave_list_size <= slave_id) || (NULL == GST_slave_list[slave_id]))
+ {
+ /* FIXME: Add forwardings for this type of message here.. */
+ GST_send_operation_fail_msg (client, op_id, "Slave not found");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ slave = GST_slave_list[slave_id];
+ if (NULL == slave->cfg)
+ {
+ GST_send_operation_fail_msg (client, op_id,
+ "Configuration not found (slave not started by me)");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ config = GNUNET_CONFIGURATION_serialize (slave->cfg, &config_size);
+ xconfig_size =
+ GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
+ GNUNET_free (config);
+ reply_size = xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
+ GNUNET_break (reply_size <= UINT16_MAX);
+ GNUNET_break (config_size <= UINT16_MAX);
+ reply = GNUNET_realloc (xconfig, reply_size);
+ (void) memmove (&reply[1], reply, xconfig_size);
+ reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
+ reply->header.size = htons ((uint16_t) reply_size);
+ reply->slave_id = msg->slave_id;
+ reply->operation_id = msg->operation_id;
+ reply->config_size = htons ((uint16_t) config_size);
+ GST_queue_message (client, &reply->header);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+ss_map_free_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct SharedService *ss = value;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (ss_map, key, value));
+ GNUNET_free (ss->name);
+ GNUNET_free (ss);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Iterator for freeing hash map entries in a slave's reghost_map
+ *
+ * @param cls handle to the slave
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+reghost_free_iterator (void *cls, const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct Slave *slave = cls;
+ struct RegisteredHostContext *rhc = value;
+ struct ForwardedOverlayConnectContext *focc;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
+ value));
+ while (NULL != (focc = rhc->focc_dll_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
+ GST_cleanup_focc (focc);
+ }
+ if (NULL != rhc->sub_op)
+ GNUNET_TESTBED_operation_done (rhc->sub_op);
+ if (NULL != rhc->client)
+ GNUNET_SERVER_client_drop (rhc->client);
+ GNUNET_free (value);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Task to clean up and shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the TaskContext from scheduler
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct LCFContextQueue *lcfq;
+ struct ForwardedOperationContext *fopc;
+ struct MessageQueue *mq_entry;
+ uint32_t id;
+
+ shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
+ (void) GNUNET_CONTAINER_multihashmap_iterate (ss_map, &ss_map_free_iterator,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (ss_map);
+ /* cleanup any remaining forwarded operations */
+ while (NULL != (fopc = fopcq_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fopc);
+ GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
+ if (GNUNET_SCHEDULER_NO_TASK != fopc->timeout_task)
+ GNUNET_SCHEDULER_cancel (fopc->timeout_task);
+ GNUNET_SERVER_client_drop (fopc->client);
+ switch (fopc->type)
+ {
+ case OP_PEER_CREATE:
+ GNUNET_free (fopc->cls);
+ break;
+ case OP_PEER_START:
+ case OP_PEER_STOP:
+ case OP_PEER_DESTROY:
+ case OP_PEER_INFO:
+ case OP_OVERLAY_CONNECT:
+ case OP_LINK_CONTROLLERS:
+ case OP_GET_SLAVE_CONFIG:
+ break;
+ case OP_FORWARDED:
+ GNUNET_assert (0);
+ };
+ GNUNET_free (fopc);
+ }
+ if (NULL != lcfq_head)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
+ {
+ GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
+ lcf_proc_task_id = GNUNET_SCHEDULER_NO_TASK;
+ }
+ }
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == lcf_proc_task_id);
+ for (lcfq = lcfq_head; NULL != lcfq; lcfq = lcfq_head)
+ {
+ GNUNET_free (lcfq->lcf->msg);
+ GNUNET_free (lcfq->lcf);
+ GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
+ GNUNET_free (lcfq);
+ }
+ GST_free_occq ();
+ GST_free_roccq ();
+ /* Clear peer list */
+ for (id = 0; id < GST_peer_list_size; id++)
+ if (NULL != GST_peer_list[id])
+ {
+ /* If destroy flag is set it means that this peer should have been
+ * destroyed by a context which we destroy before */
+ GNUNET_break (GNUNET_NO == GST_peer_list[id]->destroy_flag);
+ /* counter should be zero as we free all contexts before */
+ GNUNET_break (0 == GST_peer_list[id]->reference_cnt);
+ if ((GNUNET_NO == GST_peer_list[id]->is_remote) &&
+ (GNUNET_YES == GST_peer_list[id]->details.local.is_running))
+ GNUNET_TESTING_peer_kill (GST_peer_list[id]->details.local.peer);
+ }
+ for (id = 0; id < GST_peer_list_size; id++)
+ if (NULL != GST_peer_list[id])
+ {
+ if (GNUNET_NO == GST_peer_list[id]->is_remote)
+ {
+ if (GNUNET_YES == GST_peer_list[id]->details.local.is_running)
+ GNUNET_TESTING_peer_wait (GST_peer_list[id]->details.local.peer);
+ GNUNET_TESTING_peer_destroy (GST_peer_list[id]->details.local.peer);
+ GNUNET_CONFIGURATION_destroy (GST_peer_list[id]->details.local.cfg);
+ }
+ GNUNET_free (GST_peer_list[id]);
+ }
+ GNUNET_free_non_null (GST_peer_list);
+ /* Clear host list */
+ for (id = 0; id < GST_host_list_size; id++)
+ if (NULL != GST_host_list[id])
+ GNUNET_TESTBED_host_destroy (GST_host_list[id]);
+ GNUNET_free_non_null (GST_host_list);
+ /* Clear route list */
+ for (id = 0; id < route_list_size; id++)
+ if (NULL != route_list[id])
+ GNUNET_free (route_list[id]);
+ GNUNET_free_non_null (route_list);
+ /* Clear GST_slave_list */
+ for (id = 0; id < GST_slave_list_size; id++)
+ if (NULL != GST_slave_list[id])
+ {
+ struct HostRegistration *hr_entry;
+
+ while (NULL != (hr_entry = GST_slave_list[id]->hr_dll_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (GST_slave_list[id]->hr_dll_head,
+ GST_slave_list[id]->hr_dll_tail, hr_entry);
+ GNUNET_free (hr_entry);
+ }
+ if (NULL != GST_slave_list[id]->rhandle)
+ GNUNET_TESTBED_cancel_registration (GST_slave_list[id]->rhandle);
+ (void)
+ GNUNET_CONTAINER_multihashmap_iterate (GST_slave_list
+ [id]->reghost_map,
+ reghost_free_iterator,
+ GST_slave_list[id]);
+ GNUNET_CONTAINER_multihashmap_destroy (GST_slave_list[id]->reghost_map);
+ if (NULL != GST_slave_list[id]->cfg)
+ GNUNET_CONFIGURATION_destroy (GST_slave_list[id]->cfg);
+ if (NULL != GST_slave_list[id]->controller)
+ GNUNET_TESTBED_controller_disconnect (GST_slave_list[id]->controller);
+ if (NULL != GST_slave_list[id]->controller_proc)
+ GNUNET_TESTBED_controller_stop (GST_slave_list[id]->controller_proc);
+ GNUNET_free (GST_slave_list[id]);
+ }
+ GNUNET_free_non_null (GST_slave_list);
+ if (NULL != GST_context)
+ {
+ GNUNET_free_non_null (GST_context->master_ip);
+ if (NULL != GST_context->system)
+ GNUNET_TESTING_system_destroy (GST_context->system, GNUNET_YES);
+ GNUNET_SERVER_client_drop (GST_context->client);
+ GNUNET_free (GST_context);
+ GST_context = NULL;
+ }
+ if (NULL != transmit_handle)
+ GNUNET_SERVER_notify_transmit_ready_cancel (transmit_handle);
+ while (NULL != (mq_entry = mq_head))
+ {
+ GNUNET_free (mq_entry->msg);
+ GNUNET_SERVER_client_drop (mq_entry->client);
+ GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
+ GNUNET_free (mq_entry);
+ }
+ GNUNET_free_non_null (hostname);
+ GNUNET_CONFIGURATION_destroy (our_config);
+ /* Free hello cache */
+ GST_cache_clear ();
+ GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
+ GST_opq_openfds = NULL;
+}
+
+
+/**
+ * Callback for client disconnect
+ *
+ * @param cls NULL
+ * @param client the client which has disconnected
+ */
+static void
+client_disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ if (NULL == GST_context)
+ return;
+ if (client == GST_context->client)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Master client disconnected\n");
+ /* should not be needed as we're terminated by failure to read
+ * from stdin, but if stdin fails for some reason, this shouldn't
+ * hurt for now --- might need to revise this later if we ever
+ * decide that master connections might be temporarily down
+ * for some reason */
+ //GNUNET_SCHEDULER_shutdown ();
+ }
+}
+
+
+/**
+ * Testbed setup
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+static void
+testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
+ {&handle_init, NULL, GNUNET_MESSAGE_TYPE_TESTBED_INIT, 0},
+ {&handle_add_host, NULL, GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST, 0},
+ {&handle_configure_shared_service, NULL,
+ GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
+ {&handle_link_controllers, NULL,
+ GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
+ {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
+ {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
+ sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
+ {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
+ sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
+ {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
+ sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
+ {&handle_peer_get_config, NULL,
+ GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
+ sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
+ {&GST_handle_overlay_connect, NULL,
+ GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
+ sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
+ {&GST_handle_remote_overlay_connect, NULL,
+ GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
+ {handle_slave_get_config, NULL,
+ GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
+ sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
+ {NULL}
+ };
+ char *logfile;
+ unsigned long long num;
+
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
+ &logfile))
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_log_setup ("testbed", "DEBUG", logfile));
+ GNUNET_free (logfile);
+ }
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
+ "CACHE_SIZE", &num));
+ GST_cache_init ((unsigned int) num);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (cfg, "TESTBED",
+ "MAX_OPEN_FDS", &num));
+ GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ ((unsigned int) num);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
+ "HOSTNAME", &hostname));
+ our_config = GNUNET_CONFIGURATION_dup (cfg);
+ GNUNET_SERVER_add_handlers (server, message_handlers);
+ GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
+ ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
+ shutdown_task_id =
+ GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_PRIORITY_IDLE,
+ &shutdown_task, NULL);
+ LOG_DEBUG ("Testbed startup complete\n");
+ event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
+}
+
+
+/**
+ * The starting point of execution
+ */
+int
+main (int argc, char *const *argv)
+{
+ //sleep (15); /* Debugging */
+ return (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
+ &testbed_run, NULL)) ? 0 : 1;
+}
+
+/* end of gnunet-service-testbed.c */
diff --git a/src/testbed/gnunet-service-testbed.h b/src/testbed/gnunet-service-testbed.h
new file mode 100644
index 0000000..ebf3c66
--- /dev/null
+++ b/src/testbed/gnunet-service-testbed.h
@@ -0,0 +1,911 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 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 testbed/gnunet-service-testbed.h
+ * @brief data structures shared amongst components of TESTBED service
+ * @author Sree Harsha Totakura
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_core_service.h"
+
+#include "testbed.h"
+#include "testbed_api.h"
+#include "testbed_api_operations.h"
+#include "testbed_api_hosts.h"
+#include "gnunet_testing_lib.h"
+
+
+/**
+ * Generic logging
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Debug logging
+ */
+#define LOG_DEBUG(...) \
+ LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
+
+/**
+ * By how much should the arrays lists grow
+ */
+#define LIST_GROW_STEP 10
+
+/**
+ * Default timeout for operations which may take some time
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15)
+
+
+/**
+ * A routing entry
+ */
+struct Route
+{
+ /**
+ * destination host
+ */
+ uint32_t dest;
+
+ /**
+ * The destination host is reachable thru
+ */
+ uint32_t thru;
+};
+
+
+/**
+ * Context information for operations forwarded to subcontrollers
+ */
+struct ForwardedOperationContext
+{
+ /**
+ * The next pointer for DLL
+ */
+ struct ForwardedOperationContext *next;
+
+ /**
+ * The prev pointer for DLL
+ */
+ struct ForwardedOperationContext *prev;
+
+ /**
+ * The generated operation context
+ */
+ struct OperationContext *opc;
+
+ /**
+ * The client to which we have to reply
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Closure pointer
+ */
+ void *cls;
+
+ /**
+ * Task ID for the timeout task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * The id of the operation that has been forwarded
+ */
+ uint64_t operation_id;
+
+ /**
+ * The type of the operation which is forwarded
+ */
+ enum OperationType type;
+
+};
+
+
+/**
+ * A DLL of host registrations to be made
+ */
+struct HostRegistration
+{
+ /**
+ * next registration in the DLL
+ */
+ struct HostRegistration *next;
+
+ /**
+ * previous registration in the DLL
+ */
+ struct HostRegistration *prev;
+
+ /**
+ * The callback to call after this registration's status is available
+ */
+ GNUNET_TESTBED_HostRegistrationCompletion cb;
+
+ /**
+ * The closure for the above callback
+ */
+ void *cb_cls;
+
+ /**
+ * The host that has to be registered
+ */
+ struct GNUNET_TESTBED_Host *host;
+};
+
+
+/**
+ * Context information used while linking controllers
+ */
+struct LinkControllersContext
+{
+ /**
+ * The client which initiated the link controller operation
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * The ID of the operation
+ */
+ uint64_t operation_id;
+
+};
+
+
+/**
+ * Structure representing a connected(directly-linked) controller
+ */
+struct Slave
+{
+ /**
+ * The controller process handle if we had started the controller
+ */
+ struct GNUNET_TESTBED_ControllerProc *controller_proc;
+
+ /**
+ * The controller handle
+ */
+ struct GNUNET_TESTBED_Controller *controller;
+
+ /**
+ * The configuration of the slave. Cannot be NULL
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * handle to lcc which is associated with this slave startup. Should be set to
+ * NULL when the slave has successfully started up
+ */
+ struct LinkControllersContext *lcc;
+
+ /**
+ * Head of the host registration DLL
+ */
+ struct HostRegistration *hr_dll_head;
+
+ /**
+ * Tail of the host registration DLL
+ */
+ struct HostRegistration *hr_dll_tail;
+
+ /**
+ * The current host registration handle
+ */
+ struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
+
+ /**
+ * Hashmap to hold Registered host contexts
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *reghost_map;
+
+ /**
+ * The id of the host this controller is running on
+ */
+ uint32_t host_id;
+
+};
+
+
+/**
+ * A peer
+ */
+
+struct Peer
+{
+
+ union
+ {
+ struct
+ {
+ /**
+ * The peer handle from testing API
+ */
+ struct GNUNET_TESTING_Peer *peer;
+
+ /**
+ * The modified (by GNUNET_TESTING_peer_configure) configuration this
+ * peer is configured with
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Is the peer running
+ */
+ int is_running;
+
+ } local;
+
+ struct
+ {
+ /**
+ * The slave this peer is started through
+ */
+ struct Slave *slave;
+
+ /**
+ * The id of the remote host this peer is running on
+ */
+ uint32_t remote_host_id;
+
+ } remote;
+
+ } details;
+
+ /**
+ * Is this peer locally created?
+ */
+ int is_remote;
+
+ /**
+ * Our local reference id for this peer
+ */
+ uint32_t id;
+
+ /**
+ * References to peers are using in forwarded overlay contexts and remote
+ * overlay connect contexts. A peer can only be destroyed after all such
+ * contexts are destroyed. For this, we maintain a reference counter. When we
+ * use a peer in any such context, we increment this counter. We decrement it
+ * when we are destroying these contexts
+ */
+ uint32_t reference_cnt;
+
+ /**
+ * While destroying a peer, due to the fact that there could be references to
+ * this peer, we delay the peer destroy to a further time. We do this by using
+ * this flag to destroy the peer while destroying a context in which this peer
+ * has been used. When the flag is set to 1 and reference_cnt = 0 we destroy
+ * the peer
+ */
+ uint32_t destroy_flag;
+
+};
+
+
+/**
+ * The main context information associated with the client which started us
+ */
+struct Context
+{
+ /**
+ * The client handle associated with this context
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * The network address of the master controller
+ */
+ char *master_ip;
+
+ /**
+ * The TESTING system handle for starting peers locally
+ */
+ struct GNUNET_TESTING_System *system;
+
+ /**
+ * Our host id according to this context
+ */
+ uint32_t host_id;
+};
+
+
+/**
+ * The structure for identifying a shared service
+ */
+struct SharedService
+{
+ /**
+ * The name of the shared service
+ */
+ char *name;
+
+ /**
+ * Number of shared peers per instance of the shared service
+ */
+ uint32_t num_shared;
+
+ /**
+ * Number of peers currently sharing the service
+ */
+ uint32_t num_sharing;
+};
+
+
+/**
+ * Context information to used during operations which forward the overlay
+ * connect message
+ */
+struct ForwardedOverlayConnectContext
+{
+ /**
+ * next ForwardedOverlayConnectContext in the DLL
+ */
+ struct ForwardedOverlayConnectContext *next;
+
+ /**
+ * previous ForwardedOverlayConnectContext in the DLL
+ */
+ struct ForwardedOverlayConnectContext *prev;
+
+ /**
+ * A copy of the original overlay connect message
+ */
+ struct GNUNET_MessageHeader *orig_msg;
+
+ /**
+ * The id of the operation which created this context information
+ */
+ uint64_t operation_id;
+
+ /**
+ * the id of peer 1
+ */
+ uint32_t peer1;
+
+ /**
+ * The id of peer 2
+ */
+ uint32_t peer2;
+
+ /**
+ * Id of the host where peer2 is running
+ */
+ uint32_t peer2_host_id;
+};
+
+
+/**
+ * This context information will be created for each host that is registered at
+ * slave controllers during overlay connects.
+ */
+struct RegisteredHostContext
+{
+ /**
+ * The host which is being registered
+ */
+ struct GNUNET_TESTBED_Host *reg_host;
+
+ /**
+ * The host of the controller which has to connect to the above rhost
+ */
+ struct GNUNET_TESTBED_Host *host;
+
+ /**
+ * The gateway to which this operation is forwarded to
+ */
+ struct Slave *gateway;
+
+ /**
+ * The gateway through which peer2's controller can be reached
+ */
+ struct Slave *gateway2;
+
+ /**
+ * Handle for sub-operations
+ */
+ struct GNUNET_TESTBED_Operation *sub_op;
+
+ /**
+ * The client which initiated the link controller operation
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Head of the ForwardedOverlayConnectContext DLL
+ */
+ struct ForwardedOverlayConnectContext *focc_dll_head;
+
+ /**
+ * Tail of the ForwardedOverlayConnectContext DLL
+ */
+ struct ForwardedOverlayConnectContext *focc_dll_tail;
+
+ /**
+ * Enumeration of states for this context
+ */
+ enum RHCState
+ {
+
+ /**
+ * The initial state
+ */
+ RHC_INIT = 0,
+
+ /**
+ * State where we attempt to get peer2's controller configuration
+ */
+ RHC_GET_CFG,
+
+ /**
+ * State where we attempt to link the controller of peer 1 to the controller
+ * of peer2
+ */
+ RHC_LINK,
+
+ /**
+ * State where we attempt to do the overlay connection again
+ */
+ RHC_OL_CONNECT
+ } state;
+
+};
+
+
+/**
+ * States of LCFContext
+ */
+enum LCFContextState
+{
+ /**
+ * The Context has been initialized; Nothing has been done on it
+ */
+ INIT,
+
+ /**
+ * Delegated host has been registered at the forwarding controller
+ */
+ DELEGATED_HOST_REGISTERED,
+
+ /**
+ * The slave host has been registred at the forwarding controller
+ */
+ SLAVE_HOST_REGISTERED,
+
+ /**
+ * The context has been finished (may have error)
+ */
+ FINISHED
+};
+
+
+/**
+ * Link controllers request forwarding context
+ */
+struct LCFContext
+{
+ /**
+ * The gateway which will pass the link message to delegated host
+ */
+ struct Slave *gateway;
+
+ /**
+ * The controller link message that has to be forwarded to
+ */
+ struct GNUNET_TESTBED_ControllerLinkMessage *msg;
+
+ /**
+ * The client which has asked to perform this operation
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Handle for operations which are forwarded while linking controllers
+ */
+ struct ForwardedOperationContext *fopc;
+
+ /**
+ * The id of the operation which created this context
+ */
+ uint64_t operation_id;
+
+ /**
+ * The state of this context
+ */
+ enum LCFContextState state;
+
+ /**
+ * The delegated host
+ */
+ uint32_t delegated_host_id;
+
+ /**
+ * The slave host
+ */
+ uint32_t slave_host_id;
+
+};
+
+
+/**
+ * Structure of a queue entry in LCFContext request queue
+ */
+struct LCFContextQueue
+{
+ /**
+ * The LCFContext
+ */
+ struct LCFContext *lcf;
+
+ /**
+ * Head prt for DLL
+ */
+ struct LCFContextQueue *next;
+
+ /**
+ * Tail ptr for DLL
+ */
+ struct LCFContextQueue *prev;
+};
+
+/**
+ * Our configuration
+ */
+struct GNUNET_CONFIGURATION_Handle *our_config;
+
+/**
+ * The master context; generated with the first INIT message
+ */
+extern struct Context *GST_context;
+
+/**
+ * DLL head for forwarded operation contexts
+ */
+extern struct ForwardedOperationContext *fopcq_head;
+
+/**
+ * DLL tail for forwarded operation contexts
+ */
+extern struct ForwardedOperationContext *fopcq_tail;
+
+/**
+ * A list of peers we know about
+ */
+extern struct Peer **GST_peer_list;
+
+/**
+ * Array of hosts
+ */
+extern struct GNUNET_TESTBED_Host **GST_host_list;
+
+/**
+ * A list of directly linked neighbours
+ */
+extern struct Slave **GST_slave_list;
+
+/**
+ * Operation queue for open file descriptors
+ */
+extern struct OperationQueue *GST_opq_openfds;
+
+/**
+ * The size of the peer list
+ */
+extern unsigned int GST_peer_list_size;
+
+/**
+ * The size of the host list
+ */
+extern unsigned int GST_host_list_size;
+
+/**
+ * The size of directly linked neighbours list
+ */
+extern unsigned int GST_slave_list_size;
+
+
+/**
+ * Queues a message in send queue for sending to the service
+ *
+ * @param client the client to whom the queued message has to be sent
+ * @param msg the message to queue
+ */
+void
+GST_queue_message (struct GNUNET_SERVER_Client *client,
+ struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * Function to destroy a peer
+ *
+ * @param peer the peer structure to destroy
+ */
+void
+GST_destroy_peer (struct Peer *peer);
+
+
+/**
+ * Finds the route with directly connected host as destination through which
+ * the destination host can be reached
+ *
+ * @param host_id the id of the destination host
+ * @return the route with directly connected destination host; NULL if no route
+ * is found
+ */
+struct Route *
+GST_find_dest_route (uint32_t host_id);
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+void
+GST_handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Adds a host registration's request to a slave's registration queue
+ *
+ * @param slave the slave controller at which the given host has to be
+ * registered
+ * @param cb the host registration completion callback
+ * @param cb_cls the closure for the host registration completion callback
+ * @param host the host which has to be registered
+ */
+void
+GST_queue_host_registration (struct Slave *slave,
+ GNUNET_TESTBED_HostRegistrationCompletion cb,
+ void *cb_cls, struct GNUNET_TESTBED_Host *host);
+
+
+/**
+ * Callback to relay the reply msg of a forwarded operation back to the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the message to relay
+ */
+void
+GST_forwarded_operation_reply_relay (void *cls,
+ const struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * Task to free resources when forwarded operation has been timedout
+ *
+ * @param cls the ForwardedOperationContext
+ * @param tc the task context from scheduler
+ */
+void
+GST_forwarded_operation_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Send operation failure message to client
+ *
+ * @param client the client to which the failure message has to be sent to
+ * @param operation_id the id of the failed operation
+ * @param emsg the error message; can be NULL
+ */
+void
+GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
+ uint64_t operation_id, const char *emsg);
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+void
+GST_handle_remote_overlay_connect (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
+ *
+ * @param rhc the RegisteredHostContext
+ */
+void
+GST_process_next_focc (struct RegisteredHostContext *rhc);
+
+
+/**
+ * Cleans up ForwardedOverlayConnectContext
+ *
+ * @param focc the ForwardedOverlayConnectContext to cleanup
+ */
+void
+GST_cleanup_focc (struct ForwardedOverlayConnectContext *focc);
+
+
+/**
+ * Clears all pending overlay connect contexts in queue
+ */
+void
+GST_free_occq ();
+
+
+/**
+ * Clears all pending remote overlay connect contexts in queue
+ */
+void
+GST_free_roccq ();
+
+
+/**
+ * Initializes the cache
+ *
+ * @param size the size of the cache
+ */
+void
+GST_cache_init (unsigned int size);
+
+
+/**
+ * Clear cache
+ */
+void
+GST_cache_clear ();
+
+
+/**
+ * Looks up in the hello cache and returns the HELLO of the given peer
+ *
+ * @param peer_id the index of the peer whose HELLO has to be looked up
+ * @return the HELLO message; NULL if not found
+ */
+const struct GNUNET_MessageHeader *
+GST_cache_lookup_hello (const unsigned int peer_id);
+
+
+/**
+ * Caches the HELLO of the given peer. Updates the HELLO if it was already
+ * cached before
+ *
+ * @param id the peer identity of the peer whose HELLO has to be cached
+ * @param hello the HELLO message
+ */
+void
+GST_cache_add_hello (const unsigned int peer_id,
+ const struct GNUNET_MessageHeader *hello);
+
+
+/**
+ * Functions of this type are called when the needed handle is available for
+ * usage. These functions are to be registered with either of the functions
+ * GST_cache_get_handle_transport() or GST_cache_get_handle_core(). The
+ * corresponding handles will be set and if they are not, then it signals an
+ * error while opening the handles.
+ *
+ * @param cls the closure passed to GST_cache_get_handle_transport() or
+ * GST_cache_get_handle_core()
+ * @param ch the handle to CORE. Can be NULL if it is not requested
+ * @param th the handle to TRANSPORT. Can be NULL if it is not requested
+ * @param peer_id the identity of the peer. Will be NULL if ch is NULL. In other
+ * cases, its value being NULL means that CORE connection has failed.
+ */
+typedef void (*GST_cache_handle_ready_cb) (void *cls,
+ struct GNUNET_CORE_Handle * ch,
+ struct GNUNET_TRANSPORT_Handle * th,
+ const struct GNUNET_PeerIdentity *
+ peer_id);
+
+
+/**
+ * Callback to notify when the target peer given to
+ * GST_cache_get_handle_transport() is connected. Note that this callback may
+ * not be called if the target peer is already connected. Use
+ * GNUNET_TRANSPORT_check_neighbour_connected() to check if the target peer is
+ * already connected or not. This callback will be called only once or never (in
+ * case the target cannot be connected).
+ *
+ * @param cls the closure given to GST_cache_get_handle_done() for this callback
+ * @param target the peer identity of the target peer. The pointer should be
+ * valid until GST_cache_get_handle_done() is called.
+ */
+typedef void (*GST_cache_peer_connect_notify) (void *cls,
+ const struct GNUNET_PeerIdentity
+ * target);
+
+
+/**
+ * Get a transport handle with the given configuration. If the handle is already
+ * cached before, it will be retured in the given callback; the peer_id is used to lookup in the
+ * cache. If not a new operation is started to open the transport handle and
+ * will be given in the callback when it is available.
+ *
+ * @param peer_id the index of the peer
+ * @param cfg the configuration with which the transport handle has to be
+ * created if it was not present in the cache
+ * @param cb the callback to notify when the transport handle is available
+ * @param cb_cls the closure for the above callback
+ * @param target the peer identify of the peer whose connection to our TRANSPORT
+ * subsystem will be notified through the connect_notify_cb. Can be NULL
+ * @param connect_notify_cb the callback to call when the given target peer is
+ * connected. This callback will only be called once or never again (in
+ * case the target peer cannot be connected). Can be NULL
+ * @param connect_notify_cb_cls the closure for the above callback
+ * @return the handle which can be used cancel or mark that the handle is no
+ * longer being used
+ */
+struct GSTCacheGetHandle *
+GST_cache_get_handle_transport (unsigned int peer_id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GST_cache_handle_ready_cb cb, void *cb_cls,
+ const struct GNUNET_PeerIdentity *target,
+ GST_cache_peer_connect_notify connect_notify_cb,
+ void *connect_notify_cb_cls);
+
+
+/**
+ * Get a CORE handle with the given configuration. If the handle is already
+ * cached before, it will be retured in the given callback; the peer_id is used
+ * to lookup in the cache. If the handle is not cached before, a new operation
+ * is started to open the CORE handle and will be given in the callback when it
+ * is available along with the peer identity
+ *
+ * @param peer_id the index of the peer
+ * @param cfg the configuration with which the transport handle has to be
+ * created if it was not present in the cache
+ * @param cb the callback to notify when the transport handle is available
+ * @param cb_cls the closure for the above callback
+ * @param target the peer identify of the peer whose connection to our CORE
+ * subsystem will be notified through the connect_notify_cb. Can be NULL
+ * @param connect_notify_cb the callback to call when the given target peer is
+ * connected. This callback will only be called once or never again (in
+ * case the target peer cannot be connected). Can be NULL
+ * @param connect_notify_cb_cls the closure for the above callback
+ * @return the handle which can be used cancel or mark that the handle is no
+ * longer being used
+ */
+struct GSTCacheGetHandle *
+GST_cache_get_handle_core (unsigned int peer_id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GST_cache_handle_ready_cb cb, void *cb_cls,
+ const struct GNUNET_PeerIdentity *target,
+ GST_cache_peer_connect_notify connect_notify_cb,
+ void *connect_notify_cb_cls);
+
+
+/**
+ * Mark the GetCacheHandle as being done if a handle has been provided already
+ * or as being cancelled if the callback for the handle hasn't been called.
+ *
+ * @param cgh the CacheGetHandle handle
+ */
+void
+GST_cache_get_handle_done (struct GSTCacheGetHandle *cgh);
+
+/* End of gnunet-service-testbed.h */
diff --git a/src/testbed/gnunet-service-testbed_cache.c b/src/testbed/gnunet-service-testbed_cache.c
new file mode 100644
index 0000000..112868e
--- /dev/null
+++ b/src/testbed/gnunet-service-testbed_cache.c
@@ -0,0 +1,1048 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 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 testbed/gnunet-service-testbed_cache.h
+ * @brief testbed cache implementation
+ * @author Sree Harsha Totakura
+ */
+#include "gnunet-service-testbed.h"
+
+/**
+ * Redefine LOG with a changed log component string
+ */
+#ifdef LOG
+#undef LOG
+#endif
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "testbed-cache", __VA_ARGS__)
+
+
+/**
+ * Time to expire a cache entry
+ */
+#define CACHE_EXPIRY \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+
+/**
+ * Type of cache-get requests
+ */
+enum CacheGetType
+{
+ /**
+ * Get transport handle
+ */
+ CGT_TRANSPORT_HANDLE = 1,
+
+ /**
+ * Get core handle
+ */
+ CGT_CORE_HANDLE
+};
+
+
+/**
+ * The cache-get request handle
+ */
+struct GSTCacheGetHandle;
+
+
+/**
+ * This context structure is used to maintain a queue of notifications to check
+ * which of them are to be notified when a peer is connected.
+ */
+struct ConnectNotifyContext
+{
+ /**
+ * The next ptr for the DLL
+ */
+ struct ConnectNotifyContext *next;
+
+ /**
+ * The prev ptr for the DLL
+ */
+ struct ConnectNotifyContext *prev;
+
+ /**
+ * The peer identity of the target peer. When this target peer is connected,
+ * call the notify callback
+ */
+ const struct GNUNET_PeerIdentity *target;
+
+ /**
+ * The notify callback to be called when the target peer is connected
+ */
+ GST_cache_peer_connect_notify cb;
+
+ /**
+ * The closure for the notify callback
+ */
+ void *cb_cls;
+
+ /**
+ * The GSTCacheGetHandle reposible for creating this context
+ */
+ struct GSTCacheGetHandle *cgh;
+
+};
+
+
+/**
+ * The cache-get request handle
+ */
+struct GSTCacheGetHandle
+{
+ /**
+ * The next ptr for the DLL. Used in struct CacheEntry
+ */
+ struct GSTCacheGetHandle *next;
+
+ /**
+ * The prev ptr for the DLL. Used in struct CacheEntry
+ */
+ struct GSTCacheGetHandle *prev;
+
+ /**
+ * The cache entry object this handle corresponds to
+ */
+ struct CacheEntry *entry;
+
+ /**
+ * The cache callback to call when a handle is available
+ */
+ GST_cache_handle_ready_cb cb;
+
+ /**
+ * The closure for the above callback
+ */
+ void *cb_cls;
+
+ /**
+ * The peer connect notify context created for this handle; can be NULL
+ */
+ struct ConnectNotifyContext *nctxt;
+
+ /**
+ * The type of this cache-get request
+ */
+ enum CacheGetType type;
+
+ /**
+ * Did we call the cache callback already?
+ */
+ int notify_called;
+};
+
+/**
+ * Cache entry
+ */
+struct CacheEntry
+{
+ /**
+ * DLL next ptr for least recently used cache entries
+ */
+ struct CacheEntry *next;
+
+ /**
+ * DLL prev ptr for least recently used cache entries
+ */
+ struct CacheEntry *prev;
+
+ /**
+ * The transport handle to the peer corresponding to this entry; can be NULL
+ */
+ struct GNUNET_TRANSPORT_Handle *transport_handle_;
+
+ /**
+ * The operation handle for transport handle
+ */
+ struct GNUNET_TESTBED_Operation *transport_op_;
+
+ /**
+ * The core handle to the peer corresponding to this entry; can be NULL
+ */
+ struct GNUNET_CORE_Handle *core_handle;
+
+ /**
+ * The operation handle for core handle
+ */
+ struct GNUNET_TESTBED_Operation *core_op;
+
+ /**
+ * The peer identity of this peer. Will be set upon opening a connection to
+ * the peers CORE service. Will be NULL until then and after the CORE
+ * connection is closed
+ */
+ struct GNUNET_PeerIdentity *peer_identity;
+
+ /**
+ * The configuration of the peer. Should be not NULL as long as the core_handle
+ * or transport_handle are valid
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * The key for this entry
+ */
+ struct GNUNET_HashCode key;
+
+ /**
+ * The HELLO message
+ */
+ struct GNUNET_MessageHeader *hello;
+
+ /**
+ * the head of the CacheGetHandle queue
+ */
+ struct GSTCacheGetHandle *cgh_qhead;
+
+ /**
+ * the tail of the CacheGetHandle queue
+ */
+ struct GSTCacheGetHandle *cgh_qtail;
+
+ /**
+ * DLL head for the queue of notifications contexts to check which of them are to
+ * be notified when a peer is connected.
+ */
+ struct ConnectNotifyContext *nctxt_qhead;
+
+ /**
+ * DLL tail for the queue of notifications contexts to check which of them are to
+ * be notified when a peer is connected.
+ */
+ struct ConnectNotifyContext *nctxt_qtail;
+
+ /**
+ * The task that calls the cache callback
+ */
+ GNUNET_SCHEDULER_TaskIdentifier notify_task;
+
+ /**
+ * The task to expire this cache entry, free any handlers it has opened and
+ * mark their corresponding operations as done.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier expire_task;
+
+ /**
+ * Number of operations this cache entry is being used
+ */
+ unsigned int demand;
+
+ /**
+ * The id of the peer this entry corresponds to
+ */
+ unsigned int peer_id;
+
+ /**
+ * Is this entry in LRU cache queue?
+ */
+ unsigned int in_lru;
+};
+
+
+/**
+ * Hashmap to maintain cache
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *cache;
+
+/**
+ * DLL head for least recently used cache entries; least recently used
+ * cache items are at the head. The cache enties are added to this queue when
+ * their demand becomes zero. They are removed from the queue when they are
+ * needed by any operation.
+ */
+static struct CacheEntry *lru_cache_head;
+
+/**
+ * DLL tail for least recently used cache entries; recently used cache
+ * items are at the tail.The cache enties are added to this queue when
+ * their demand becomes zero. They are removed from the queue when they are
+ * needed by any operation.
+ */
+static struct CacheEntry *lru_cache_tail;
+
+/**
+ * the size of the LRU queue
+ */
+static unsigned int lru_cache_size;
+
+/**
+ * the threshold size for the LRU queue
+ */
+static unsigned int lru_cache_threshold_size;
+
+/**
+ * The total number of elements in cache
+ */
+static unsigned int cache_size;
+
+
+/**
+ * Looks up in the cache and returns the entry
+ *
+ * @param id the peer identity of the peer whose corresponding entry has to be looked up
+ * @return the HELLO message; NULL if not found
+ */
+static struct CacheEntry *
+cache_lookup (const struct GNUNET_HashCode *key)
+{
+ struct CacheEntry *entry;
+
+ if (NULL == cache)
+ return NULL;
+ entry = GNUNET_CONTAINER_multihashmap_get (cache, key);
+ return entry;
+}
+
+
+/**
+ * Function to disconnect the core and transport handles; free the existing
+ * configuration; and remove from the LRU cache list. The entry is left to be in
+ * the hash table so that the HELLO can still be found later
+ *
+ * @param entry the cache entry
+ */
+static void
+close_handles (struct CacheEntry *entry)
+{
+ struct ConnectNotifyContext *ctxt;
+
+ GNUNET_assert (0 == entry->demand);
+ if (GNUNET_YES == entry->in_lru)
+ {
+ GNUNET_assert (0 < lru_cache_size);
+ if (GNUNET_SCHEDULER_NO_TASK != entry->expire_task)
+ {
+ GNUNET_SCHEDULER_cancel (entry->expire_task);
+ entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_CONTAINER_DLL_remove (lru_cache_head, lru_cache_tail, entry);
+ lru_cache_size--;
+ entry->in_lru = GNUNET_NO;
+ }
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == entry->expire_task);
+ while (NULL != (ctxt = entry->nctxt_qhead))
+ {
+ GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail, ctxt);
+ GNUNET_free (ctxt);
+ }
+ LOG_DEBUG ("Cleaning up handles from an entry in cache\n");
+ if (NULL != entry->transport_handle_)
+ {
+ GNUNET_assert (NULL != entry->transport_op_);
+ GNUNET_TESTBED_operation_done (entry->transport_op_);
+ entry->transport_op_ = NULL;
+ }
+ if (NULL != entry->core_handle)
+ {
+ GNUNET_assert (NULL != entry->core_op);
+ GNUNET_TESTBED_operation_done (entry->core_op);
+ entry->core_op = NULL;
+ }
+ if (NULL != entry->cfg)
+ {
+ GNUNET_CONFIGURATION_destroy (entry->cfg);
+ entry->cfg = NULL;
+ }
+}
+
+
+/**
+ * The task to expire this cache entry, free any handlers it has opened and
+ * mark their corresponding operations as done.
+ *
+ * @param cls the CacheEntry
+ * @param tc the scheduler task context
+ */
+static void
+expire_cache_entry (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CacheEntry *entry = cls;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != entry->expire_task);
+ entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+ close_handles (entry);
+}
+
+
+/**
+ * Creates a new cache entry and then puts it into the cache's hashtable.
+ *
+ * @param key the hash code to use for inserting the newly created entry
+ * @param peer_id the index of the peer to tag the newly created entry
+ * @return the newly created entry
+ */
+static struct CacheEntry *
+add_entry (const struct GNUNET_HashCode *key, unsigned int peer_id)
+{
+ struct CacheEntry *entry;
+
+ entry = GNUNET_malloc (sizeof (struct CacheEntry));
+ entry->peer_id = peer_id;
+ memcpy (&entry->key, key, sizeof (struct GNUNET_HashCode));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (cache, &entry->key, entry,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+ cache_size++;
+ return entry;
+}
+
+
+/**
+ * Function to find a suitable GSTCacheGetHandle which is waiting for one of the
+ * handles in given entry to be available.
+ *
+ * @param entry the cache entry whose GSTCacheGetHandle list has to be searched
+ * @param head the starting list element in the GSTCacheGetHandle where the
+ * search has to be begin
+ * @return a suitable GSTCacheGetHandle whose handle ready notify callback
+ * hasn't been called yet. NULL if no such suitable GSTCacheGetHandle
+ * is found
+ */
+static struct GSTCacheGetHandle *
+search_suitable_cgh (const struct CacheEntry *entry,
+ const struct GSTCacheGetHandle *head)
+{
+ const struct GSTCacheGetHandle *cgh;
+
+ for (cgh = head; NULL != cgh; cgh = cgh->next)
+ {
+ if (GNUNET_YES == cgh->notify_called)
+ return NULL;
+ switch (cgh->type)
+ {
+ case CGT_TRANSPORT_HANDLE:
+ if (NULL == entry->transport_handle_)
+ continue;
+ break;
+ case CGT_CORE_HANDLE:
+ if (NULL == entry->core_handle)
+ continue;
+ break;
+ }
+ break;
+ }
+ return (struct GSTCacheGetHandle *) cgh;
+}
+
+
+/**
+ * Task to call the handle ready notify callback of a queued GSTCacheGetHandle
+ * of an entry when one or all of its handles are available.
+ *
+ * @param cls the cache entry
+ * @param tc the task context from scheduler
+ */
+static void
+call_cgh_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct CacheEntry *entry = cls;
+ struct GSTCacheGetHandle *cgh;
+ const struct GSTCacheGetHandle *cgh2;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != entry->notify_task);
+ entry->notify_task = GNUNET_SCHEDULER_NO_TASK;
+ cgh = search_suitable_cgh (entry, entry->cgh_qhead);
+ GNUNET_assert (NULL != cgh);
+ cgh2 = NULL;
+ if (NULL != cgh->next)
+ cgh2 = search_suitable_cgh (entry, cgh->next);
+ GNUNET_CONTAINER_DLL_remove (entry->cgh_qhead, entry->cgh_qtail, cgh);
+ cgh->notify_called = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert_tail (entry->cgh_qhead, entry->cgh_qtail, cgh);
+ if (NULL != cgh2)
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
+ if (NULL != cgh->nctxt)
+ { /* Register the peer connect notify callback */
+ GNUNET_CONTAINER_DLL_insert_tail (entry->nctxt_qhead, entry->nctxt_qtail,
+ cgh->nctxt);
+ }
+ LOG_DEBUG ("Calling notify for handle type %u\n", cgh->type);
+ cgh->cb (cgh->cb_cls, entry->core_handle, entry->transport_handle_,
+ entry->peer_identity);
+}
+
+
+/**
+ * Function called from peer connect notify callbacks from CORE and TRANSPORT
+ * connections. This function calls the pendning peer connect notify callbacks
+ * which are queued in an entry.
+ *
+ * @param cls the cache entry
+ * @param peer the peer that connected
+ * @param type the type of the handle this notification corresponds to
+ */
+static void
+peer_connect_notify_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const enum CacheGetType type)
+{
+ struct CacheEntry *entry = cls;
+ struct ConnectNotifyContext *ctxt;
+ struct ConnectNotifyContext *ctxt2;
+ GST_cache_peer_connect_notify cb;
+ void *cb_cls;
+
+
+ for (ctxt = entry->nctxt_qhead; NULL != ctxt;)
+ {
+ GNUNET_assert (NULL != ctxt->cgh);
+ if (type != ctxt->cgh->type)
+ {
+ ctxt = ctxt->next;
+ continue;
+ }
+ if (0 != memcmp (ctxt->target, peer, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ ctxt = ctxt->next;
+ continue;
+ }
+ cb = ctxt->cb;
+ cb_cls = ctxt->cb_cls;
+ ctxt->cgh->nctxt = NULL;
+ ctxt2 = ctxt->next;
+ GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail, ctxt);
+ GNUNET_free (ctxt);
+ ctxt = ctxt2;
+ cb (cb_cls, peer);
+ }
+ if (NULL == ctxt)
+ return;
+
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param peer the peer that connected
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+static void
+transport_peer_connect_notify_cb (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ peer_connect_notify_cb (cls, peer, CGT_TRANSPORT_HANDLE);
+}
+
+
+/**
+ * Function called when resources for opening a connection to TRANSPORT are
+ * available.
+ *
+ * @param cls the cache entry
+ */
+static void
+opstart_get_handle_transport (void *cls)
+{
+ struct CacheEntry *entry = cls;
+
+ GNUNET_assert (NULL != entry);
+ LOG_DEBUG ("Opening a transport connection to peer %u\n", entry->peer_id);
+ entry->transport_handle_ =
+ GNUNET_TRANSPORT_connect (entry->cfg, NULL, entry, NULL,
+ &transport_peer_connect_notify_cb, NULL);
+ if (NULL == entry->transport_handle_)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (0 == entry->demand)
+ return;
+ if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
+ return;
+ if (NULL != search_suitable_cgh (entry, entry->cgh_qhead))
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
+}
+
+
+/**
+ * Function called when the operation responsible for opening a TRANSPORT
+ * connection is marked as done.
+ *
+ * @param cls the cache entry
+ */
+static void
+oprelease_get_handle_transport (void *cls)
+{
+ struct CacheEntry *entry = cls;
+
+ if (NULL == entry->transport_handle_)
+ return;
+ GNUNET_TRANSPORT_disconnect (entry->transport_handle_);
+ entry->transport_handle_ = NULL;
+}
+
+
+/**
+ * Function called after GNUNET_CORE_connect has succeeded (or failed
+ * for good). Note that the private key of the peer is intentionally
+ * not exposed here; if you need it, your process should try to read
+ * the private key file directly (which should work if you are
+ * authorized...). Implementations of this function must not call
+ * GNUNET_CORE_disconnect (other than by scheduling a new task to
+ * do this later).
+ *
+ * @param cls closure
+ * @param server handle to the server, NULL if we failed
+ * @param my_identity ID of this peer, NULL if we failed
+ */
+static void
+core_startup_cb (void *cls, struct GNUNET_CORE_Handle *server,
+ const struct GNUNET_PeerIdentity *my_identity)
+{
+ struct CacheEntry *entry = cls;
+
+ if (NULL == my_identity)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_assert (NULL == entry->peer_identity);
+ entry->core_handle = server;
+ entry->peer_identity = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
+ memcpy (entry->peer_identity, my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ if (0 == entry->demand)
+ return;
+ if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
+ return;
+ if (NULL != search_suitable_cgh (entry, entry->cgh_qhead))
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
+}
+
+
+/**
+ * Method called whenever a given peer connects at CORE level
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ * @param atsi performance data for the connection
+ * @param atsi_count number of records in 'atsi'
+ */
+static void
+core_peer_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *atsi,
+ unsigned int atsi_count)
+{
+ peer_connect_notify_cb (cls, peer, CGT_CORE_HANDLE);
+}
+
+
+/**
+ * Function called when resources for opening a connection to CORE are
+ * available.
+ *
+ * @param cls the cache entry
+ */
+static void
+opstart_get_handle_core (void *cls)
+{
+ struct CacheEntry *entry = cls;
+
+ const struct GNUNET_CORE_MessageHandler no_handlers[] = {
+ {NULL, 0, 0}
+ };
+
+ GNUNET_assert (NULL != entry);
+ LOG_DEBUG ("Opening a CORE connection to peer %u\n", entry->peer_id);
+ /* void?: We also get the handle when the connection to CORE is successful */
+ (void) GNUNET_CORE_connect (entry->cfg, entry, /* closure */
+ &core_startup_cb, /* core startup notify */
+ &core_peer_connect_cb, /* peer connect notify */
+ NULL, /* peer disconnect notify */
+ NULL, /* inbound notify */
+ GNUNET_NO, /* inbound header only? */
+ NULL, /* outbound notify */
+ GNUNET_NO, /* outbound header only? */
+ no_handlers);
+}
+
+
+/**
+ * Function called when the operation responsible for opening a TRANSPORT
+ * connection is marked as done.
+ *
+ * @param cls the cache entry
+ */
+static void
+oprelease_get_handle_core (void *cls)
+{
+ struct CacheEntry *entry = cls;
+
+ if (NULL == entry->core_handle)
+ return;
+ GNUNET_CORE_disconnect (entry->core_handle);
+ entry->core_handle = NULL;
+ GNUNET_free_non_null (entry->peer_identity);
+ entry->peer_identity = NULL;
+}
+
+
+/**
+ * Function to get a handle with given configuration. The type of the handle is
+ * implicitly provided in the GSTCacheGetHandle. If the handle is already cached
+ * before, it will be retured in the given callback; the peer_id is used to
+ * lookup in the cache; if not, a new operation is started to open the transport
+ * handle and will be given in the callback when it is available.
+ *
+ * @param cls the cache entry
+ */
+static struct GSTCacheGetHandle *
+cache_get_handle (unsigned int peer_id, struct GSTCacheGetHandle *cgh,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_PeerIdentity *target,
+ GST_cache_peer_connect_notify connect_notify_cb,
+ void *connect_notify_cb_cls)
+{
+ struct GNUNET_HashCode key;
+ void *handle;
+ struct CacheEntry *entry;
+ struct ConnectNotifyContext *ctxt;
+ struct GNUNET_TESTBED_Operation *op;
+
+ GNUNET_assert (0 != cgh->type);
+ GNUNET_CRYPTO_hash (&peer_id, sizeof (peer_id), &key);
+ handle = NULL;
+ entry = cache_lookup (&key);
+ if (NULL != entry)
+ {
+ if (GNUNET_YES == entry->in_lru)
+ {
+ GNUNET_assert (0 == entry->demand);
+ GNUNET_assert (0 < lru_cache_size);
+ if (GNUNET_SCHEDULER_NO_TASK != entry->expire_task)
+ {
+ GNUNET_SCHEDULER_cancel (entry->expire_task);
+ entry->expire_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_CONTAINER_DLL_remove (lru_cache_head, lru_cache_tail, entry);
+ lru_cache_size--;
+ entry->in_lru = GNUNET_NO;
+ }
+ switch (cgh->type)
+ {
+ case CGT_TRANSPORT_HANDLE:
+ handle = entry->transport_handle_;
+ if (NULL != handle)
+ LOG_DEBUG ("Found TRANSPORT handle in cache for peer %u\n",
+ entry->peer_id);
+ break;
+ case CGT_CORE_HANDLE:
+ handle = entry->core_handle;
+ if (NULL != handle)
+ LOG_DEBUG ("Found CORE handle in cache for peer %u\n", entry->peer_id);
+ break;
+ }
+ }
+ if (NULL == entry)
+ entry = add_entry (&key, peer_id);
+ if (NULL == entry->cfg)
+ entry->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ entry->demand++;
+ cgh->entry = entry;
+ GNUNET_CONTAINER_DLL_insert (entry->cgh_qhead, entry->cgh_qtail, cgh);
+ if ((NULL != target) && (NULL != connect_notify_cb))
+ {
+ ctxt = GNUNET_malloc (sizeof (struct ConnectNotifyContext));
+ ctxt->target = target;
+ ctxt->cb = connect_notify_cb;
+ ctxt->cb_cls = connect_notify_cb_cls;
+ GNUNET_assert (NULL == cgh->nctxt);
+ cgh->nctxt = ctxt;
+ ctxt->cgh = cgh;
+ }
+ if (NULL != handle)
+ {
+ if (GNUNET_SCHEDULER_NO_TASK == entry->notify_task)
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
+ return cgh;
+ }
+ switch (cgh->type)
+ {
+ case CGT_TRANSPORT_HANDLE:
+ if (NULL != entry->transport_op_)
+ return cgh;
+ op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_transport,
+ &oprelease_get_handle_transport);
+ entry->transport_op_ = op;
+ break;
+ case CGT_CORE_HANDLE:
+ if (NULL != entry->core_op)
+ return cgh;
+ op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_core,
+ &oprelease_get_handle_core);
+ entry->core_op = op;
+ break;
+ }
+ GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, op);
+ GNUNET_TESTBED_operation_begin_wait_ (op);
+ return cgh;
+}
+
+
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+cache_clear_iterator (void *cls, const struct GNUNET_HashCode *key, void *value)
+{
+ struct CacheEntry *entry = value;
+ static unsigned int ncleared;
+
+ GNUNET_assert (NULL != entry);
+ GNUNET_break (0 == entry->demand);
+ LOG_DEBUG ("Clearing entry %u of %u\n", ++ncleared, cache_size);
+ GNUNET_CONTAINER_multihashmap_remove (cache, key, value);
+ if (0 == entry->demand)
+ close_handles (entry);
+ GNUNET_free_non_null (entry->hello);
+ GNUNET_break (GNUNET_SCHEDULER_NO_TASK == entry->expire_task);
+ GNUNET_break (NULL == entry->transport_handle_);
+ GNUNET_break (NULL == entry->transport_op_);
+ GNUNET_break (NULL == entry->core_handle);
+ GNUNET_break (NULL == entry->core_op);
+ GNUNET_break (NULL == entry->cfg);
+ GNUNET_assert (NULL == entry->cgh_qhead);
+ GNUNET_assert (NULL == entry->cgh_qtail);
+ GNUNET_assert (NULL == entry->nctxt_qhead);
+ GNUNET_assert (NULL == entry->nctxt_qtail);
+ GNUNET_free (entry);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Clear cache
+ */
+void
+GST_cache_clear ()
+{
+ GNUNET_CONTAINER_multihashmap_iterate (cache, &cache_clear_iterator, NULL);
+ GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (cache));
+ GNUNET_CONTAINER_multihashmap_destroy (cache);
+}
+
+
+/**
+ * Initializes the cache
+ *
+ * @param size the size of the cache
+ */
+void
+GST_cache_init (unsigned int size)
+{
+ if (0 == size)
+ return;
+ lru_cache_threshold_size = size;
+ if (size > 1)
+ size = size / 2;
+ cache = GNUNET_CONTAINER_multihashmap_create (size, GNUNET_YES);
+}
+
+
+/**
+ * Mark the GetCacheHandle as being done if a handle has been provided already
+ * or as being cancelled if the callback for the handle hasn't been called.
+ *
+ * @param cgh the CacheGetHandle handle
+ */
+void
+GST_cache_get_handle_done (struct GSTCacheGetHandle *cgh)
+{
+ struct CacheEntry *entry;
+
+ entry = cgh->entry;
+ GNUNET_assert (NULL != entry);
+ GNUNET_assert (0 < entry->demand);
+ entry->demand--;
+ if (GNUNET_SCHEDULER_NO_TASK != entry->notify_task)
+ {
+ GNUNET_SCHEDULER_cancel (entry->notify_task);
+ entry->notify_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_CONTAINER_DLL_remove (entry->cgh_qhead, entry->cgh_qtail, cgh);
+ if (NULL != cgh->nctxt)
+ {
+ GNUNET_assert (cgh == cgh->nctxt->cgh);
+ if (GNUNET_YES == cgh->notify_called)
+ GNUNET_CONTAINER_DLL_remove (entry->nctxt_qhead, entry->nctxt_qtail,
+ cgh->nctxt);
+ GNUNET_free (cgh->nctxt);
+ }
+ GNUNET_free (cgh);
+ if (0 == entry->demand)
+ {
+ entry->expire_task =
+ GNUNET_SCHEDULER_add_delayed (CACHE_EXPIRY, &expire_cache_entry, entry);
+ GNUNET_CONTAINER_DLL_insert_tail (lru_cache_head, lru_cache_tail, entry);
+ lru_cache_size++;
+ entry->in_lru = GNUNET_YES;
+ if (lru_cache_size > lru_cache_threshold_size)
+ close_handles (lru_cache_head);
+ }
+ else
+ {
+ struct GSTCacheGetHandle *cgh2;
+
+ if (NULL != (cgh2 = search_suitable_cgh (entry, entry->cgh_qhead)))
+ entry->notify_task = GNUNET_SCHEDULER_add_now (&call_cgh_cb, entry);
+ }
+}
+
+
+/**
+ * Get a transport handle with the given configuration. If the handle is
+ * already cached before, it will be retured in the given callback; the peer_id
+ * is used to lookup in the cache; if not, a new operation is started to open the
+ * transport handle and will be given in the callback when it is available.
+ *
+ * @param peer_id the index of the peer
+ * @param cfg the configuration with which the transport handle has to be
+ * created if it was not present in the cache
+ * @param cb the callback to notify when the transport handle is available
+ * @param cb_cls the closure for the above callback
+ * @param target the peer identify of the peer whose connection to our TRANSPORT
+ * subsystem will be notified through the connect_notify_cb. Can be NULL
+ * @param connect_notify_cb the callback to call when the given target peer is
+ * connected. This callback will only be called once or never again (in
+ * case the target peer cannot be connected). Can be NULL
+ * @param connect_notify_cb_cls the closure for the above callback
+ * @return the handle which can be used cancel or mark that the handle is no
+ * longer being used
+ */
+struct GSTCacheGetHandle *
+GST_cache_get_handle_transport (unsigned int peer_id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GST_cache_handle_ready_cb cb, void *cb_cls,
+ const struct GNUNET_PeerIdentity *target,
+ GST_cache_peer_connect_notify connect_notify_cb,
+ void *connect_notify_cb_cls)
+{
+ struct GSTCacheGetHandle *cgh;
+
+ cgh = GNUNET_malloc (sizeof (struct GSTCacheGetHandle));
+ cgh->cb = cb;
+ cgh->cb_cls = cb_cls;
+ cgh->type = CGT_TRANSPORT_HANDLE;
+ return cache_get_handle (peer_id, cgh, cfg, target, connect_notify_cb,
+ connect_notify_cb_cls);
+}
+
+
+/**
+ * Get a CORE handle with the given configuration. If the handle is already
+ * cached before, it will be retured in the given callback; the peer_id is used
+ * to lookup in the cache. If the handle is not cached before, a new operation
+ * is started to open the CORE handle and will be given in the callback when it
+ * is available along with the peer identity
+ *
+ * @param peer_id the index of the peer
+ * @param cfg the configuration with which the transport handle has to be
+ * created if it was not present in the cache
+ * @param cb the callback to notify when the transport handle is available
+ * @param cb_cls the closure for the above callback
+ * @param target the peer identify of the peer whose connection to our CORE
+ * subsystem will be notified through the connect_notify_cb. Can be NULL
+ * @param connect_notify_cb the callback to call when the given target peer is
+ * connected. This callback will only be called once or never again (in
+ * case the target peer cannot be connected). Can be NULL
+ * @param connect_notify_cb_cls the closure for the above callback
+ * @return the handle which can be used cancel or mark that the handle is no
+ * longer being used
+ */
+struct GSTCacheGetHandle *
+GST_cache_get_handle_core (unsigned int peer_id,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GST_cache_handle_ready_cb cb, void *cb_cls,
+ const struct GNUNET_PeerIdentity *target,
+ GST_cache_peer_connect_notify connect_notify_cb,
+ void *connect_notify_cb_cls)
+{
+ struct GSTCacheGetHandle *cgh;
+
+ cgh = GNUNET_malloc (sizeof (struct GSTCacheGetHandle));
+ cgh->cb = cb;
+ cgh->cb_cls = cb_cls;
+ cgh->type = CGT_CORE_HANDLE;
+ return cache_get_handle (peer_id, cgh, cfg, target, connect_notify_cb,
+ connect_notify_cb_cls);
+}
+
+
+/**
+ * Looks up in the hello cache and returns the HELLO of the given peer
+ *
+ * @param peer_id the index of the peer whose HELLO has to be looked up
+ * @return the HELLO message; NULL if not found
+ */
+const struct GNUNET_MessageHeader *
+GST_cache_lookup_hello (const unsigned int peer_id)
+{
+ struct CacheEntry *entry;
+ struct GNUNET_HashCode key;
+
+ LOG_DEBUG ("Looking up HELLO for peer %u\n", peer_id);
+ GNUNET_CRYPTO_hash (&peer_id, sizeof (peer_id), &key);
+ entry = cache_lookup (&key);
+ if (NULL == entry)
+ return NULL;
+ if (NULL != entry->hello)
+ LOG_DEBUG ("HELLO found for peer %u\n", peer_id);
+ return entry->hello;
+}
+
+
+/**
+ * Caches the HELLO of the given peer. Updates the HELLO if it was already
+ * cached before
+ *
+ * @param id the peer identity of the peer whose HELLO has to be cached
+ * @param hello the HELLO message
+ */
+void
+GST_cache_add_hello (const unsigned int peer_id,
+ const struct GNUNET_MessageHeader *hello)
+{
+ struct CacheEntry *entry;
+ struct GNUNET_HashCode key;
+
+ GNUNET_CRYPTO_hash (&peer_id, sizeof (peer_id), &key);
+ entry = GNUNET_CONTAINER_multihashmap_get (cache, &key);
+ if (NULL == entry)
+ entry = add_entry (&key, peer_id);
+ GNUNET_free_non_null (entry->hello);
+ entry->hello = GNUNET_copy_message (hello);
+}
+
+/* end of gnunet-service-testbed_hc.c */
diff --git a/src/testbed/gnunet-service-testbed_oc.c b/src/testbed/gnunet-service-testbed_oc.c
new file mode 100644
index 0000000..9b571e3
--- /dev/null
+++ b/src/testbed/gnunet-service-testbed_oc.c
@@ -0,0 +1,1595 @@
+/*
+ This file is part of GNUnet.
+ (C) 2012 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 testbed/gnunet-service-testbed_oc.c
+ * @brief code for handling overlay connect operations
+ * @author Sree Harsha Totakura
+ */
+
+#include "gnunet-service-testbed.h"
+
+/**
+ * Redefine LOG with a changed log component string
+ */
+#ifdef LOG
+#undef LOG
+#endif
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "testbed-OC", __VA_ARGS__)
+
+
+/**
+ * Context information for requesting TRANSPORT to connect to a peer
+ */
+struct TryConnectContext
+{
+ /**
+ * The identity of the peer to which the transport has to attempt a connection
+ */
+ struct GNUNET_PeerIdentity *pid;
+
+ /**
+ * The transport handle obtained from cache. Do NOT close/disconnect.
+ */
+ struct GNUNET_TRANSPORT_Handle *th_;
+
+ /**
+ * The GetCacheHandle for the p1th transport handle
+ */
+ struct GSTCacheGetHandle *cgh_th;
+
+ /**
+ * the try connect handle
+ */
+ struct GNUNET_TRANSPORT_TryConnectHandle *tch;
+
+ /**
+ * The task handle
+ */
+ GNUNET_SCHEDULER_TaskIdentifier task;
+
+ /**
+ * The id of the operation which is resposible for this context
+ */
+ uint64_t op_id;
+
+ /**
+ * The number of times we attempted to connect
+ */
+ unsigned int retries;
+
+};
+
+
+/**
+ * Context information for connecting 2 peers in overlay.
+ */
+struct OverlayConnectContext
+{
+ /**
+ * The next pointer for maintaining a DLL of all OverlayConnectContexts
+ */
+ struct OverlayConnectContext *next;
+
+ /**
+ * The prev pointer for maintaining a DLL of all OverlayConnectContexts
+ */
+ struct OverlayConnectContext *prev;
+
+ /**
+ * The client which has requested for overlay connection. This is used to send
+ * either a success of failure message
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * the first peer which is to expect an overlay connection from the second peer.
+ */
+ struct Peer *peer;
+
+ /**
+ * Transport handle of the first peer obtained from cache to get its HELLO. Do
+ * NOT close/disconnect.
+ */
+ struct GNUNET_TRANSPORT_Handle *p1th_;
+
+ /**
+ * The CacheGetHandle for the p1th transport handle
+ */
+ struct GSTCacheGetHandle *cgh_p1th;
+
+ /**
+ * The GetCacheHandle for registering callback to notify CORE level peer
+ * connects and to get our identity.
+ */
+ struct GSTCacheGetHandle *cgh_ch;
+
+ /**
+ * HELLO of the first peer. This should be sent to the second peer.
+ */
+ struct GNUNET_MessageHeader *hello;
+
+ /**
+ * Get GetHelloHandle to acquire a HELLO of the first peer
+ */
+ struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
+
+ /**
+ * The handle for offering the HELLO of the first peer to the second
+ * peer. This is only used if the second peer is a local peer.
+ */
+ struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
+
+ /**
+ * The error message we send if this overlay connect operation has timed out
+ */
+ char *emsg;
+
+ /**
+ * Operation context for the suboperation we start to get the identity of the
+ * second peer if it is a remote peer
+ */
+ struct OperationContext *opc;
+
+ /**
+ * Controller of peer 2; NULL if the peer is a local peer
+ */
+ struct GNUNET_TESTBED_Controller *peer2_controller;
+
+ /**
+ * The transport TryConnectContext. This will be NULL if the second peer is a
+ * remote peer
+ */
+ struct TryConnectContext tcc;
+
+ /**
+ * The peer identity of the first peer
+ */
+ struct GNUNET_PeerIdentity peer_identity;
+
+ /**
+ * The peer identity of the other peer
+ */
+ struct GNUNET_PeerIdentity other_peer_identity;
+
+ /**
+ * The id of the operation responsible for creating this context
+ */
+ uint64_t op_id;
+
+ /**
+ * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
+ * connect to peer 2
+ */
+ GNUNET_SCHEDULER_TaskIdentifier send_hello_task;
+
+ /**
+ * The id of the overlay connect timeout task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * The id of the cleanup task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
+
+ /**
+ * The id of peer A
+ */
+ uint32_t peer_id;
+
+ /**
+ * The id of peer B
+ */
+ uint32_t other_peer_id;
+
+};
+
+
+/**
+ * Context information for remote overlay connect operations. Remote overlay
+ * connections are used when peers A and B reside on different hosts. In these
+ * operations the host controller for peer B is asked by the host controller of
+ * peer A to make peer B connect to peer A by sending the controller of peer B
+ * the HELLO of peer A.
+ */
+struct RemoteOverlayConnectCtx
+{
+ /**
+ * the next pointer for DLL
+ */
+ struct RemoteOverlayConnectCtx *next;
+
+ /**
+ * the prev pointer for DLL
+ */
+ struct RemoteOverlayConnectCtx *prev;
+
+ /**
+ * The peer handle of peer B
+ */
+ struct Peer *peer;
+
+ /**
+ * Peer A's HELLO
+ */
+ struct GNUNET_MessageHeader *hello;
+
+ /**
+ * The handle for offering HELLO
+ */
+ struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
+
+ /**
+ * The transport try connect context
+ */
+ struct TryConnectContext tcc;
+
+ /**
+ * The peer identity of peer A
+ */
+ struct GNUNET_PeerIdentity a_id;
+
+ /**
+ * Task for offering HELLO of A to B and doing try_connect
+ */
+ GNUNET_SCHEDULER_TaskIdentifier attempt_connect_task_id;
+
+ /**
+ * Task to timeout RequestOverlayConnect
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_rocc_task_id;
+
+ /**
+ * The id of the operation responsible for creating this context
+ */
+ uint64_t op_id;
+};
+
+
+/**
+ * DLL head for OverlayConnectContext DLL - to be used to clean up during shutdown
+ */
+static struct OverlayConnectContext *occq_head;
+
+/**
+ * DLL tail for OverlayConnectContext DLL
+ */
+static struct OverlayConnectContext *occq_tail;
+
+/**
+ * DLL head for RequectOverlayConnectContext DLL - to be used to clean up during
+ * shutdown
+ */
+static struct RemoteOverlayConnectCtx *roccq_head;
+
+/**
+ * DLL tail for RequectOverlayConnectContext DLL
+ */
+static struct RemoteOverlayConnectCtx *roccq_tail;
+
+
+/**
+ * Cleans up ForwardedOverlayConnectContext
+ *
+ * @param focc the ForwardedOverlayConnectContext to cleanup
+ */
+void
+GST_cleanup_focc (struct ForwardedOverlayConnectContext *focc)
+{
+ GNUNET_free_non_null (focc->orig_msg);
+ GNUNET_free (focc);
+}
+
+
+/**
+ * Timeout task for cancelling a forwarded overlay connect connect
+ *
+ * @param cls the ForwardedOverlayConnectContext
+ * @param tc the task context from the scheduler
+ */
+static void
+forwarded_overlay_connect_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext
+ *tc)
+{
+ struct ForwardedOperationContext *fopc = cls;
+ struct RegisteredHostContext *rhc;
+ struct ForwardedOverlayConnectContext *focc;
+
+ rhc = fopc->cls;
+ focc = rhc->focc_dll_head;
+ GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
+ GST_cleanup_focc (focc);
+ LOG_DEBUG ("Overlay linking between peers %u and %u failed\n", focc->peer1,
+ focc->peer2);
+ GST_forwarded_operation_timeout (cls, tc);
+ if (NULL != rhc->focc_dll_head)
+ GST_process_next_focc (rhc);
+}
+
+
+/**
+ * Callback to be called when forwarded overlay connection operation has a reply
+ * from the sub-controller successfull. We have to relay the reply msg back to
+ * the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the peer create success message
+ */
+static void
+forwarded_overlay_connect_listener (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct ForwardedOperationContext *fopc = cls;
+ struct RegisteredHostContext *rhc;
+ struct ForwardedOverlayConnectContext *focc;
+
+ rhc = fopc->cls;
+ GST_forwarded_operation_reply_relay (cls, msg);
+ focc = rhc->focc_dll_head;
+ GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head, rhc->focc_dll_tail, focc);
+ GST_cleanup_focc (focc);
+ if (NULL != rhc->focc_dll_head)
+ GST_process_next_focc (rhc);
+}
+
+
+/**
+ * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
+ *
+ * @param rhc the RegisteredHostContext
+ */
+void
+GST_process_next_focc (struct RegisteredHostContext *rhc)
+{
+ struct ForwardedOperationContext *fopc;
+ struct ForwardedOverlayConnectContext *focc;
+
+ focc = rhc->focc_dll_head;
+ GNUNET_assert (NULL != focc);
+ GNUNET_assert (RHC_OL_CONNECT == rhc->state);
+ fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (rhc->client);
+ fopc->client = rhc->client;
+ fopc->operation_id = focc->operation_id;
+ fopc->cls = rhc;
+ fopc->type = OP_OVERLAY_CONNECT;
+ fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (rhc->gateway->controller,
+ focc->operation_id, focc->orig_msg,
+ &forwarded_overlay_connect_listener,
+ fopc);
+ GNUNET_free (focc->orig_msg);
+ focc->orig_msg = NULL;
+ fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_overlay_connect_timeout,
+ fopc);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+}
+
+
+/**
+ * Cleanup overlay connect context structure
+ *
+ * @param occ the overlay connect context
+ */
+static void
+cleanup_occ (struct OverlayConnectContext *occ)
+{
+ LOG_DEBUG ("0x%llx: Cleaning up occ\n", occ->op_id);
+ GNUNET_free_non_null (occ->emsg);
+ GNUNET_free_non_null (occ->hello);
+ GNUNET_SERVER_client_drop (occ->client);
+ if (NULL != occ->opc)
+ GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
+ if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
+ GNUNET_SCHEDULER_cancel (occ->send_hello_task);
+ if (GNUNET_SCHEDULER_NO_TASK != occ->cleanup_task)
+ GNUNET_SCHEDULER_cancel (occ->cleanup_task);
+ if (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task)
+ GNUNET_SCHEDULER_cancel (occ->timeout_task);
+ if (NULL != occ->cgh_ch)
+ {
+ GST_cache_get_handle_done (occ->cgh_ch);
+ occ->peer->reference_cnt--;
+ }
+ if (NULL != occ->ghh)
+ GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
+ if (NULL != occ->ohh)
+ GNUNET_TRANSPORT_offer_hello_cancel (occ->ohh);
+ if (GNUNET_SCHEDULER_NO_TASK != occ->tcc.task)
+ GNUNET_SCHEDULER_cancel (occ->tcc.task);
+ if (NULL != occ->tcc.tch)
+ GNUNET_TRANSPORT_try_connect_cancel (occ->tcc.tch);
+ if (NULL != occ->cgh_p1th)
+ {
+ GST_cache_get_handle_done (occ->cgh_p1th);
+ occ->peer->reference_cnt--;
+ }
+ if (NULL != occ->tcc.cgh_th)
+ {
+ GST_cache_get_handle_done (occ->tcc.cgh_th);
+ GST_peer_list[occ->other_peer_id]->reference_cnt--;
+ }
+ if ((GNUNET_YES == occ->peer->destroy_flag) &&
+ (0 == occ->peer->reference_cnt))
+ GST_destroy_peer (occ->peer);
+ if ((NULL == occ->peer2_controller) &&
+ (GNUNET_YES == GST_peer_list[occ->other_peer_id]->destroy_flag) &&
+ (0 == GST_peer_list[occ->other_peer_id]->reference_cnt))
+ GST_destroy_peer (GST_peer_list[occ->other_peer_id]);
+ GNUNET_CONTAINER_DLL_remove (occq_head, occq_tail, occ);
+ GNUNET_free (occ);
+}
+
+
+/**
+ * Task for cleaing up overlay connect context structure
+ *
+ * @param cls the overlay connect context
+ * @param tc the task context
+ */
+static void
+do_cleanup_occ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct OverlayConnectContext *occ = cls;
+
+ occ->cleanup_task = GNUNET_SCHEDULER_NO_TASK;
+ cleanup_occ (occ);
+}
+
+
+/**
+ * Task which will be run when overlay connect request has been timed out
+ *
+ * @param cls the OverlayConnectContext
+ * @param tc the TaskContext
+ */
+static void
+timeout_overlay_connect (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct OverlayConnectContext *occ = cls;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
+ occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "0x%llx: Timeout while connecting peers %u and %u\n", occ->op_id,
+ occ->peer_id, occ->other_peer_id);
+ GST_send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
+ cleanup_occ (occ);
+}
+
+
+static void
+send_overlay_connect_success_msg (struct OverlayConnectContext *occ)
+{
+ struct GNUNET_TESTBED_ConnectionEventMessage *msg;
+
+ LOG_DEBUG ("0x%llx: Peers connected - Sending overlay connect success\n",
+ occ->op_id);
+ msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
+ msg->header.size =
+ htons (sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT);
+ msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
+ msg->peer1 = htonl (occ->peer_id);
+ msg->peer2 = htonl (occ->other_peer_id);
+ msg->operation_id = GNUNET_htonll (occ->op_id);
+ GST_queue_message (occ->client, &msg->header);
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param new_peer the peer that connected
+ */
+static void
+overlay_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer)
+{
+ struct OverlayConnectContext *occ = cls;
+ char *new_peer_str;
+ char *other_peer_str;
+
+ //LOG_DEBUG ("Overlay connect notify\n");
+ if (0 ==
+ memcmp (new_peer, &occ->peer_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ return;
+ new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
+ other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
+ if (0 !=
+ memcmp (new_peer, &occ->other_peer_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* LOG_DEBUG ("Unexpected peer %4s connected when expecting peer %4s\n", */
+ /* new_peer_str, other_peer_str); */
+ GNUNET_free (new_peer_str);
+ GNUNET_free (other_peer_str);
+ return;
+ }
+ GNUNET_free (new_peer_str);
+ LOG_DEBUG ("0x%llx: Peer %4s connected to peer %4s\n", occ->op_id,
+ other_peer_str, GNUNET_i2s (&occ->peer_identity));
+ GNUNET_free (other_peer_str);
+ if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
+ {
+ GNUNET_SCHEDULER_cancel (occ->send_hello_task);
+ occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
+ GNUNET_SCHEDULER_cancel (occ->timeout_task);
+ occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_SCHEDULER_NO_TASK != occ->tcc.task)
+ {
+ GNUNET_SCHEDULER_cancel (occ->tcc.task);
+ occ->tcc.task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free_non_null (occ->emsg);
+ occ->emsg = NULL;
+ send_overlay_connect_success_msg (occ);
+ occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
+ //cleanup_occ (occ);
+}
+
+
+/**
+ * Task to ask transport of a peer to connect to another peer
+ *
+ * @param cls the TryConnectContext
+ * @param tc the scheduler task context
+ */
+static void
+try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Callback to be called with result of the try connect request.
+ *
+ * @param cls the overlay connect context
+ * @param result GNUNET_OK if message was transmitted to transport service
+ * GNUNET_SYSERR if message was not transmitted to transport service
+ */
+static void
+try_connect_cb (void *cls, const int result)
+{
+ struct TryConnectContext *tcc = cls;
+
+ tcc->tch = NULL;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == tcc->task);
+ tcc->task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MILLISECONDS,
+ 500 + pow (2, ++tcc->retries)),
+ &try_connect_task, tcc);
+}
+
+
+/**
+ * Task to ask transport of a peer to connect to another peer
+ *
+ * @param cls the TryConnectContext
+ * @param tc the scheduler task context
+ */
+static void
+try_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct TryConnectContext *tcc = cls;
+
+ tcc->task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+ GNUNET_assert (NULL == tcc->tch);
+ GNUNET_assert (NULL != tcc->pid);
+ GNUNET_assert (NULL != tcc->th_);
+ GNUNET_assert (NULL != tcc->cgh_th);
+ LOG_DEBUG ("0x%llx: Trail %u to connect to peer %s\n", tcc->op_id,
+ tcc->retries, GNUNET_i2s (tcc->pid));
+ tcc->tch =
+ GNUNET_TRANSPORT_try_connect (tcc->th_, tcc->pid, &try_connect_cb, tcc);
+}
+
+
+/**
+ * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
+ * peer 1.
+ *
+ * @param cls the OverlayConnectContext
+ * @param tc the TaskContext from scheduler
+ */
+static void
+send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Task that is run when hello has been sent
+ *
+ * @param cls the overlay connect context
+ * @param tc the scheduler task context; if tc->reason =
+ * GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
+ * GNUNET_SCHEDULER_REASON_READ_READY is succeeded
+ */
+static void
+occ_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct OverlayConnectContext *occ = cls;
+
+ occ->ohh = NULL;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->send_hello_task);
+ if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
+ {
+ GNUNET_free_non_null (occ->emsg);
+ GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Timeout while offering HELLO to other peer",
+ occ->op_id);
+ occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
+ return;
+ }
+ if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
+ return;
+ GNUNET_free_non_null (occ->emsg);
+ GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while try connect", occ->op_id);
+ occ->tcc.pid = &occ->peer_identity;
+ occ->tcc.op_id = occ->op_id;
+ occ->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &occ->tcc);
+}
+
+
+/**
+ * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
+ * peer 1.
+ *
+ * @param cls the OverlayConnectContext
+ * @param tc the TaskContext from scheduler
+ */
+static void
+send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct OverlayConnectContext *occ = cls;
+ char *other_peer_str;
+
+ occ->send_hello_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+ GNUNET_assert (NULL != occ->hello);
+ other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
+ if (NULL != occ->peer2_controller)
+ {
+ struct GNUNET_TESTBED_RemoteOverlayConnectMessage *msg;
+ uint16_t msize;
+ uint16_t hello_size;
+
+ LOG_DEBUG ("0x%llx: Offering HELLO of %s (size: %u) to %s via Remote "
+ "Overlay Request\n", occ->op_id,
+ GNUNET_i2s (&occ->peer_identity), ntohs (occ->hello->size),
+ other_peer_str);
+ hello_size = ntohs (occ->hello->size);
+ msize =
+ sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) + hello_size;
+ msg = GNUNET_malloc (msize);
+ msg->header.type =
+ htons (GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT);
+ msg->header.size = htons (msize);
+ msg->peer = htonl (occ->other_peer_id);
+ msg->operation_id = GNUNET_htonll (occ->op_id);
+ (void) memcpy (&msg->peer_identity, &occ->peer_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ memcpy (msg->hello, occ->hello, hello_size);
+ GNUNET_TESTBED_queue_message_ (occ->peer2_controller, &msg->header);
+ }
+ else
+ {
+ LOG_DEBUG ("0x%llx: Offering HELLO of %s to %s\n", occ->op_id,
+ GNUNET_i2s (&occ->peer_identity), other_peer_str);
+ occ->ohh =
+ GNUNET_TRANSPORT_offer_hello (occ->tcc.th_, occ->hello,
+ occ_hello_sent_cb, occ);
+ if (NULL == occ->ohh)
+ {
+ GNUNET_break (0);
+ occ->send_hello_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MILLISECONDS,
+ 100 +
+ GNUNET_CRYPTO_random_u32
+ (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
+ &send_hello, occ);
+ }
+ }
+ GNUNET_free (other_peer_str);
+}
+
+
+/**
+ * Callback from cache with needed handles set
+ *
+ * @param cls the closure passed to GST_cache_get_handle_transport()
+ * @param ch the handle to CORE. Can be NULL if it is not requested
+ * @param th the handle to TRANSPORT. Can be NULL if it is not requested
+ * @param ignore_ peer identity which is ignored in this callback
+ */
+static void
+p2_transport_connect_cache_callback (void *cls, struct GNUNET_CORE_Handle *ch,
+ struct GNUNET_TRANSPORT_Handle *th,
+ const struct GNUNET_PeerIdentity *ignore_)
+{
+ struct OverlayConnectContext *occ = cls;
+
+ if (NULL == th)
+ {
+ GNUNET_asprintf (&occ->emsg, "0x%llx: Cannot connect to TRANSPORT of %s",
+ occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
+ GNUNET_SCHEDULER_cancel (occ->timeout_task);
+ occ->timeout_task =
+ GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
+ return;
+ }
+ occ->tcc.th_ = th;
+ GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while offering HELLO to %s",
+ occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
+ occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
+}
+
+
+/**
+ * Connects to the transport of the other peer if it is a local peer and
+ * schedules the send hello task
+ *
+ * @param occ the overlay connect context
+ */
+static void
+p2_transport_connect (struct OverlayConnectContext *occ)
+{
+ GNUNET_assert (NULL == occ->emsg);
+ GNUNET_assert (NULL != occ->hello);
+ GNUNET_assert (NULL == occ->ghh);
+ GNUNET_assert (NULL == occ->p1th_);
+ GNUNET_assert (NULL == occ->cgh_p1th);
+ if (NULL == occ->peer2_controller)
+ {
+ GST_peer_list[occ->other_peer_id]->reference_cnt++;
+ occ->tcc.cgh_th =
+ GST_cache_get_handle_transport (occ->other_peer_id,
+ GST_peer_list[occ->other_peer_id]->
+ details.local.cfg,
+ &p2_transport_connect_cache_callback,
+ occ, NULL, NULL, NULL);
+ return;
+ }
+ GNUNET_asprintf (&occ->emsg, "0x%llx: Timeout while offering HELLO to %s",
+ occ->op_id, GNUNET_i2s (&occ->other_peer_identity));
+ occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
+}
+
+
+/**
+ * Test for checking whether HELLO message is empty
+ *
+ * @param cls empty flag to set
+ * @param address the HELLO
+ * @param expiration expiration of the HELLO
+ * @return
+ */
+static int
+test_address (void *cls, const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
+{
+ int *empty = cls;
+
+ *empty = GNUNET_NO;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called whenever there is an update to the HELLO of peers in the
+ * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
+ * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
+ *
+ * @param cls closure
+ * @param hello our updated HELLO
+ */
+static void
+hello_update_cb (void *cls, const struct GNUNET_MessageHeader *hello)
+{
+ struct OverlayConnectContext *occ = cls;
+ int empty;
+ uint16_t msize;
+
+ msize = ntohs (hello->size);
+ empty = GNUNET_YES;
+ (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
+ hello, GNUNET_NO, &test_address,
+ &empty);
+ if (GNUNET_YES == empty)
+ {
+ LOG_DEBUG ("0x%llx: HELLO of %s is empty\n", occ->op_id,
+ GNUNET_i2s (&occ->peer_identity));
+ return;
+ }
+ LOG_DEBUG ("0x%llx: Received HELLO of %s\n", occ->op_id,
+ GNUNET_i2s (&occ->peer_identity));
+ occ->hello = GNUNET_malloc (msize);
+ GST_cache_add_hello (occ->peer_id, hello);
+ memcpy (occ->hello, hello, msize);
+ GNUNET_TRANSPORT_get_hello_cancel (occ->ghh);
+ occ->ghh = NULL;
+ GST_cache_get_handle_done (occ->cgh_p1th);
+ occ->peer->reference_cnt--;
+ occ->cgh_p1th = NULL;
+ occ->p1th_ = NULL;
+ GNUNET_free_non_null (occ->emsg);
+ occ->emsg = NULL;
+ p2_transport_connect (occ);
+}
+
+
+/**
+ * Callback from cache with needed handles set
+ *
+ * @param cls the closure passed to GST_cache_get_handle_transport()
+ * @param ch the handle to CORE. Can be NULL if it is not requested
+ * @param th the handle to TRANSPORT. Can be NULL if it is not requested
+ * @param ignore_ peer identity which is ignored in this callback
+ */
+static void
+p1_transport_connect_cache_callback (void *cls, struct GNUNET_CORE_Handle *ch,
+ struct GNUNET_TRANSPORT_Handle *th,
+ const struct GNUNET_PeerIdentity *ignore_)
+{
+ struct OverlayConnectContext *occ = cls;
+
+ GNUNET_free_non_null (occ->emsg);
+ occ->emsg = NULL;
+ if (NULL == th)
+ {
+ GNUNET_asprintf (&occ->emsg, "0x%llx: Cannot connect to TRANSPORT of %s",
+ occ->op_id, GNUNET_i2s (&occ->peer_identity));
+ GNUNET_SCHEDULER_cancel (occ->timeout_task);
+ occ->timeout_task =
+ GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
+ return;
+ }
+ GNUNET_assert (NULL == occ->p1th_);
+ GNUNET_assert (NULL != occ->cgh_p1th);
+ occ->p1th_ = th;
+ GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Timeout while acquiring HELLO of peer %4s",
+ occ->op_id, GNUNET_i2s (&occ->peer_identity));
+ occ->ghh = GNUNET_TRANSPORT_get_hello (occ->p1th_, &hello_update_cb, occ);
+}
+
+
+/**
+ * Callback from cache with needed handles set
+ *
+ * @param cls the closure passed to GST_cache_get_handle_transport()
+ * @param ch the handle to CORE. Can be NULL if it is not requested
+ * @param th the handle to TRANSPORT. Can be NULL if it is not requested
+ * @param my_identity the identity of our peer
+ */
+static void
+occ_cache_get_handle_core_cb (void *cls, struct GNUNET_CORE_Handle *ch,
+ struct GNUNET_TRANSPORT_Handle *th,
+ const struct GNUNET_PeerIdentity *my_identity)
+{
+ struct OverlayConnectContext *occ = cls;
+ const struct GNUNET_MessageHeader *hello;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
+ GNUNET_free_non_null (occ->emsg);
+ if ((NULL == ch) || (NULL == my_identity))
+ {
+ (void) GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Failed to connect to CORE of peer with"
+ "id: %u", occ->op_id, occ->peer_id);
+ GNUNET_SCHEDULER_cancel (occ->timeout_task);
+ occ->timeout_task =
+ GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
+ return;
+ }
+ //occ->ch_ = ch;
+ occ->emsg = NULL;
+ if (GNUNET_YES ==
+ GNUNET_CORE_is_peer_connected_sync (ch, &occ->other_peer_identity))
+ {
+ LOG_DEBUG ("0x%llx: Target peer already connected\n", occ->op_id);
+ GNUNET_SCHEDULER_cancel (occ->timeout_task);
+ occ->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ send_overlay_connect_success_msg (occ);
+ occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
+ return;
+ }
+ memcpy (&occ->peer_identity, my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ LOG_DEBUG ("0x%llx: Acquiring HELLO of peer %s\n", occ->op_id,
+ GNUNET_i2s (&occ->peer_identity));
+ /* Lookup for HELLO in hello cache */
+ if (NULL != (hello = GST_cache_lookup_hello (occ->peer_id)))
+ {
+ LOG_DEBUG ("0x%llx: HELLO of peer %s found in cache\n", occ->op_id,
+ GNUNET_i2s (&occ->peer_identity));
+ occ->hello = GNUNET_copy_message (hello);
+ p2_transport_connect (occ);
+ return;
+ }
+ GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Timeout while acquiring TRANSPORT of %s from cache",
+ occ->op_id, GNUNET_i2s (&occ->peer_identity));
+ occ->peer->reference_cnt++;
+ occ->cgh_p1th =
+ GST_cache_get_handle_transport (occ->peer_id,
+ occ->peer->details.local.cfg,
+ p1_transport_connect_cache_callback, occ,
+ NULL, NULL, NULL);
+ return;
+}
+
+
+/**
+ * Callback to be called when forwarded get peer config operation as part of
+ * overlay connect is successfull. Connection to Peer 1's core is made and is
+ * checked for new connection from peer 2
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the peer create success message
+ */
+static void
+overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct OverlayConnectContext *occ = cls;
+ const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
+
+ occ->opc = NULL;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task);
+ if (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION != ntohs (msg->type))
+ {
+ GNUNET_SCHEDULER_cancel (occ->timeout_task);
+ occ->timeout_task =
+ GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
+ }
+ cmsg =
+ (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
+ memcpy (&occ->other_peer_identity, &cmsg->peer_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ GNUNET_free_non_null (occ->emsg);
+ GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Timeout while connecting to CORE of peer with "
+ "id: %u", occ->op_id, occ->peer_id);
+ occ->peer->reference_cnt++;
+ occ->cgh_ch =
+ GST_cache_get_handle_core (occ->peer_id, occ->peer->details.local.cfg,
+ occ_cache_get_handle_core_cb, occ,
+ &occ->other_peer_identity,
+ &overlay_connect_notify, occ);
+ return;
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the RegisteredHostContext
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+registeredhost_registration_completion (void *cls, const char *emsg)
+{
+ struct RegisteredHostContext *rhc = cls;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ uint32_t peer2_host_id;
+
+ /* if (NULL != rhc->focc_dll_head) */
+ /* TESTBED_process_next_focc (rhc); */
+ peer2_host_id = GNUNET_TESTBED_host_get_id_ (rhc->reg_host);
+ GNUNET_assert (RHC_INIT == rhc->state);
+ GNUNET_assert (NULL == rhc->sub_op);
+ if ((NULL == rhc->gateway2) || ((peer2_host_id < GST_slave_list_size) /* Check if we have the needed config */
+ && (NULL != GST_slave_list[peer2_host_id])))
+ {
+ rhc->state = RHC_LINK;
+ cfg =
+ (NULL ==
+ rhc->gateway2) ? our_config : GST_slave_list[peer2_host_id]->cfg;
+ rhc->sub_op =
+ GNUNET_TESTBED_controller_link (rhc, rhc->gateway->controller,
+ rhc->reg_host, rhc->host, cfg,
+ GNUNET_NO);
+ return;
+ }
+ rhc->state = RHC_GET_CFG;
+ rhc->sub_op =
+ GNUNET_TESTBED_get_slave_config (rhc, rhc->gateway2->controller,
+ rhc->reg_host);
+}
+
+
+/**
+ * Iterator to match a registered host context
+ *
+ * @param cls pointer 2 pointer of RegisteredHostContext
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+reghost_match_iterator (void *cls, const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct RegisteredHostContext **rh = cls;
+ struct RegisteredHostContext *rh_val = value;
+
+ if ((rh_val->host == (*rh)->host) && (rh_val->reg_host == (*rh)->reg_host))
+ {
+ GNUNET_free (*rh);
+ *rh = rh_val;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Function to generate the hashcode corresponding to a RegisteredHostContext
+ *
+ * @param reg_host the host which is being registered in RegisteredHostContext
+ * @param host the host of the controller which has to connect to the above rhost
+ * @return the hashcode
+ */
+static struct GNUNET_HashCode
+hash_hosts (struct GNUNET_TESTBED_Host *reg_host,
+ struct GNUNET_TESTBED_Host *host)
+{
+ struct GNUNET_HashCode hash;
+ uint32_t host_ids[2];
+
+ host_ids[0] = GNUNET_TESTBED_host_get_id_ (reg_host);
+ host_ids[1] = GNUNET_TESTBED_host_get_id_ (host);
+ GNUNET_CRYPTO_hash (host_ids, sizeof (host_ids), &hash);
+ return hash;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OLCONNECT messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+void
+GST_handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
+ struct Peer *peer;
+ struct OverlayConnectContext *occ;
+ struct GNUNET_TESTBED_Controller *peer2_controller;
+ uint64_t operation_id;
+ uint32_t p1;
+ uint32_t p2;
+ uint32_t peer2_host_id;
+
+ if (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage) !=
+ ntohs (message->size))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
+ p1 = ntohl (msg->peer1);
+ p2 = ntohl (msg->peer2);
+ if ((p1 >= GST_peer_list_size) || (NULL == GST_peer_list[p1]))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ peer = GST_peer_list[p1];
+ peer2_host_id = ntohl (msg->peer2_host_id);
+ operation_id = GNUNET_ntohll (msg->operation_id);
+ LOG_DEBUG
+ ("Received overlay connect for peers %u and %u with op id: 0x%llx\n", p1,
+ p2, operation_id);
+ if (GNUNET_YES == peer->is_remote)
+ {
+ struct ForwardedOperationContext *fopc;
+ struct Route *route_to_peer2_host;
+ struct Route *route_to_peer1_host;
+
+ LOG_DEBUG ("0x%llx: Forwarding overlay connect\n", operation_id);
+ route_to_peer2_host = NULL;
+ route_to_peer1_host = NULL;
+ route_to_peer2_host = GST_find_dest_route (peer2_host_id);
+ if ((NULL != route_to_peer2_host) ||
+ (peer2_host_id == GST_context->host_id))
+ {
+ /* Peer 2 either below us OR with us */
+ route_to_peer1_host =
+ GST_find_dest_route (GST_peer_list[p1]->details.
+ remote.remote_host_id);
+ /* Because we get this message only if we know where peer 1 is */
+ GNUNET_assert (NULL != route_to_peer1_host);
+ if ((peer2_host_id == GST_context->host_id) ||
+ (route_to_peer2_host->dest != route_to_peer1_host->dest))
+ {
+ /* Peer2 is either with us OR peer1 and peer2 can be reached through
+ * different gateways */
+ struct GNUNET_HashCode hash;
+ struct RegisteredHostContext *rhc;
+ int skip_focc;
+
+ rhc = GNUNET_malloc (sizeof (struct RegisteredHostContext));
+ if (NULL != route_to_peer2_host)
+ rhc->reg_host = GST_host_list[route_to_peer2_host->dest];
+ else
+ rhc->reg_host = GST_host_list[GST_context->host_id];
+ rhc->host = GST_host_list[route_to_peer1_host->dest];
+ GNUNET_assert (NULL != rhc->reg_host);
+ GNUNET_assert (NULL != rhc->host);
+ rhc->gateway = peer->details.remote.slave;
+ rhc->gateway2 =
+ (NULL ==
+ route_to_peer2_host) ? NULL :
+ GST_slave_list[route_to_peer2_host->dest];
+ rhc->state = RHC_INIT;
+ GNUNET_SERVER_client_keep (client);
+ rhc->client = client;
+ hash = hash_hosts (rhc->reg_host, rhc->host);
+ skip_focc = GNUNET_NO;
+ if ((GNUNET_NO ==
+ GNUNET_CONTAINER_multihashmap_contains (peer->details.
+ remote.slave->reghost_map,
+ &hash)) ||
+ (GNUNET_SYSERR !=
+ GNUNET_CONTAINER_multihashmap_get_multiple (peer->details.remote.
+ slave->reghost_map,
+ &hash,
+ reghost_match_iterator,
+ &rhc)))
+ {
+ /* create and add a new registerd host context */
+ /* add the focc to its queue */
+ GNUNET_CONTAINER_multihashmap_put (peer->details.remote.
+ slave->reghost_map, &hash, rhc,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GNUNET_assert (NULL != GST_host_list[peer2_host_id]);
+ GST_queue_host_registration (peer->details.remote.slave,
+ registeredhost_registration_completion,
+ rhc, GST_host_list[peer2_host_id]);
+ }
+ else
+ {
+ /* rhc is now set to the existing one from the hash map by
+ * reghost_match_iterator() */
+ /* if queue is empty then ignore creating focc and proceed with
+ * normal forwarding */
+ if (RHC_OL_CONNECT == rhc->state)
+ skip_focc = GNUNET_YES;
+ }
+ if (GNUNET_NO == skip_focc)
+ {
+ struct ForwardedOverlayConnectContext *focc;
+
+ focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
+ focc->peer1 = p1;
+ focc->peer2 = p2;
+ focc->peer2_host_id = peer2_host_id;
+ focc->orig_msg = GNUNET_copy_message (message);
+ focc->operation_id = operation_id;
+ GNUNET_CONTAINER_DLL_insert_tail (rhc->focc_dll_head,
+ rhc->focc_dll_tail, focc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ }
+ }
+ fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+ GNUNET_SERVER_client_keep (client);
+ fopc->client = client;
+ fopc->operation_id = operation_id;
+ fopc->type = OP_OVERLAY_CONNECT;
+ fopc->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
+ slave->controller, operation_id,
+ message,
+ &GST_forwarded_operation_reply_relay,
+ fopc);
+ fopc->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &GST_forwarded_operation_timeout,
+ fopc);
+ GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ peer2_controller = NULL;
+ if ((p2 >= GST_peer_list_size) || (NULL == GST_peer_list[p2]))
+ {
+ if ((peer2_host_id >= GST_slave_list_size) ||
+ (NULL == GST_slave_list[peer2_host_id]))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "0x%llx: Configuration of peer2's controller missing for connecting peers"
+ "%u and %u\n", operation_id, p1, p2);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ peer2_controller = GST_slave_list[peer2_host_id]->controller;
+ if (NULL == peer2_controller)
+ {
+ GNUNET_break (0); /* What's going on? */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ }
+ else
+ {
+ if (GNUNET_YES == GST_peer_list[p2]->is_remote)
+ peer2_controller = GST_peer_list[p2]->details.remote.slave->controller;
+ }
+ occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
+ GNUNET_CONTAINER_DLL_insert_tail (occq_head, occq_tail, occ);
+ GNUNET_SERVER_client_keep (client);
+ occ->client = client;
+ occ->peer_id = p1;
+ occ->other_peer_id = p2;
+ occ->peer = GST_peer_list[p1];
+ occ->op_id = GNUNET_ntohll (msg->operation_id);
+ occ->peer2_controller = peer2_controller;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == occ->timeout_task);
+ occ->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_overlay_connect, occ);
+ /* Get the identity of the second peer */
+ if (NULL != occ->peer2_controller)
+ {
+ struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
+
+ cmsg.header.size =
+ htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
+ cmsg.header.type =
+ htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION);
+ cmsg.peer_id = msg->peer2;
+ cmsg.operation_id = msg->operation_id;
+ occ->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (occ->peer2_controller,
+ occ->op_id, &cmsg.header,
+ &overlay_connect_get_config,
+ occ);
+ GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Timeout while getting peer identity of peer "
+ "with id: %u", occ->op_id, occ->other_peer_id);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ GNUNET_TESTING_peer_get_identity (GST_peer_list[occ->other_peer_id]->
+ details.local.peer,
+ &occ->other_peer_identity);
+ GNUNET_asprintf (&occ->emsg,
+ "0x%llx: Timeout while connecting to CORE of peer with "
+ "id: %u", occ->op_id, occ->peer_id);
+ occ->peer->reference_cnt++;
+ occ->cgh_ch =
+ GST_cache_get_handle_core (occ->peer_id, occ->peer->details.local.cfg,
+ occ_cache_get_handle_core_cb, occ,
+ &occ->other_peer_identity,
+ &overlay_connect_notify, occ);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Function to cleanup RemoteOverlayConnectCtx and any associated tasks
+ * with it
+ *
+ * @param rocc the RemoteOverlayConnectCtx
+ */
+static void
+cleanup_rocc (struct RemoteOverlayConnectCtx *rocc)
+{
+ LOG_DEBUG ("0x%llx: Cleaning up rocc\n", rocc->op_id);
+ if (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id)
+ GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
+ if (GNUNET_SCHEDULER_NO_TASK != rocc->timeout_rocc_task_id)
+ GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
+ if (NULL != rocc->ohh)
+ GNUNET_TRANSPORT_offer_hello_cancel (rocc->ohh);
+ if (NULL != rocc->tcc.tch)
+ GNUNET_TRANSPORT_try_connect_cancel (rocc->tcc.tch);
+ if (GNUNET_SCHEDULER_NO_TASK != rocc->tcc.task)
+ GNUNET_SCHEDULER_cancel (rocc->tcc.task);
+ //GNUNET_TRANSPORT_disconnect (rocc->tcc.th_);
+ GST_cache_get_handle_done (rocc->tcc.cgh_th);
+ rocc->peer->reference_cnt--;
+ if ((GNUNET_YES == rocc->peer->destroy_flag) &&
+ (0 == rocc->peer->reference_cnt))
+ GST_destroy_peer (rocc->peer);
+ GNUNET_free_non_null (rocc->hello);
+ GNUNET_CONTAINER_DLL_remove (roccq_head, roccq_tail, rocc);
+ GNUNET_free (rocc);
+}
+
+
+/**
+ * Task to timeout rocc and cleanit up
+ *
+ * @param cls the RemoteOverlayConnectCtx
+ * @param tc the TaskContext from scheduler
+ */
+static void
+timeout_rocc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RemoteOverlayConnectCtx *rocc = cls;
+
+ GNUNET_assert (rocc->timeout_rocc_task_id != GNUNET_SCHEDULER_NO_TASK);
+ rocc->timeout_rocc_task_id = GNUNET_SCHEDULER_NO_TASK;
+ LOG_DEBUG ("0x%llx: rocc timed out\n", rocc->op_id);
+ cleanup_rocc (rocc);
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param new_peer the peer that connected
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+static void
+cache_transport_peer_connect_notify (void *cls,
+ const struct GNUNET_PeerIdentity *new_peer)
+{
+ struct RemoteOverlayConnectCtx *rocc = cls;
+
+ LOG_DEBUG ("0x%llx: Request Overlay connect notify\n", rocc->op_id);
+ GNUNET_assert (0 ==
+ memcmp (new_peer, &rocc->a_id,
+ sizeof (struct GNUNET_PeerIdentity)));
+ LOG_DEBUG ("0x%llx: Peer %4s connected\n", rocc->op_id,
+ GNUNET_i2s (&rocc->a_id));
+ cleanup_rocc (rocc);
+}
+
+
+/**
+ * Task to offer the HELLO message to the peer and ask it to connect to the peer
+ * whose identity is in RemoteOverlayConnectCtx
+ *
+ * @param cls the RemoteOverlayConnectCtx
+ * @param tc the TaskContext from scheduler
+ */
+static void
+attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Task that is run when hello has been sent
+ *
+ * @param cls the overlay connect context
+ * @param tc the scheduler task context; if tc->reason =
+ * GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
+ * GNUNET_SCHEDULER_REASON_READ_READY is succeeded
+ */
+static void
+rocc_hello_sent_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RemoteOverlayConnectCtx *rocc = cls;
+
+ rocc->ohh = NULL;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rocc->attempt_connect_task_id);
+ LOG_DEBUG ("0x%llx: HELLO of peer %4s sent to local peer with id: %u\n",
+ rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
+ if (GNUNET_SCHEDULER_REASON_TIMEOUT == tc->reason)
+ {
+ GNUNET_break (0);
+ rocc->attempt_connect_task_id =
+ GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
+ return;
+ }
+ if (GNUNET_SCHEDULER_REASON_READ_READY != tc->reason)
+ return;
+ rocc->tcc.task = GNUNET_SCHEDULER_add_now (&try_connect_task, &rocc->tcc);
+}
+
+
+/**
+ * Task to offer the HELLO message to the peer and ask it to connect to the peer
+ * whose identity is in RemoteOverlayConnectCtx
+ *
+ * @param cls the RemoteOverlayConnectCtx
+ * @param tc the TaskContext from scheduler
+ */
+static void
+attempt_connect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RemoteOverlayConnectCtx *rocc = cls;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rocc->attempt_connect_task_id);
+ rocc->attempt_connect_task_id = GNUNET_SCHEDULER_NO_TASK;
+ LOG_DEBUG ("0x%llx: Offering HELLO of peer %4s to local peer with id: %u\n",
+ rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
+ rocc->ohh =
+ GNUNET_TRANSPORT_offer_hello (rocc->tcc.th_, rocc->hello,
+ rocc_hello_sent_cb, rocc);
+ if (NULL == rocc->ohh)
+ rocc->attempt_connect_task_id =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MILLISECONDS,
+ 100 +
+ GNUNET_CRYPTO_random_u32
+ (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
+ &attempt_connect_task, rocc);
+}
+
+
+/**
+ * Callback from cache with needed handles set
+ *
+ * @param cls the closure passed to GST_cache_get_handle_transport()
+ * @param ch the handle to CORE. Can be NULL if it is not requested
+ * @param th the handle to TRANSPORT. Can be NULL if it is not requested
+ * @param ignore_ peer identity which is ignored in this callback
+ */
+static void
+rocc_cache_get_handle_transport_cb (void *cls, struct GNUNET_CORE_Handle *ch,
+ struct GNUNET_TRANSPORT_Handle *th,
+ const struct GNUNET_PeerIdentity *ignore_)
+{
+ struct RemoteOverlayConnectCtx *rocc = cls;
+
+ if (NULL == th)
+ {
+ rocc->timeout_rocc_task_id =
+ GNUNET_SCHEDULER_add_now (&timeout_rocc_task, rocc);
+ return;
+ }
+ rocc->tcc.th_ = th;
+ rocc->tcc.pid = &rocc->a_id;
+ if (GNUNET_YES ==
+ GNUNET_TRANSPORT_check_neighbour_connected (rocc->tcc.th_, rocc->tcc.pid))
+ {
+ LOG_DEBUG ("0x%llx: Target peer %4s already connected to local peer: %u\n",
+ rocc->op_id, GNUNET_i2s (&rocc->a_id), rocc->peer->id);
+ cleanup_rocc (rocc);
+ return;
+ }
+ rocc->attempt_connect_task_id =
+ GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+void
+GST_handle_remote_overlay_connect (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_RemoteOverlayConnectMessage *msg;
+ struct RemoteOverlayConnectCtx *rocc;
+ struct Peer *peer;
+ uint32_t peer_id;
+ uint16_t msize;
+ uint16_t hsize;
+
+ msize = ntohs (message->size);
+ if (sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) >= msize)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msg = (const struct GNUNET_TESTBED_RemoteOverlayConnectMessage *) message;
+ if ((NULL == msg->hello) ||
+ (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type)))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ hsize = ntohs (msg->hello->size);
+ if ((sizeof (struct GNUNET_TESTBED_RemoteOverlayConnectMessage) + hsize) !=
+ msize)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ peer_id = ntohl (msg->peer);
+ if ((peer_id >= GST_peer_list_size) ||
+ (NULL == (peer = GST_peer_list[peer_id])))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (GNUNET_YES == peer->is_remote)
+ {
+ struct GNUNET_MessageHeader *msg2;
+
+ msg2 = GNUNET_copy_message (message);
+ GNUNET_TESTBED_queue_message_ (peer->details.remote.slave->controller,
+ msg2);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ rocc = GNUNET_malloc (sizeof (struct RemoteOverlayConnectCtx));
+ rocc->op_id = GNUNET_ntohll (msg->operation_id);
+ GNUNET_CONTAINER_DLL_insert_tail (roccq_head, roccq_tail, rocc);
+ memcpy (&rocc->a_id, &msg->peer_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ LOG_DEBUG ("Received request for overlay connection with op_id: 0x%llx "
+ "from local peer %u to peer %4s with hello size: %u\n",
+ rocc->op_id, peer_id, GNUNET_i2s (&rocc->a_id), hsize);
+ rocc->peer = peer;
+ rocc->peer->reference_cnt++;
+ rocc->hello = GNUNET_malloc (hsize);
+ memcpy (rocc->hello, msg->hello, hsize);
+ rocc->tcc.cgh_th =
+ GST_cache_get_handle_transport (peer_id, rocc->peer->details.local.cfg,
+ &rocc_cache_get_handle_transport_cb, rocc,
+ &rocc->a_id,
+ &cache_transport_peer_connect_notify,
+ rocc);
+ rocc->timeout_rocc_task_id =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_rocc_task, rocc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Clears all pending overlay connect contexts in queue
+ */
+void
+GST_free_occq ()
+{
+ struct OverlayConnectContext *occ;
+
+ while (NULL != (occ = occq_head))
+ cleanup_occ (occ);
+}
+
+
+/**
+ * Clears all pending remote overlay connect contexts in queue
+ */
+void
+GST_free_roccq ()
+{
+ struct RemoteOverlayConnectCtx *rocc;
+
+ while (NULL != (rocc = roccq_head))
+ cleanup_rocc (rocc);
+}
diff --git a/src/testbed/gnunet-testbed-profiler.c b/src/testbed/gnunet-testbed-profiler.c
new file mode 100644
index 0000000..ebb82df
--- /dev/null
+++ b/src/testbed/gnunet-testbed-profiler.c
@@ -0,0 +1,283 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011, 2012 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 3, 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 testbed/gnunet-testbed-profiler.c
+ * @brief Profiling driver for the testbed.
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "testbed_api_hosts.h"
+
+/**
+ * Generic loggins shorthand
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+
+/**
+ * Handle to global configuration
+ */
+struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Peer linking - topology operation
+ */
+struct GNUNET_TESTBED_Operation *topology_op;
+
+/**
+ * Abort task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * Shutdown task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+/**
+ * Global event mask for all testbed events
+ */
+uint64_t event_mask;
+
+/**
+ * Number of peers to be started by the profiler
+ */
+static unsigned int num_peers;
+
+/**
+ * Number of timeout failures to tolerate
+ */
+static unsigned int num_cont_fails;
+
+/**
+ * Continuous failures during overlay connect operations
+ */
+static unsigned int cont_fails;
+
+/**
+ * Links which are successfully established
+ */
+static unsigned int established_links;
+
+/**
+ * Links which are not successfully established
+ */
+static unsigned int failed_links;
+
+/**
+ * Global testing status
+ */
+static int result;
+
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ if (NULL != cfg)
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */
+}
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Aborting\n");
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ result = GNUNET_SYSERR;
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+}
+
+
+/**
+ * Function to print summary about how many overlay links we have made and how
+ * many failed
+ */
+static void
+print_overlay_links_summary ()
+{
+ static int printed_already;
+
+ if (GNUNET_YES == printed_already)
+ return;
+ printed_already = GNUNET_YES;
+ printf ("%u links succeeded\n", established_links);
+ printf ("%u links failed due to timeouts\n", failed_links);
+}
+
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+ const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+ /* Control reaches here when a peer linking operation fails */
+ if (NULL != event->details.operation_finished.emsg)
+ {
+ printf ("F");
+ fflush (stdout);
+ failed_links++;
+ if (++cont_fails > num_cont_fails)
+ {
+ printf ("\nAborting due to very high failure rate\n");
+ print_overlay_links_summary ();
+ GNUNET_SCHEDULER_cancel (abort_task);
+ abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
+ return;
+ }
+ }
+ break;
+ case GNUNET_TESTBED_ET_CONNECT:
+ {
+ if (0 != cont_fails)
+ cont_fails--;
+ if (0 == established_links)
+ printf ("Establishing links. Please wait\n");
+ printf (".");
+ fflush (stdout);
+ established_links++;
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_run (void *cls, unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers)
+{
+ result = GNUNET_OK;
+ fprintf (stdout, "\n");
+ print_overlay_links_summary ();
+ fprintf (stdout, "Testbed running, waiting for keystroke to shut down\n");
+ fflush (stdout);
+ (void) getc (stdin);
+ fprintf (stdout, "Shutting down. Please wait\n");
+ fflush (stdout);
+ shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+}
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param config configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ if (NULL == args[0])
+ {
+ fprintf (stderr, _("No hosts-file specified on command line\n"));
+ return;
+ }
+ if (0 == num_peers)
+ {
+ result = GNUNET_OK;
+ return;
+ }
+ cfg = GNUNET_CONFIGURATION_dup (config);
+ event_mask = 0;
+ event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ GNUNET_TESTBED_run (args[0], cfg, num_peers, event_mask, controller_event_cb,
+ NULL, &test_run, NULL);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function.
+ *
+ * @return 0 on success
+ */
+int
+main (int argc, char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'p', "num-peers", "COUNT",
+ gettext_noop ("create COUNT number of peers"),
+ GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers},
+ {'e', "num-errors", "COUNT",
+ gettext_noop ("tolerate COUNT number of continious timeout failures"),
+ GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_cont_fails},
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+ return 2;
+ result = GNUNET_SYSERR;
+ ret =
+ GNUNET_PROGRAM_run (argc, argv,
+ "gnunet-testbed-profiler [OPTIONS] hosts-file",
+ _("Profiler for testbed"), options, &run, NULL);
+ GNUNET_free ((void *) argv);
+ if (GNUNET_OK != ret)
+ return ret;
+ if (GNUNET_OK != result)
+ return 1;
+ return 0;
+}
diff --git a/src/testbed/gnunet_mpi_test.c b/src/testbed/gnunet_mpi_test.c
new file mode 100644
index 0000000..fded9e2
--- /dev/null
+++ b/src/testbed/gnunet_mpi_test.c
@@ -0,0 +1,107 @@
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include <mpi.h>
+
+/**
+ * Generic logging shorthand
+ */
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "gnunet-mpi-test", __VA_ARGS__)
+
+int
+main (int argc, char *argv[])
+{
+ char *msg;
+ char *filename;
+ char **argv2;
+ struct GNUNET_OS_Process *proc;
+ unsigned long code;
+ pid_t pid;
+ enum GNUNET_OS_ProcessStatusType proc_status;
+ int ntasks;
+ int rank;
+ int msg_size;
+ int ret;
+ unsigned int cnt;
+
+ ret = GNUNET_SYSERR;
+ if (argc < 2)
+ {
+ printf ("Need arguments: gnunet-mpi-test <cmd> <cmd_args>");
+ return 1;
+ }
+ if (MPI_SUCCESS != MPI_Init (&argc, &argv))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ if (MPI_SUCCESS != MPI_Comm_size (MPI_COMM_WORLD, &ntasks))
+ {
+ GNUNET_break (0);
+ goto finalize;
+ }
+ if (MPI_SUCCESS != MPI_Comm_rank (MPI_COMM_WORLD, &rank))
+ {
+ GNUNET_break (0);
+ goto finalize;
+ }
+ pid = getpid ();
+ (void) GNUNET_asprintf (&filename, "%d-%d.mpiout", (int) pid, rank);
+ msg_size = GNUNET_asprintf (&msg, "My rank is: %d\n", rank);
+ printf ("%s", msg);
+ if (msg_size ==
+ GNUNET_DISK_fn_write (filename, msg, msg_size,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_GROUP_READ |
+ GNUNET_DISK_PERM_USER_WRITE |
+ GNUNET_DISK_PERM_GROUP_WRITE))
+ ret = GNUNET_OK;
+ GNUNET_free (filename);
+ GNUNET_free (msg);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break (0);
+ goto finalize;
+ }
+
+ ret = GNUNET_SYSERR;
+ argv2 = GNUNET_malloc (sizeof (char *) * (argc));
+ for (cnt = 1; cnt < argc; cnt++)
+ argv2[cnt - 1] = argv[cnt];
+ proc =
+ GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL,
+ NULL, argv2[0], argv2);
+ if (NULL == proc)
+ {
+ printf ("Cannot exec\n");
+ GNUNET_free (argv2);
+ goto finalize;
+ }
+ do
+ {
+ (void) sleep (1);
+ ret = GNUNET_OS_process_status (proc, &proc_status, &code);
+ }
+ while (GNUNET_NO == ret);
+ GNUNET_free (argv2);
+ GNUNET_assert (GNUNET_NO != ret);
+ if (GNUNET_OK == ret)
+ {
+ if (0 != code)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Child terminated abnormally\n");
+ ret = GNUNET_SYSERR;
+ GNUNET_break (0);
+ goto finalize;
+ }
+ }
+ else
+ GNUNET_break (0);
+
+finalize:
+ (void) MPI_Finalize ();
+ if (GNUNET_OK == ret)
+ return 0;
+ printf ("Something went wrong\n");
+ return 1;
+}
diff --git a/src/testbed/ll_master.c b/src/testbed/ll_master.c
new file mode 100644
index 0000000..98cef42
--- /dev/null
+++ b/src/testbed/ll_master.c
@@ -0,0 +1,92 @@
+/*
+ This file is part of GNUnet
+ (C) 2012 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 3, 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 testbed/ll_master.c
+ * @brief The load level master. Creates child processes through LoadLeveler
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include <llapi.h>
+
+/**
+ * LL job information
+ */
+static struct LL_job job_info;
+
+/**
+ * Exit status
+ */
+static int status;
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ int ret;
+
+ if (NULL == args[0])
+ {
+ fprintf (stderr, _("Job command file not given. Exiting\n"));
+ return;
+ }
+ ret = llsubmit (args[0], NULL, //char *monitor_program,
+ NULL, //char *monitor_arg,
+ &job_info, LL_JOB_VERSION);
+ if (0 != ret)
+ return;
+ status = GNUNET_OK;
+}
+
+
+/**
+ * Main function
+ *
+ * @param argc the number of command line arguments
+ * @param argv command line arg array
+ * @return return code
+ */
+int
+main (int argc, char **argv)
+{
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ status = GNUNET_SYSERR;
+ ret =
+ GNUNET_PROGRAM_run (argc, argv, "ll-master",
+ "LoadLeveler master process for starting child processes",
+ options, &run, NULL);
+ if (GNUNET_OK != ret)
+ return 1;
+ return (GNUNET_OK == status) ? 0 : 1;
+}
diff --git a/src/testbed/ll_monitor.c b/src/testbed/ll_monitor.c
new file mode 100644
index 0000000..3a43b49
--- /dev/null
+++ b/src/testbed/ll_monitor.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of GNUnet
+ (C) 2012 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 3, 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 testbed/ll_monitor.c
+ * @brief The load level monitor process. This is called whenever a job event
+ * happens. This file is called with the following syntax:
+ * "monitor_program job_id user_arg state exit_status"
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include <llapi.h>
+
+
+/**
+ * Main function
+ *
+ * @param argc the number of command line arguments
+ * @param argv command line arg array
+ * @return return code
+ */
+int
+main (int argc, char **argv)
+{
+ char *job_id;
+ char *user_arg;
+ char *state;
+ char *exit_status;
+ char *outfile;
+ FILE *out;
+
+ if (5 != argc)
+ {
+ fprintf (stderr, "Invalid number of arguments\n");
+ return 1;
+ }
+ job_id = argv[1];
+ user_arg = argv[2];
+ state = argv[3];
+ exit_status = argv[4];
+ PRINTF ("Job id: %s\n", job_id);
+ PRINTF ("\t User arg: %s \n", user_arg);
+ PRINTF ("\t Job state: %s \n", state);
+ PRINTF ("\t Exit status: %s \n", exit_status);
+
+ if (-1 == asprintf (&outfile, "job-%s.status", job_id))
+ return 1;
+ out = fopen (outfile, "a");
+ if (NULL == out)
+ return 1;
+ fprintf (out, "Job id: %s\n", job_id);
+ fprintf (out, "\t User arg: %s \n", user_arg);
+ fprintf (out, "\t Job state: %s \n", state);
+ fprintf (out, "\t Exit status: %s \n", exit_status);
+ fclose (out);
+ return 0;
+}
diff --git a/src/testbed/overlay_topology.txt b/src/testbed/overlay_topology.txt
new file mode 100644
index 0000000..420dbb6
--- /dev/null
+++ b/src/testbed/overlay_topology.txt
@@ -0,0 +1,5 @@
+
+1:2|3
+3:4| 0| 1
+2: 3|1|0
+0: 2
diff --git a/src/testbed/sample.job b/src/testbed/sample.job
new file mode 100755
index 0000000..da3ee47
--- /dev/null
+++ b/src/testbed/sample.job
@@ -0,0 +1,16 @@
+#!/bin/bash
+# This job command file is called job.cmd
+#@ job_type = parallel
+#@ class = general
+#@ node = 1
+#@ output = job$(jobid).out
+#@ error = job$(jobid).err
+#@ total_tasks=16
+#@ wall_clock_limit = 0:0:1
+#@ network.MPI = sn_all,not_shared,us
+##@ ... other LoadLeveler keywords (see below)
+#@ notification = always
+#@ notify_user = totakura@in.tum.de
+#@ queue
+
+#@ executable = /bin/bash
diff --git a/src/testbed/sample_hosts.txt b/src/testbed/sample_hosts.txt
new file mode 100644
index 0000000..5b66169
--- /dev/null
+++ b/src/testbed/sample_hosts.txt
@@ -0,0 +1,15 @@
+totakura@192.168.0.1:22
+totakura@192.168.0.2:22
+totakura@192.168.0.3:22
+totakura@192.168.0.4:22
+totakura@192.168.0.5:22
+totakura@192.168.0.6:22
+totakura@192.168.0.7:22
+totakura@192.168.0.8:22
+totakura@192.168.0.9:22
+totakura@192.168.0.10:22
+totakura@192.168.0.11:22
+totakura@192.168.0.12:22
+totakura@192.168.0.13:22
+totakura@192.168.0.14:22
+totakura@192.168.0.15:22
diff --git a/src/testbed/test_gnunet_helper_testbed.c b/src/testbed/test_gnunet_helper_testbed.c
new file mode 100644
index 0000000..db889c1
--- /dev/null
+++ b/src/testbed/test_gnunet_helper_testbed.c
@@ -0,0 +1,249 @@
+/*
+ This file is part of GNUnet
+ (C) 2012 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 3, 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 testbed/test_gnunet_helper_testbed.c
+ * @brief Testcase for testing gnunet-helper-testbed.c
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include <zlib.h>
+
+#include "testbed_api.h"
+#include "testbed_helper.h"
+#include "testbed_api_hosts.h"
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+
+/**
+ * Handle to the helper process
+ */
+static struct GNUNET_HELPER_Handle *helper;
+
+/**
+ * Message to helper
+ */
+static struct GNUNET_TESTBED_HelperInit *msg;
+
+/**
+ * Message send handle
+ */
+static struct GNUNET_HELPER_SendHandle *shandle;
+
+/**
+ * Abort task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * Shutdown task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+/**
+ * Configuratin handler
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Global testing status
+ */
+static int result;
+
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ GNUNET_HELPER_stop (helper);
+ GNUNET_free_non_null (msg);
+ if (NULL != cfg)
+ GNUNET_CONFIGURATION_destroy (cfg);
+}
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
+ result = GNUNET_SYSERR;
+ if (NULL != shandle)
+ GNUNET_HELPER_send_cancel (shandle);
+ if (GNUNET_SCHEDULER_NO_TASK == shutdown_task)
+ shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+}
+
+
+/**
+ * Continuation function.
+ *
+ * @param cls closure
+ * @param result GNUNET_OK on success,
+ * GNUNET_NO if helper process died
+ * GNUNET_SYSERR during GNUNET_HELPER_stop
+ */
+static void
+cont_cb (void *cls, int result)
+{
+ shandle = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Message sent\n");
+ GNUNET_assert (GNUNET_OK == result);
+}
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * Do not call GNUNET_SERVER_mst_destroy in callback
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
+ */
+static int
+mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message)
+{
+ const struct GNUNET_TESTBED_HelperReply *msg;
+ char *config;
+ uLongf config_size;
+ uLongf xconfig_size;
+
+ msg = (const struct GNUNET_TESTBED_HelperReply *) message;
+ config_size = 0;
+ xconfig_size = 0;
+ GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) <
+ ntohs (msg->header.size));
+ GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
+ ntohs (msg->header.type));
+ config_size = (uLongf) ntohs (msg->config_size);
+ xconfig_size =
+ (uLongf) (ntohs (msg->header.size) -
+ sizeof (struct GNUNET_TESTBED_HelperReply));
+ config = GNUNET_malloc (config_size);
+ GNUNET_assert (Z_OK ==
+ uncompress ((Bytef *) config, &config_size,
+ (const Bytef *) &msg[1], xconfig_size));
+ GNUNET_free (config);
+ if (GNUNET_SCHEDULER_NO_TASK == shutdown_task)
+ shutdown_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 1),
+ &do_shutdown, NULL);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Callback that will be called when the helper process dies. This is not called
+ * when the helper process is stoped using GNUNET_HELPER_stop()
+ *
+ * @param cls the closure from GNUNET_HELPER_start()
+ */
+static void
+exp_cb (void *cls)
+{
+ helper = NULL;
+ result = GNUNET_SYSERR;
+}
+
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg2)
+{
+ static char *const binary_argv[] = {
+ "gnunet-helper-testbed",
+ NULL
+ };
+ const char *controller_name = "127.0.0.1";
+
+ helper =
+ GNUNET_HELPER_start (GNUNET_YES, "gnunet-helper-testbed", binary_argv,
+ &mst_cb, &exp_cb, NULL);
+ GNUNET_assert (NULL != helper);
+ cfg = GNUNET_CONFIGURATION_dup (cfg2);
+ msg = GNUNET_TESTBED_create_helper_init_msg_ (controller_name, NULL, cfg);
+ shandle =
+ GNUNET_HELPER_send (helper, &msg->header, GNUNET_NO, &cont_cb, NULL);
+ GNUNET_assert (NULL != shandle);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES, 1), &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function
+ *
+ * @param argc the number of command line arguments
+ * @param argv command line arg array
+ * @return return code
+ */
+int
+main (int argc, char **argv)
+{
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ result = GNUNET_OK;
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run (argc, argv, "test_gnunet_helper_testbed",
+ "Testcase for testing gnunet-helper-testbed.c",
+ options, &run, NULL))
+ return 1;
+ return (GNUNET_OK == result) ? 0 : 1;
+}
+
+/* end of test_gnunet_helper_testbed.c */
diff --git a/src/testbed/test_testbed_api.c b/src/testbed/test_testbed_api.c
new file mode 100644
index 0000000..c5c4486
--- /dev/null
+++ b/src/testbed/test_testbed_api.c
@@ -0,0 +1,464 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/test_testbed_api.c
+ * @brief testcases for the testbed api
+ * @author Sree Harsha Totakura
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dht_service.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_testbed_service.h"
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Relative time seconds shorthand
+ */
+#define TIME_REL_SECS(sec) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
+
+/**
+ * Our localhost
+ */
+static struct GNUNET_TESTBED_Host *host;
+
+/**
+ * The controller process
+ */
+static struct GNUNET_TESTBED_ControllerProc *cp;
+
+/**
+ * The controller handle
+ */
+static struct GNUNET_TESTBED_Controller *controller;
+
+/**
+ * A neighbouring host
+ */
+static struct GNUNET_TESTBED_Host *neighbour;
+
+/**
+ * Handle for neighbour registration
+ */
+static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
+
+/**
+ * Handle for a peer
+ */
+static struct GNUNET_TESTBED_Peer *peer;
+
+/**
+ * Handle to configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to operation
+ */
+static struct GNUNET_TESTBED_Operation *operation;
+
+/**
+ * Handle to peer's DHT service
+ */
+static struct GNUNET_DHT_Handle *dht_handle;
+
+/**
+ * Abort task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * The testing result
+ */
+static int result;
+
+
+/**
+ * Enumeration of sub testcases
+ */
+enum Test
+{
+ /**
+ * Test cases which are not covered by the below ones
+ */
+ OTHER,
+
+ /**
+ * Test where we get a peer config from controller
+ */
+ PEER_GETCONFIG,
+
+ /**
+ * Test where we connect to a service running on the peer
+ */
+ PEER_SERVICE_CONNECT,
+
+ /**
+ * Test where we get a peer's identity from controller
+ */
+ PEER_DESTROY,
+};
+
+/**
+ * Testing status
+ */
+static enum Test sub_test;
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down...\n");
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ if (NULL != reg_handle)
+ GNUNET_TESTBED_cancel_registration (reg_handle);
+ GNUNET_TESTBED_controller_disconnect (controller);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ if (NULL != cp)
+ GNUNET_TESTBED_controller_stop (cp);
+ GNUNET_TESTBED_host_destroy (neighbour);
+ GNUNET_TESTBED_host_destroy (host);
+}
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ do_shutdown (cls, tc);
+}
+
+
+/**
+ * Adapter function called to establish a connection to
+ * a service.
+ *
+ * @param cls closure
+ * @param cfg configuration of the peer to connect to; will be available until
+ * GNUNET_TESTBED_operation_done() is called on the operation returned
+ * from GNUNET_TESTBED_service_connect()
+ * @return service handle to return in 'op_result', NULL on error
+ */
+static void *
+dht_connect_adapter (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ GNUNET_assert (NULL == cls);
+ GNUNET_assert (OTHER == sub_test);
+ sub_test = PEER_SERVICE_CONNECT;
+ dht_handle = GNUNET_DHT_connect (cfg, 10);
+ return dht_handle;
+}
+
+
+/**
+ * Adapter function called to destroy a connection to
+ * a service.
+ *
+ * @param cls closure
+ * @param op_result service handle returned from the connect adapter
+ */
+static void
+dht_disconnect_adapter (void *cls, void *op_result)
+{
+ GNUNET_assert (NULL != op_result);
+ GNUNET_assert (op_result == dht_handle);
+ GNUNET_DHT_disconnect (dht_handle);
+ dht_handle = NULL;
+ GNUNET_assert (PEER_SERVICE_CONNECT == sub_test);
+ GNUNET_assert (NULL != operation);
+ operation = GNUNET_TESTBED_peer_stop (peer, NULL, NULL);
+ GNUNET_assert (NULL != operation);
+}
+
+
+/**
+ * Callback to be called when a service connect operation is completed
+ *
+ * @param cls the callback closure from functions generating an operation
+ * @param op the operation that has been finished
+ * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+service_connect_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
+ void *ca_result, const char *emsg)
+{
+ switch (sub_test)
+ {
+ case PEER_SERVICE_CONNECT:
+ GNUNET_assert (operation == op);
+ GNUNET_assert (NULL == emsg);
+ GNUNET_assert (NULL == cls);
+ GNUNET_assert (ca_result == dht_handle);
+ GNUNET_TESTBED_operation_done (operation); /* This results in call to
+ * disconnect adapter */
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+
+/**
+ * Callback to be called when the requested peer information is available
+ *
+ * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
+ * @param op the operation this callback corresponds to
+ * @param pinfo the result; will be NULL if the operation has failed
+ * @param emsg error message if the operation has failed; will be NULL if the
+ * operation is successfull
+ */
+static void
+peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
+ const struct GNUNET_TESTBED_PeerInformation *pinfo,
+ const char *emsg)
+{
+ switch (sub_test)
+ {
+ case PEER_GETCONFIG:
+ GNUNET_assert (NULL != pinfo);
+ GNUNET_assert (NULL == emsg);
+ GNUNET_assert (NULL == cb_cls);
+ GNUNET_assert (operation == op);
+ GNUNET_assert (GNUNET_TESTBED_PIT_CONFIGURATION == pinfo->pit);
+ GNUNET_assert (NULL != pinfo->result.cfg);
+ sub_test = PEER_DESTROY;
+ GNUNET_TESTBED_operation_done (operation);
+ operation = GNUNET_TESTBED_peer_destroy (peer);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Signature of the event handler function called by the
+ * respective event controller.
+ *
+ * @param cls closure
+ * @param event information about the event
+ */
+static void
+controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+ switch (sub_test)
+ {
+ case PEER_DESTROY:
+ GNUNET_assert (event->details.operation_finished.operation == operation);
+ GNUNET_assert (NULL == event->details.operation_finished.op_cls);
+ GNUNET_assert (NULL == event->details.operation_finished.emsg);
+ GNUNET_assert (NULL == event->details.operation_finished.generic);
+ GNUNET_TESTBED_operation_done (operation);
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ break;
+ case PEER_SERVICE_CONNECT:
+ GNUNET_assert (event->details.operation_finished.operation == operation);
+ GNUNET_assert (NULL == event->details.operation_finished.op_cls);
+ GNUNET_assert (NULL == event->details.operation_finished.emsg);
+ GNUNET_assert (NULL != dht_handle);
+ GNUNET_assert (event->details.operation_finished.generic == dht_handle);
+ break;
+ default:
+ GNUNET_assert (0);
+ break;
+ }
+ break;
+ case GNUNET_TESTBED_ET_PEER_START:
+ GNUNET_assert (event->details.peer_start.host == host);
+ GNUNET_assert (event->details.peer_start.peer == peer);
+ GNUNET_assert (OTHER == sub_test);
+ GNUNET_TESTBED_operation_done (operation);
+ operation =
+ GNUNET_TESTBED_service_connect (NULL, peer, "dht",
+ &service_connect_comp_cb, NULL,
+ &dht_connect_adapter,
+ &dht_disconnect_adapter, NULL);
+ GNUNET_assert (NULL != operation);
+ break;
+ case GNUNET_TESTBED_ET_PEER_STOP:
+ GNUNET_assert (event->details.peer_stop.peer == peer);
+ GNUNET_assert (PEER_SERVICE_CONNECT == sub_test);
+ result = GNUNET_YES;
+ sub_test = PEER_GETCONFIG;
+ GNUNET_TESTBED_operation_done (operation);
+ operation =
+ GNUNET_TESTBED_peer_get_information (peer,
+ GNUNET_TESTBED_PIT_CONFIGURATION,
+ &peerinfo_cb, NULL);
+ break;
+ default:
+ GNUNET_assert (0); /* We should never reach this state */
+ }
+}
+
+
+/**
+ * Functions of this signature are called when a peer has been successfully
+ * created
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_create()
+ * @param peer the handle for the created peer; NULL on any error during
+ * creation
+ * @param emsg NULL if peer is not NULL; else MAY contain the error description
+ */
+static void
+peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
+{
+ struct GNUNET_TESTBED_Peer **peer_ptr;
+
+ peer_ptr = cls;
+ GNUNET_assert (NULL != peer);
+ GNUNET_assert (NULL != peer_ptr);
+ *peer_ptr = peer;
+ GNUNET_TESTBED_operation_done (operation);
+ operation = GNUNET_TESTBED_peer_start (NULL, peer, NULL, NULL);
+ GNUNET_assert (NULL != operation);
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the host which has been registered
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+registration_comp (void *cls, const char *emsg)
+{
+ GNUNET_assert (cls == neighbour);
+ reg_handle = NULL;
+ operation =
+ GNUNET_TESTBED_peer_create (controller, host, cfg, &peer_create_cb,
+ &peer);
+ GNUNET_assert (NULL != operation);
+}
+
+
+/**
+ * Callback to signal successfull startup of the controller process
+ *
+ * @param cls the closure from GNUNET_TESTBED_controller_start()
+ * @param cfg the configuration with which the controller has been started;
+ * NULL if status is not GNUNET_OK
+ * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
+ * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
+ */
+static void
+status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, int status)
+{
+ uint64_t event_mask;
+
+ GNUNET_assert (GNUNET_OK == status);
+ event_mask = 0;
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
+ event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ controller =
+ GNUNET_TESTBED_controller_connect (cfg, host, event_mask, &controller_cb,
+ NULL);
+ GNUNET_assert (NULL != controller);
+ neighbour = GNUNET_TESTBED_host_create ("localhost", NULL, 0);
+ GNUNET_assert (NULL != neighbour);
+ reg_handle =
+ GNUNET_TESTBED_register_host (controller, neighbour, &registration_comp,
+ neighbour);
+ GNUNET_assert (NULL != reg_handle);
+}
+
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
+ GNUNET_assert (NULL != host);
+ cfg = GNUNET_CONFIGURATION_dup (config);
+ cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb,
+ NULL);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES, 5), &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ int ret;
+
+ char *const argv2[] = { "test_testbed_api",
+ "-c", "test_testbed_api.conf",
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ result = GNUNET_SYSERR;
+ ret =
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api", "nohelp", options, &run, NULL);
+ if ((GNUNET_OK != ret) || (GNUNET_OK != result))
+ return 1;
+ return 0;
+}
+
+/* end of test_testbed_api.c */
diff --git a/src/testbed/test_testbed_api.conf b/src/testbed/test_testbed_api.conf
new file mode 100644
index 0000000..52e0c9b
--- /dev/null
+++ b/src/testbed/test_testbed_api.conf
@@ -0,0 +1,91 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+NEIGHBOUR_LIMIT = 100
+TOPOLOGY = RANDOM
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
+
+[consensus]
+AUTOSTART = NO
+
+[gns]
+AUTOSTART = NO
+
+[statistics]
+AUTOSTART = NO
+
+[peerinfo]
+NO_IO = YES
diff --git a/src/testbed/test_testbed_api_2peers_1controller.c b/src/testbed/test_testbed_api_2peers_1controller.c
new file mode 100644
index 0000000..d5616c2
--- /dev/null
+++ b/src/testbed/test_testbed_api_2peers_1controller.c
@@ -0,0 +1,532 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/test_testbed_api_2peers_1controller.c
+ * @brief testcases for the testbed api: 2 peers are configured, started and
+ * connected together. The 2 peer reside on a single controller.
+ * @author Sree Harsha Totakura
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_testbed_service.h"
+
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Relative time seconds shorthand
+ */
+#define TIME_REL_SECS(sec) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
+
+/**
+ * Peer context
+ */
+struct PeerContext
+{
+ /**
+ * The peer handle
+ */
+ struct GNUNET_TESTBED_Peer *peer;
+
+ /**
+ * Operations involving this peer
+ */
+ struct GNUNET_TESTBED_Operation *operation;
+
+ /**
+ * set to GNUNET_YES when peer is started
+ */
+ int is_running;
+};
+
+/**
+ * Our localhost
+ */
+static struct GNUNET_TESTBED_Host *host;
+
+/**
+ * The controller process
+ */
+static struct GNUNET_TESTBED_ControllerProc *cp;
+
+/**
+ * The controller handle
+ */
+static struct GNUNET_TESTBED_Controller *controller;
+
+/**
+ * A neighbouring host
+ */
+static struct GNUNET_TESTBED_Host *neighbour;
+
+/**
+ * Handle for neighbour registration
+ */
+static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
+
+/**
+ * peer 1
+ */
+static struct PeerContext peer1;
+
+/**
+ * peer2
+ */
+static struct PeerContext peer2;
+
+/**
+ * Handle to configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to operations involving both peers
+ */
+static struct GNUNET_TESTBED_Operation *common_operation;
+
+/**
+ * Abort task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * Delayed connect job identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier delayed_connect_task;
+
+/**
+ * Different stages in testing
+ */
+enum Stage
+{
+
+ /**
+ * Initial stage
+ */
+ INIT,
+
+ /**
+ * peers are created
+ */
+ PEERS_CREATED,
+
+ /**
+ * peers are started
+ */
+ PEERS_STARTED,
+
+ /**
+ * peers are connected
+ */
+ PEERS_CONNECTED,
+
+ /**
+ * Peers are connected once again (this should not fail as they are already connected)
+ */
+ PEERS_CONNECTED_2,
+
+ /**
+ * peers are stopped
+ */
+ PEERS_STOPPED,
+
+ /**
+ * Final success stage
+ */
+ SUCCESS
+};
+
+/**
+ * The testing result
+ */
+static enum Stage result;
+
+/**
+ * shortcut to exit during failure
+ */
+#define FAIL_TEST(cond) do { \
+ if (!(cond)) { \
+ GNUNET_break(0); \
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task) \
+ GNUNET_SCHEDULER_cancel (abort_task); \
+ abort_task = GNUNET_SCHEDULER_NO_TASK; \
+ GNUNET_SCHEDULER_add_now (do_shutdown, NULL); \
+ return; \
+ } \
+ } while (0)
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ if (GNUNET_SCHEDULER_NO_TASK != delayed_connect_task)
+ GNUNET_SCHEDULER_cancel (delayed_connect_task);
+ if (NULL != reg_handle)
+ GNUNET_TESTBED_cancel_registration (reg_handle);
+ GNUNET_TESTBED_controller_disconnect (controller);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ if (NULL != cp)
+ GNUNET_TESTBED_controller_stop (cp);
+ GNUNET_TESTBED_host_destroy (neighbour);
+ GNUNET_TESTBED_host_destroy (host);
+}
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ do_shutdown (cls, tc);
+}
+
+
+/**
+ * Callback to be called when an operation is completed
+ *
+ * @param cls the callback closure from functions generating an operation
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg);
+
+
+/**
+ * task for delaying a connect
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_delayed_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ delayed_connect_task = GNUNET_SCHEDULER_NO_TASK;
+ FAIL_TEST (NULL == common_operation);
+ common_operation =
+ GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
+ peer2.peer);
+}
+
+
+/**
+ * Callback to be called when an operation is completed
+ *
+ * @param cls the callback closure from functions generating an operation
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
+{
+ FAIL_TEST (common_operation == op);
+ switch (result)
+ {
+ case PEERS_STARTED:
+ FAIL_TEST (NULL == peer1.operation);
+ FAIL_TEST (NULL == peer2.operation);
+ FAIL_TEST (NULL != common_operation);
+ break;
+ case PEERS_CONNECTED:
+ FAIL_TEST (NULL == peer1.operation);
+ FAIL_TEST (NULL == peer2.operation);
+ FAIL_TEST (NULL != common_operation);
+ break;
+ default:
+ FAIL_TEST (0);
+ }
+}
+
+
+/**
+ * Signature of the event handler function called by the
+ * respective event controller.
+ *
+ * @param cls closure
+ * @param event information about the event
+ */
+static void
+controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED: /* Will be reached when we destroy peers */
+ FAIL_TEST (PEERS_STOPPED == result);
+ FAIL_TEST (NULL == event->details.operation_finished.op_cls);
+ FAIL_TEST (NULL == event->details.operation_finished.emsg);
+ FAIL_TEST (NULL == event->details.operation_finished.generic);
+ if (event->details.operation_finished.operation == peer1.operation)
+ {
+ GNUNET_TESTBED_operation_done (peer1.operation);
+ peer1.operation = NULL;
+ peer1.peer = NULL;
+ }
+ else if (event->details.operation_finished.operation == peer2.operation)
+ {
+ GNUNET_TESTBED_operation_done (peer2.operation);
+ peer2.operation = NULL;
+ peer2.peer = NULL;
+ }
+ else
+ FAIL_TEST (0);
+ if ((NULL == peer1.peer) && (NULL == peer2.peer))
+ {
+ result = SUCCESS;
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ }
+ break;
+ case GNUNET_TESTBED_ET_PEER_START:
+ FAIL_TEST (INIT == result);
+ FAIL_TEST (event->details.peer_start.host == host);
+ if (event->details.peer_start.peer == peer1.peer)
+ {
+ peer1.is_running = GNUNET_YES;
+ GNUNET_TESTBED_operation_done (peer1.operation);
+ peer1.operation = NULL;
+ }
+ else if (event->details.peer_start.peer == peer2.peer)
+ {
+ peer2.is_running = GNUNET_YES;
+ GNUNET_TESTBED_operation_done (peer2.operation);
+ peer2.operation = NULL;
+ }
+ else
+ FAIL_TEST (0);
+ if ((GNUNET_YES == peer1.is_running) && (GNUNET_YES == peer2.is_running))
+ {
+ result = PEERS_STARTED;
+ common_operation =
+ GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
+ peer2.peer);
+ }
+ break;
+ case GNUNET_TESTBED_ET_PEER_STOP:
+ FAIL_TEST (PEERS_CONNECTED_2 == result);
+ if (event->details.peer_stop.peer == peer1.peer)
+ {
+ peer1.is_running = GNUNET_NO;
+ GNUNET_TESTBED_operation_done (peer1.operation);
+ peer1.operation = GNUNET_TESTBED_peer_destroy (peer1.peer);
+ }
+ else if (event->details.peer_stop.peer == peer2.peer)
+ {
+ peer2.is_running = GNUNET_NO;
+ GNUNET_TESTBED_operation_done (peer2.operation);
+ peer2.operation = GNUNET_TESTBED_peer_destroy (peer2.peer);
+ }
+ else
+ FAIL_TEST (0);
+ if ((GNUNET_NO == peer1.is_running) && (GNUNET_NO == peer2.is_running))
+ result = PEERS_STOPPED;
+ break;
+ case GNUNET_TESTBED_ET_CONNECT:
+ switch (result)
+ {
+ case PEERS_STARTED:
+ FAIL_TEST (NULL == peer1.operation);
+ FAIL_TEST (NULL == peer2.operation);
+ FAIL_TEST (NULL != common_operation);
+ FAIL_TEST ((event->details.peer_connect.peer1 == peer1.peer) &&
+ (event->details.peer_connect.peer2 == peer2.peer));
+ GNUNET_TESTBED_operation_done (common_operation);
+ common_operation = NULL;
+ result = PEERS_CONNECTED;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected\n");
+ delayed_connect_task =
+ GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (3), &do_delayed_connect,
+ NULL);
+ break;
+ case PEERS_CONNECTED:
+ FAIL_TEST (NULL == peer1.operation);
+ FAIL_TEST (NULL == peer2.operation);
+ FAIL_TEST (NULL != common_operation);
+ GNUNET_TESTBED_operation_done (common_operation);
+ common_operation = NULL;
+ result = PEERS_CONNECTED_2;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected again\n");
+ peer1.operation = GNUNET_TESTBED_peer_stop (peer1.peer, NULL, NULL);
+ peer2.operation = GNUNET_TESTBED_peer_stop (peer2.peer, NULL, NULL);
+ break;
+ default:
+ FAIL_TEST (0);
+ }
+ break;
+ default:
+ FAIL_TEST (0);
+ };
+}
+
+
+/**
+ * Functions of this signature are called when a peer has been successfully
+ * created
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_create()
+ * @param peer the handle for the created peer; NULL on any error during
+ * creation
+ * @param emsg NULL if peer is not NULL; else MAY contain the error description
+ */
+static void
+peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
+{
+ struct PeerContext *pc = cls;
+
+ FAIL_TEST (NULL != pc->operation);
+ FAIL_TEST (NULL != peer);
+ FAIL_TEST (NULL == pc->peer);
+ pc->peer = peer;
+ GNUNET_TESTBED_operation_done (pc->operation);
+ pc->operation = GNUNET_TESTBED_peer_start (NULL, pc->peer, NULL, NULL);
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the host which has been registered
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+registration_comp (void *cls, const char *emsg)
+{
+ FAIL_TEST (cls == neighbour);
+ reg_handle = NULL;
+ peer1.operation =
+ GNUNET_TESTBED_peer_create (controller, host, cfg, &peer_create_cb,
+ &peer1);
+ peer2.operation =
+ GNUNET_TESTBED_peer_create (controller, host, cfg, &peer_create_cb,
+ &peer2);
+ FAIL_TEST (NULL != peer1.operation);
+ FAIL_TEST (NULL != peer2.operation);
+}
+
+
+/**
+ * Callback to signal successfull startup of the controller process
+ *
+ * @param cls the closure from GNUNET_TESTBED_controller_start()
+ * @param cfg the configuration with which the controller has been started;
+ * NULL if status is not GNUNET_OK
+ * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
+ * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
+ */
+static void
+status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, int status)
+{
+ uint64_t event_mask;
+
+ if (GNUNET_OK != status)
+ {
+ cp = NULL;
+ FAIL_TEST (0);
+ }
+ event_mask = 0;
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
+ event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ controller =
+ GNUNET_TESTBED_controller_connect (cfg, host, event_mask, &controller_cb,
+ NULL);
+ FAIL_TEST (NULL != controller);
+ neighbour = GNUNET_TESTBED_host_create ("localhost", NULL, 0);
+ FAIL_TEST (NULL != neighbour);
+ reg_handle =
+ GNUNET_TESTBED_register_host (controller, neighbour, &registration_comp,
+ neighbour);
+ FAIL_TEST (NULL != reg_handle);
+}
+
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
+ FAIL_TEST (NULL != host);
+ cfg = GNUNET_CONFIGURATION_dup (config);
+ cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb,
+ NULL);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ int ret;
+
+ char *const argv2[] = { "test_testbed_api_2peers_1controller",
+ "-c", "test_testbed_api.conf",
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ result = INIT;
+ ret =
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api_2peers_1controller", "nohelp",
+ options, &run, NULL);
+ if ((GNUNET_OK != ret) || (SUCCESS != result))
+ return 1;
+ return 0;
+}
+
+/* end of test_testbed_api_2peers_1controller.c */
diff --git a/src/testbed/test_testbed_api_3peers_3controllers.c b/src/testbed/test_testbed_api_3peers_3controllers.c
new file mode 100644
index 0000000..47ad810
--- /dev/null
+++ b/src/testbed/test_testbed_api_3peers_3controllers.c
@@ -0,0 +1,946 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/test_testbed_api_3peers_3controllers.c
+ * @brief testcases for the testbed api: 3 peers are configured, started and
+ * connected together. Each peer resides on its own controller.
+ * @author Sree Harsha Totakura
+ */
+
+
+/**
+ * The testing architecture is:
+ * A
+ * / \
+ * / \
+ * B === C
+ * A is the master controller and B, C are slave controllers. B links to C
+ * laterally.
+ * Peers are mapped to controllers in the following relations:
+ * Peer Controller
+ * 1 A
+ * 2 B
+ * 3 C
+ *
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_testbed_service.h"
+
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Relative time seconds shorthand
+ */
+#define TIME_REL_SECS(sec) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
+
+
+/**
+ * Peer context
+ */
+struct PeerContext
+{
+ /**
+ * The peer handle
+ */
+ struct GNUNET_TESTBED_Peer *peer;
+
+ /**
+ * Operations involving this peer
+ */
+ struct GNUNET_TESTBED_Operation *operation;
+
+ /**
+ * set to GNUNET_YES when peer is started
+ */
+ int is_running;
+};
+
+/**
+ * Our localhost
+ */
+static struct GNUNET_TESTBED_Host *host;
+
+/**
+ * The controller process of one controller
+ */
+static struct GNUNET_TESTBED_ControllerProc *cp1;
+
+/**
+ * A neighbouring host
+ */
+static struct GNUNET_TESTBED_Host *neighbour1;
+
+/**
+ * Another neighbouring host
+ */
+static struct GNUNET_TESTBED_Host *neighbour2;
+
+/**
+ * Handle for neighbour registration
+ */
+static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
+
+/**
+ * The controller handle of one controller
+ */
+static struct GNUNET_TESTBED_Controller *controller1;
+
+/**
+ * peer 1
+ */
+static struct PeerContext peer1;
+
+/**
+ * peer2
+ */
+static struct PeerContext peer2;
+
+/**
+ * peer3
+ */
+static struct PeerContext peer3;
+
+/**
+ * Handle to starting configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to slave controller C's configuration, used to establish lateral link from
+ * master controller
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg2;
+
+/**
+ * Handle to operations involving both peers
+ */
+static struct GNUNET_TESTBED_Operation *common_operation;
+
+/**
+ * The handle for whether a host is habitable or not
+ */
+struct GNUNET_TESTBED_HostHabitableCheckHandle *hc_handle;
+
+/**
+ * Abort task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * Delayed connect job identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier delayed_connect_task;
+
+/**
+ * Different stages in testing
+ */
+enum Stage
+{
+
+ /**
+ * Initial stage
+ */
+ INIT,
+
+ /**
+ * Controller 1 has started
+ */
+ CONTROLLER1_UP,
+
+ /**
+ * peer1 is created
+ */
+ PEER1_CREATED,
+
+ /**
+ * peer1 is started
+ */
+ PEER1_STARTED,
+
+ /**
+ * Controller 2 has started
+ */
+ CONTROLLER2_UP,
+
+ /**
+ * peer2 is created
+ */
+ PEER2_CREATED,
+
+ /**
+ * peer2 is started
+ */
+ PEER2_STARTED,
+
+ /**
+ * Controller 3 has started
+ */
+ CONTROLLER3_UP,
+
+ /**
+ * Peer3 is created
+ */
+ PEER3_CREATED,
+
+ /**
+ * Peer3 started
+ */
+ PEER3_STARTED,
+
+ /**
+ * peer1 and peer2 are connected
+ */
+ PEERS_1_2_CONNECTED,
+
+ /**
+ * peer2 and peer3 are connected
+ */
+ PEERS_2_3_CONNECTED,
+
+ /**
+ * Peers are connected once again (this should not fail as they are already connected)
+ */
+ PEERS_CONNECTED_2,
+
+ /**
+ * peers are stopped
+ */
+ PEERS_STOPPED,
+
+ /**
+ * Final success stage
+ */
+ SUCCESS,
+
+ /**
+ * Optional stage for marking test to be skipped
+ */
+ SKIP
+};
+
+/**
+ * The testing result
+ */
+static enum Stage result;
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ if (NULL != hc_handle)
+ GNUNET_TESTBED_is_host_habitable_cancel (hc_handle);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == delayed_connect_task);
+ if (NULL != common_operation)
+ GNUNET_TESTBED_operation_done (common_operation);
+ if (NULL != reg_handle)
+ GNUNET_TESTBED_cancel_registration (reg_handle);
+ if (NULL != controller1)
+ GNUNET_TESTBED_controller_disconnect (controller1);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ if (NULL != cfg2)
+ GNUNET_CONFIGURATION_destroy (cfg2);
+ if (NULL != cp1)
+ GNUNET_TESTBED_controller_stop (cp1);
+ if (NULL != host)
+ GNUNET_TESTBED_host_destroy (host);
+ if (NULL != neighbour1)
+ GNUNET_TESTBED_host_destroy (neighbour1);
+ if (NULL != neighbour2)
+ GNUNET_TESTBED_host_destroy (neighbour2);
+}
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_SCHEDULER_NO_TASK != delayed_connect_task)
+ {
+ GNUNET_SCHEDULER_cancel (delayed_connect_task);
+ delayed_connect_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ do_shutdown (cls, tc);
+}
+
+static void
+abort_test ()
+{
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
+}
+
+
+/**
+ * Callback to be called when an operation is completed
+ *
+ * @param cls the callback closure from functions generating an operation
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg);
+
+
+/**
+ * task for delaying a connect
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_delayed_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ delayed_connect_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL != common_operation)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ common_operation =
+ GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
+ peer2.peer);
+}
+
+
+/**
+ * Callback to be called when an operation is completed
+ *
+ * @param cls the callback closure from functions generating an operation
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
+{
+ if (common_operation != op)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+
+ switch (result)
+ {
+ case PEER3_STARTED:
+ case PEERS_2_3_CONNECTED:
+ case PEERS_1_2_CONNECTED:
+ break;
+ default:
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ if ((NULL != peer1.operation) || (NULL != peer2.operation) ||
+ (NULL != peer3.operation))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+}
+
+
+/**
+ * Functions of this signature are called when a peer has been successfully
+ * created
+ *
+ * @param cls NULL
+ * @param peer the handle for the created peer; NULL on any error during
+ * creation
+ * @param emsg NULL if peer is not NULL; else MAY contain the error description
+ */
+static void
+peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
+{
+ switch (result)
+ {
+ case CONTROLLER1_UP:
+ if ((NULL == peer1.operation) || (NULL == peer) || (NULL != peer1.peer))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ peer1.peer = peer;
+ GNUNET_TESTBED_operation_done (peer1.operation);
+ result = PEER1_CREATED;
+ peer1.operation = GNUNET_TESTBED_peer_start (NULL, peer, NULL, NULL);
+ break;
+ case CONTROLLER2_UP:
+ if ((NULL == peer2.operation) || (NULL == peer) || (NULL != peer2.peer))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ peer2.peer = peer;
+ GNUNET_TESTBED_operation_done (peer2.operation);
+ result = PEER2_CREATED;
+ peer2.operation = GNUNET_TESTBED_peer_start (NULL, peer, NULL, NULL);
+ break;
+ case CONTROLLER3_UP:
+ if ((NULL == peer3.operation) || (NULL == peer) || (NULL != peer3.peer))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ peer3.peer = peer;
+ GNUNET_TESTBED_operation_done (peer3.operation);
+ result = PEER3_CREATED;
+ peer3.operation = GNUNET_TESTBED_peer_start (NULL, peer, NULL, NULL);
+ break;
+ default:
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+}
+
+
+/**
+ * Signature of the event handler function called by the
+ * respective event controller.
+ *
+ * @param cls closure
+ * @param event information about the event
+ */
+static void
+controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+ if ((NULL != event->details.operation_finished.op_cls) ||
+ (NULL != event->details.operation_finished.emsg))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ switch (result)
+ {
+ case PEERS_STOPPED:
+ if (NULL != event->details.operation_finished.generic)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ if (event->details.operation_finished.operation == peer1.operation)
+ {
+ GNUNET_TESTBED_operation_done (peer1.operation);
+ peer1.operation = NULL;
+ peer1.peer = NULL;
+ }
+ else if (event->details.operation_finished.operation == peer2.operation)
+ {
+ GNUNET_TESTBED_operation_done (peer2.operation);
+ peer2.operation = NULL;
+ peer2.peer = NULL;
+ }
+ else if (event->details.operation_finished.operation == peer3.operation)
+ {
+ GNUNET_TESTBED_operation_done (peer3.operation);
+ peer3.operation = NULL;
+ peer3.peer = NULL;
+ }
+ else
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ if ((NULL == peer1.peer) && (NULL == peer2.peer) && (NULL == peer3.peer))
+ {
+ result = SUCCESS;
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ }
+ break;
+ case PEER1_STARTED:
+ if ((NULL != event->details.operation_finished.generic) ||
+ (NULL == common_operation))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ GNUNET_TESTBED_operation_done (common_operation);
+ common_operation = NULL;
+ result = CONTROLLER2_UP;
+ peer2.operation =
+ GNUNET_TESTBED_peer_create (controller1, neighbour1, cfg,
+ &peer_create_cb, NULL);
+ if (NULL == peer2.operation)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ break;
+ case PEER2_STARTED:
+ if ((NULL != event->details.operation_finished.generic) ||
+ (NULL == common_operation))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ GNUNET_TESTBED_operation_done (common_operation);
+ common_operation = NULL;
+ result = CONTROLLER3_UP;
+ peer3.operation =
+ GNUNET_TESTBED_peer_create (controller1, neighbour2, cfg,
+ &peer_create_cb, NULL);
+ if (NULL == peer3.operation)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ break;
+ case GNUNET_TESTBED_ET_PEER_START:
+ switch (result)
+ {
+ case PEER1_CREATED:
+ if (event->details.peer_start.host != host)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ peer1.is_running = GNUNET_YES;
+ GNUNET_TESTBED_operation_done (peer1.operation);
+ peer1.operation = NULL;
+ result = PEER1_STARTED;
+ common_operation =
+ GNUNET_TESTBED_controller_link (NULL, controller1, neighbour1, NULL,
+ cfg, GNUNET_YES);
+ break;
+ case PEER2_CREATED:
+ if (event->details.peer_start.host != neighbour1)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ peer2.is_running = GNUNET_YES;
+ GNUNET_TESTBED_operation_done (peer2.operation);
+ peer2.operation = NULL;
+ result = PEER2_STARTED;
+ if (NULL != common_operation)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ common_operation =
+ GNUNET_TESTBED_controller_link (NULL, controller1, neighbour2, NULL,
+ cfg, GNUNET_YES);
+ if (NULL == common_operation)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ break;
+ case PEER3_CREATED:
+ if (event->details.peer_start.host != neighbour2)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ peer3.is_running = GNUNET_YES;
+ GNUNET_TESTBED_operation_done (peer3.operation);
+ peer3.operation = NULL;
+ result = PEER3_STARTED;
+ common_operation =
+ GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer2.peer,
+ peer1.peer);
+ break;
+ default:
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ break;
+ case GNUNET_TESTBED_ET_PEER_STOP:
+ if (PEERS_CONNECTED_2 != result)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ if (event->details.peer_stop.peer == peer1.peer)
+ {
+ peer1.is_running = GNUNET_NO;
+ GNUNET_TESTBED_operation_done (peer1.operation);
+ }
+ else if (event->details.peer_stop.peer == peer2.peer)
+ {
+ peer2.is_running = GNUNET_NO;
+ GNUNET_TESTBED_operation_done (peer2.operation);
+ }
+ else if (event->details.peer_stop.peer == peer3.peer)
+ {
+ peer3.is_running = GNUNET_NO;
+ GNUNET_TESTBED_operation_done (peer3.operation);
+ }
+ else
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ if ((GNUNET_NO == peer1.is_running) && (GNUNET_NO == peer2.is_running) &&
+ (GNUNET_NO == peer3.is_running))
+ {
+ result = PEERS_STOPPED;
+ peer1.operation = GNUNET_TESTBED_peer_destroy (peer1.peer);
+ peer2.operation = GNUNET_TESTBED_peer_destroy (peer2.peer);
+ peer3.operation = GNUNET_TESTBED_peer_destroy (peer3.peer);
+ }
+ break;
+ case GNUNET_TESTBED_ET_CONNECT:
+ if ((NULL != peer1.operation) || (NULL != peer2.operation) ||
+ (NULL != peer3.operation) || (NULL == common_operation))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ switch (result)
+ {
+ case PEER3_STARTED:
+ if ((event->details.peer_connect.peer1 != peer2.peer) ||
+ (event->details.peer_connect.peer2 != peer1.peer))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ GNUNET_TESTBED_operation_done (common_operation);
+ common_operation = NULL;
+ result = PEERS_1_2_CONNECTED;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected\n");
+ common_operation =
+ GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer2.peer,
+ peer3.peer);
+ break;
+ case PEERS_1_2_CONNECTED:
+ if ((event->details.peer_connect.peer1 != peer2.peer) ||
+ (event->details.peer_connect.peer2 != peer3.peer))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ GNUNET_TESTBED_operation_done (common_operation);
+ common_operation = NULL;
+ result = PEERS_2_3_CONNECTED;
+ delayed_connect_task =
+ GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (3), &do_delayed_connect,
+ NULL);
+ break;
+ case PEERS_2_3_CONNECTED:
+ if ((event->details.peer_connect.peer1 != peer1.peer) ||
+ (event->details.peer_connect.peer2 != peer2.peer))
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ GNUNET_TESTBED_operation_done (common_operation);
+ common_operation = NULL;
+ result = PEERS_CONNECTED_2;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected again\n");
+ peer1.operation = GNUNET_TESTBED_peer_stop (peer1.peer, NULL, NULL);
+ peer2.operation = GNUNET_TESTBED_peer_stop (peer2.peer, NULL, NULL);
+ peer3.operation = GNUNET_TESTBED_peer_stop (peer3.peer, NULL, NULL);
+ break;
+ default:
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the host which has been registered
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+registration_comp (void *cls, const char *emsg)
+{
+ reg_handle = NULL;
+ if (cls == neighbour1)
+ {
+ neighbour2 = GNUNET_TESTBED_host_create ("127.0.0.1", NULL, 0);
+ if (NULL == neighbour2)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ reg_handle =
+ GNUNET_TESTBED_register_host (controller1, neighbour2,
+ &registration_comp, neighbour2);
+ if (NULL == reg_handle)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ return;
+ }
+ if (cls != neighbour2)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ peer1.operation =
+ GNUNET_TESTBED_peer_create (controller1, host, cfg, &peer_create_cb,
+ &peer1);
+ if (NULL == peer1.operation)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+}
+
+
+/**
+ * Callback to signal successfull startup of the controller process
+ *
+ * @param cls the closure from GNUNET_TESTBED_controller_start()
+ * @param cfg the configuration with which the controller has been started;
+ * NULL if status is not GNUNET_OK
+ * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
+ * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
+ */
+static void
+status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config,
+ int status)
+{
+ uint64_t event_mask;
+
+ if (GNUNET_OK != status)
+ {
+ GNUNET_break (0);
+ cp1 = NULL;
+ abort_test ();
+ return;
+ }
+ event_mask = 0;
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
+ event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ switch (result)
+ {
+ case INIT:
+ controller1 =
+ GNUNET_TESTBED_controller_connect (config, host, event_mask,
+ &controller_cb, NULL);
+ if (NULL == controller1)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ result = CONTROLLER1_UP;
+ neighbour1 = GNUNET_TESTBED_host_create ("127.0.0.1", NULL, 0);
+ if (NULL == neighbour1)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ reg_handle =
+ GNUNET_TESTBED_register_host (controller1, neighbour1,
+ &registration_comp, neighbour1);
+ if (NULL == reg_handle)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+}
+
+
+/**
+ * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
+ * inform whether the given host is habitable or not. The Handle returned by
+ * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
+ *
+ * @param cls NULL
+ * @param host the host whose status is being reported; will be NULL if the host
+ * given to GNUNET_TESTBED_is_host_habitable() is NULL
+ * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
+ */
+static void
+host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *_host,
+ int status)
+{
+ hc_handle = NULL;
+ if (GNUNET_NO == status)
+ {
+ (void) PRINTF ("%s",
+ "Unable to run the test as this system is not configured "
+ "to use password less SSH logins to localhost.\n"
+ "Skipping test\n");
+ GNUNET_SCHEDULER_cancel (abort_task);
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ (void) GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ result = SKIP;
+ return;
+ }
+ cp1 =
+ GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb, NULL);
+}
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
+ if (NULL == host)
+ {
+ GNUNET_break (0);
+ abort_test ();
+ return;
+ }
+ if (NULL ==
+ (hc_handle =
+ GNUNET_TESTBED_is_host_habitable (host, config, &host_habitable_cb,
+ NULL)))
+ {
+ GNUNET_TESTBED_host_destroy (host);
+ host = NULL;
+ (void) PRINTF ("%s",
+ "Unable to run the test as this system is not configured "
+ "to use password less SSH logins to localhost.\n"
+ "Skipping test\n");
+ result = SKIP;
+ return;
+ }
+ cfg = GNUNET_CONFIGURATION_dup (config);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ char *const argv2[] = { "test_testbed_api_3peers_3controllers",
+ "-c", "test_testbed_api.conf",
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ result = INIT;
+ ret =
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api_3peers_3controllers", "nohelp",
+ options, &run, NULL);
+ if (GNUNET_OK != ret)
+ return 1;
+ switch (result)
+ {
+ case SUCCESS:
+ return 0;
+ case SKIP:
+ return 77; /* Mark test as skipped */
+ default:
+ return 1;
+ }
+}
+
+/* end of test_testbed_api_3peers_3controllers.c */
diff --git a/src/testbed/test_testbed_api_controllerlink.c b/src/testbed/test_testbed_api_controllerlink.c
new file mode 100644
index 0000000..eadc6c9
--- /dev/null
+++ b/src/testbed/test_testbed_api_controllerlink.c
@@ -0,0 +1,749 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/test_testbed_api_controllerlink.c
+ * @brief testcase for testing controller to subcontroller linking
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+
+/**
+ * The controller architecture we try to achieve in this test case:
+ *
+ * Master Controller
+ * // \\
+ * // \\
+ * Slave Controller 1---------Slave Controller 3
+ * ||
+ * ||
+ * Slave Controller 2
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testing_lib.h"
+#include "gnunet_testbed_service.h"
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Debug logging shorthand
+ */
+#define LOG_DEBUG(...) \
+ LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
+
+/**
+ * Different stages in testing
+ */
+enum Stage
+{
+
+ /**
+ * Initial stage
+ */
+ INIT,
+
+ /**
+ * Master controller has started
+ */
+ MASTER_STARTED,
+
+ /**
+ * A peer has been created on master
+ */
+ MASTER_PEER_CREATE_SUCCESS,
+
+ /**
+ * Peer on master controller has been started successfully.
+ */
+ MASTER_PEER_START_SUCCESS,
+
+ /**
+ * The first slave has been registered at master controller
+ */
+ SLAVE1_REGISTERED,
+
+ /**
+ * The second slave has been registered at the master controller
+ */
+ SLAVE2_REGISTERED,
+
+ /**
+ * Link from master to slave 1 has been successfully created
+ */
+ SLAVE1_LINK_SUCCESS,
+
+ /**
+ * Peer create on slave 1 successful
+ */
+ SLAVE1_PEER_CREATE_SUCCESS,
+
+ /**
+ * Peer startup on slave 1 successful
+ */
+ SLAVE1_PEER_START_SUCCESS,
+
+ /**
+ * Link from slave 1 to slave 2 has been successfully created.
+ */
+ SLAVE2_LINK_SUCCESS,
+
+ /**
+ * Peer create on slave 2 successful
+ */
+ SLAVE2_PEER_CREATE_SUCCESS,
+
+ /**
+ * Peer on slave 1 successfully stopped
+ */
+ SLAVE1_PEER_STOP_SUCCESS,
+
+ /**
+ * Peer startup on slave 2 successful
+ */
+ SLAVE2_PEER_START_SUCCESS,
+
+ /**
+ * Try to connect peers on master and slave 2.
+ */
+ MASTER_SLAVE2_PEERS_CONNECTED,
+
+ /**
+ * Peer on slave 2 successfully stopped
+ */
+ SLAVE2_PEER_STOP_SUCCESS,
+
+ /**
+ * Peer destroy on slave 1 successful
+ */
+ SLAVE1_PEER_DESTROY_SUCCESS,
+
+ /**
+ * Peer destory on slave 2 successful
+ */
+ SLAVE2_PEER_DESTROY_SUCCESS,
+
+ /**
+ * Slave 3 has successfully registered
+ */
+ SLAVE3_REGISTERED,
+
+ /**
+ * Slave 3 has successfully started
+ */
+ SLAVE3_STARTED,
+
+ /**
+ * The configuration of slave 3 is acquired
+ */
+ SLAVE3_GET_CONFIG_SUCCESS,
+
+ /**
+ * Slave 1 has linked to slave 3;
+ */
+ SLAVE3_LINK_SUCCESS,
+
+ /**
+ * Destory master peer and mark test as success
+ */
+ SUCCESS,
+
+ /**
+ * Marks test as skipped
+ */
+ SKIP
+};
+
+/**
+ * Host for running master controller
+ */
+static struct GNUNET_TESTBED_Host *host;
+
+/**
+ * The master controller process
+ */
+static struct GNUNET_TESTBED_ControllerProc *cp;
+
+/**
+ * Handle to master controller
+ */
+static struct GNUNET_TESTBED_Controller *mc;
+
+/**
+ * Slave host for running slave controller
+ */
+static struct GNUNET_TESTBED_Host *slave;
+
+/**
+ * Another slave host for running another slave controller
+ */
+static struct GNUNET_TESTBED_Host *slave2;
+
+/**
+ * Host for slave 3
+ */
+static struct GNUNET_TESTBED_Host *slave3;
+
+/**
+ * Slave host registration handle
+ */
+static struct GNUNET_TESTBED_HostRegistrationHandle *rh;
+
+/**
+ * Handle to global configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Configuration of slave 3 controller
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg3;
+
+/**
+ * Abort task
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * Operation handle for linking controllers
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+/**
+ * Handle to peer started at slave 1
+ */
+static struct GNUNET_TESTBED_Peer *slave1_peer;
+
+/**
+ * Handle to peer started at slave 2
+ */
+static struct GNUNET_TESTBED_Peer *slave2_peer;
+
+/**
+ * Handle to a peer started at master controller
+ */
+static struct GNUNET_TESTBED_Peer *master_peer;
+
+/**
+ * The handle for whether a host is habitable or not
+ */
+struct GNUNET_TESTBED_HostHabitableCheckHandle *hc_handle;
+
+/**
+ * Event mask
+ */
+uint64_t event_mask;
+
+/**
+ * Global testing status
+ */
+static enum Stage result;
+
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ if (NULL != hc_handle)
+ GNUNET_TESTBED_is_host_habitable_cancel (hc_handle);
+ if (NULL != slave3)
+ GNUNET_TESTBED_host_destroy (slave3);
+ if (NULL != slave2)
+ GNUNET_TESTBED_host_destroy (slave2);
+ if (NULL != slave)
+ GNUNET_TESTBED_host_destroy (slave);
+ if (NULL != host)
+ GNUNET_TESTBED_host_destroy (host);
+ if (NULL != mc)
+ GNUNET_TESTBED_controller_disconnect (mc);
+ if (NULL != cfg)
+ GNUNET_CONFIGURATION_destroy (cfg);
+ if (NULL != cfg3)
+ GNUNET_CONFIGURATION_destroy (cfg3);
+ if (NULL != cp)
+ GNUNET_TESTBED_controller_stop (cp);
+ if (NULL != rh)
+ GNUNET_TESTBED_cancel_registration (rh);
+}
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ do_shutdown (cls, tc);
+}
+
+
+/**
+ * Calls abort now
+ *
+ * @param
+ * @return
+ */
+static void
+do_abort_now (void *cls)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
+}
+
+
+/**
+ * Task for inserting delay between tests
+ *
+ * @param
+ * @return
+ */
+static void
+delay_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ switch (result)
+ {
+ case SLAVE2_PEER_CREATE_SUCCESS:
+ op = GNUNET_TESTBED_peer_stop (slave1_peer, NULL, NULL);
+ GNUNET_assert (NULL != op);
+ break;
+ case MASTER_SLAVE2_PEERS_CONNECTED:
+ op = GNUNET_TESTBED_peer_stop (slave2_peer, NULL, NULL);
+ GNUNET_assert (NULL != op);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Functions of this signature are called when a peer has been successfully
+ * created
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_create()
+ * @param peer the handle for the created peer; NULL on any error during
+ * creation
+ * @param emsg NULL if peer is not NULL; else MAY contain the error description
+ */
+static void
+peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
+{
+ GNUNET_assert (NULL != peer);
+ GNUNET_assert (NULL == emsg);
+ switch (result)
+ {
+ case MASTER_STARTED:
+ result = MASTER_PEER_CREATE_SUCCESS;
+ master_peer = peer;
+ GNUNET_TESTBED_operation_done (op);
+ op = GNUNET_TESTBED_peer_start (NULL, master_peer, NULL, NULL);
+ break;
+ case SLAVE1_LINK_SUCCESS:
+ result = SLAVE1_PEER_CREATE_SUCCESS;
+ slave1_peer = peer;
+ GNUNET_TESTBED_operation_done (op);
+ op = GNUNET_TESTBED_peer_start (NULL, slave1_peer, NULL, NULL);
+ break;
+ case SLAVE2_LINK_SUCCESS:
+ result = SLAVE2_PEER_CREATE_SUCCESS;
+ slave2_peer = peer;
+ GNUNET_TESTBED_operation_done (op);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 1), &delay_task,
+ NULL);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ GNUNET_assert (NULL != op);
+}
+
+
+/**
+ * Checks the event if it is an operation finished event and if indicates a
+ * successfull completion of operation
+ *
+ * @param event the event information to check
+ */
+static void
+check_operation_success (const struct GNUNET_TESTBED_EventInformation *event)
+{
+ GNUNET_assert (NULL != event);
+ GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
+ GNUNET_assert (event->details.operation_finished.operation == op);
+ GNUNET_assert (NULL == event->details.operation_finished.op_cls);
+ GNUNET_assert (NULL == event->details.operation_finished.emsg);
+ GNUNET_assert (NULL == event->details.operation_finished.generic);
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the host which has been registered
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+registration_cont (void *cls, const char *emsg);
+
+
+/**
+ * Signature of the event handler function called by the
+ * respective event controller.
+ *
+ * @param cls closure
+ * @param event information about the event
+ */
+static void
+controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (result)
+ {
+ case SLAVE2_REGISTERED:
+ check_operation_success (event);
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ result = SLAVE1_LINK_SUCCESS;
+ GNUNET_assert (NULL != slave2);
+ GNUNET_assert (NULL != slave);
+ op = GNUNET_TESTBED_peer_create (mc, slave, cfg, peer_create_cb, NULL);
+ GNUNET_assert (NULL != op);
+ break;
+ case SLAVE1_PEER_START_SUCCESS:
+ check_operation_success (event);
+ GNUNET_TESTBED_operation_done (op);
+ result = SLAVE2_LINK_SUCCESS;
+ op = GNUNET_TESTBED_peer_create (mc, slave2, cfg, peer_create_cb, NULL);
+ GNUNET_assert (NULL != op);
+ break;
+ case MASTER_PEER_CREATE_SUCCESS:
+ GNUNET_assert (GNUNET_TESTBED_ET_PEER_START == event->type);
+ GNUNET_assert (event->details.peer_start.host == host);
+ GNUNET_assert (event->details.peer_start.peer == master_peer);
+ GNUNET_TESTBED_operation_done (op);
+ result = MASTER_PEER_START_SUCCESS;
+ slave = GNUNET_TESTBED_host_create_with_id (1, "127.0.0.1", NULL, 0);
+ GNUNET_assert (NULL != slave);
+ rh = GNUNET_TESTBED_register_host (mc, slave, &registration_cont, NULL);
+ GNUNET_assert (NULL != rh);
+ break;
+ case SLAVE1_PEER_CREATE_SUCCESS:
+ GNUNET_assert (GNUNET_TESTBED_ET_PEER_START == event->type);
+ GNUNET_assert (event->details.peer_start.host == slave);
+ GNUNET_assert (event->details.peer_start.peer == slave1_peer);
+ GNUNET_TESTBED_operation_done (op);
+ result = SLAVE1_PEER_START_SUCCESS;
+ op = GNUNET_TESTBED_controller_link (NULL, mc, slave2, slave, cfg,
+ GNUNET_YES);
+ break;
+ case SLAVE2_PEER_CREATE_SUCCESS:
+ GNUNET_assert (GNUNET_TESTBED_ET_PEER_STOP == event->type);
+ GNUNET_assert (event->details.peer_stop.peer == slave1_peer);
+ GNUNET_TESTBED_operation_done (op);
+ result = SLAVE1_PEER_STOP_SUCCESS;
+ op = GNUNET_TESTBED_peer_start (NULL, slave2_peer, NULL, NULL);
+ GNUNET_assert (NULL != op);
+ break;
+ case SLAVE1_PEER_STOP_SUCCESS:
+ GNUNET_assert (GNUNET_TESTBED_ET_PEER_START == event->type);
+ GNUNET_assert (event->details.peer_start.host == slave2);
+ GNUNET_assert (event->details.peer_start.peer == slave2_peer);
+ GNUNET_TESTBED_operation_done (op);
+ result = SLAVE2_PEER_START_SUCCESS;
+ op = GNUNET_TESTBED_overlay_connect (mc, NULL, NULL, master_peer,
+ slave2_peer);
+ break;
+ case SLAVE2_PEER_START_SUCCESS:
+ GNUNET_assert (NULL != event);
+ GNUNET_assert (GNUNET_TESTBED_ET_CONNECT == event->type);
+ GNUNET_assert (event->details.peer_connect.peer1 == master_peer);
+ GNUNET_assert (event->details.peer_connect.peer2 == slave2_peer);
+ result = MASTER_SLAVE2_PEERS_CONNECTED;
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 1), &delay_task,
+ NULL);
+ break;
+ case MASTER_SLAVE2_PEERS_CONNECTED:
+ GNUNET_assert (GNUNET_TESTBED_ET_PEER_STOP == event->type);
+ GNUNET_assert (event->details.peer_stop.peer == slave2_peer);
+ GNUNET_TESTBED_operation_done (op);
+ result = SLAVE2_PEER_STOP_SUCCESS;
+ op = GNUNET_TESTBED_peer_destroy (slave1_peer);
+ GNUNET_assert (NULL != op);
+ break;
+ case SLAVE2_PEER_STOP_SUCCESS:
+ check_operation_success (event);
+ GNUNET_TESTBED_operation_done (op);
+ result = SLAVE1_PEER_DESTROY_SUCCESS;
+ op = GNUNET_TESTBED_peer_destroy (slave2_peer);
+ GNUNET_assert (NULL != op);
+ break;
+ case SLAVE1_PEER_DESTROY_SUCCESS:
+ check_operation_success (event);
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ result = SLAVE2_PEER_DESTROY_SUCCESS;
+ slave3 = GNUNET_TESTBED_host_create_with_id (3, "127.0.0.1", NULL, 0);
+ rh = GNUNET_TESTBED_register_host (mc, slave3, &registration_cont, NULL);
+ break;
+ case SLAVE3_REGISTERED:
+ check_operation_success (event);
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ result = SLAVE3_STARTED;
+ op = GNUNET_TESTBED_get_slave_config (NULL, mc, slave3);
+ GNUNET_assert (NULL != op);
+ break;
+ case SLAVE3_STARTED:
+ GNUNET_assert (NULL != event);
+ GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
+ GNUNET_assert (event->details.operation_finished.operation == op);
+ GNUNET_assert (NULL == event->details.operation_finished.op_cls);
+ GNUNET_assert (NULL == event->details.operation_finished.emsg);
+ cfg3 = GNUNET_CONFIGURATION_dup (event->details.operation_finished.generic);
+ GNUNET_TESTBED_operation_done (op);
+ result = SLAVE3_GET_CONFIG_SUCCESS;
+ op = GNUNET_TESTBED_controller_link (NULL, mc, slave3, slave, cfg3,
+ GNUNET_NO);
+ break;
+ case SLAVE3_GET_CONFIG_SUCCESS:
+ result = SLAVE3_LINK_SUCCESS;
+ GNUNET_TESTBED_operation_done (op);
+ op = GNUNET_TESTBED_peer_destroy (master_peer);
+ break;
+ case SLAVE3_LINK_SUCCESS:
+ check_operation_success (event);
+ result = SUCCESS;
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 3), &do_shutdown,
+ NULL);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the host which has been registered
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+registration_cont (void *cls, const char *emsg)
+{
+ rh = NULL;
+ switch (result)
+ {
+ case MASTER_PEER_START_SUCCESS:
+ GNUNET_assert (NULL == emsg);
+ GNUNET_assert (NULL != mc);
+ result = SLAVE1_REGISTERED;
+ slave2 = GNUNET_TESTBED_host_create_with_id (2, "127.0.0.1", NULL, 0);
+ GNUNET_assert (NULL != slave2);
+ rh = GNUNET_TESTBED_register_host (mc, slave2, &registration_cont, NULL);
+ GNUNET_assert (NULL != rh);
+ break;
+ case SLAVE1_REGISTERED:
+ GNUNET_assert (NULL == emsg);
+ GNUNET_assert (NULL != mc);
+ result = SLAVE2_REGISTERED;
+ GNUNET_assert (NULL != cfg);
+ op = GNUNET_TESTBED_controller_link (NULL, mc, slave, NULL, cfg,
+ GNUNET_YES);
+ GNUNET_assert (NULL != op);
+ break;
+ case SLAVE2_PEER_DESTROY_SUCCESS:
+ GNUNET_assert (NULL == emsg);
+ GNUNET_assert (NULL != mc);
+ GNUNET_assert (NULL == op);
+ result = SLAVE3_REGISTERED;
+ op = GNUNET_TESTBED_controller_link (NULL, mc, slave3, NULL, cfg,
+ GNUNET_YES);
+ GNUNET_assert (NULL != op);
+ break;
+ default:
+ GNUNET_break (0);
+ do_abort_now (NULL);
+ }
+}
+
+/**
+ * Callback to signal successfull startup of the controller process
+ *
+ * @param cls the closure from GNUNET_TESTBED_controller_start()
+ * @param cfg the configuration with which the controller has been started;
+ * NULL if status is not GNUNET_OK
+ * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
+ * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
+ */
+static void
+status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config,
+ int status)
+{
+ switch (result)
+ {
+ case INIT:
+ GNUNET_assert (GNUNET_OK == status);
+ event_mask = 0;
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
+ event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
+ event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ mc = GNUNET_TESTBED_controller_connect (config, host, event_mask,
+ &controller_cb, NULL);
+ GNUNET_assert (NULL != mc);
+ result = MASTER_STARTED;
+ op = GNUNET_TESTBED_peer_create (mc, host, cfg, peer_create_cb, NULL);
+ GNUNET_assert (NULL != op);
+ break;
+ default:
+ GNUNET_break (0);
+ cp = NULL;
+ do_abort_now (NULL);
+ }
+}
+
+
+/**
+ * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
+ * inform whether the given host is habitable or not. The Handle returned by
+ * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
+ *
+ * @param cls NULL
+ * @param host the host whose status is being reported; will be NULL if the host
+ * given to GNUNET_TESTBED_is_host_habitable() is NULL
+ * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
+ */
+static void
+host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *_host,
+ int status)
+{
+ hc_handle = NULL;
+ if (GNUNET_NO == status)
+ {
+ (void) PRINTF ("%s",
+ "Unable to run the test as this system is not configured "
+ "to use password less SSH logins to localhost.\n"
+ "Skipping test\n");
+ GNUNET_SCHEDULER_cancel (abort_task);
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ (void) GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ result = SKIP;
+ return;
+ }
+ cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, cfg, status_cb,
+ NULL);
+}
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
+ GNUNET_assert (NULL != host);
+ if (NULL ==
+ (hc_handle =
+ GNUNET_TESTBED_is_host_habitable (host, config, &host_habitable_cb,
+ NULL)))
+ {
+ GNUNET_TESTBED_host_destroy (host);
+ host = NULL;
+ (void) PRINTF ("%s",
+ "Unable to run the test as this system is not configured "
+ "to use password less SSH logins to localhost.\n"
+ "Marking test as successful\n");
+ result = SKIP;
+ return;
+ }
+ cfg = GNUNET_CONFIGURATION_dup (config);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES, 5), &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ char *const argv2[] = { "test_testbed_api_controllerlink",
+ "-c", "test_testbed_api.conf",
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ result = INIT;
+ ret =
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api_controllerlink", "nohelp", options,
+ &run, NULL);
+ if (GNUNET_OK != ret)
+ return 1;
+ switch (result)
+ {
+ case SUCCESS:
+ return 0;
+ case SKIP:
+ return 77; /* Mark test as skipped */
+ default:
+ return 1;
+ }
+}
+
+/* end of test_testbed_api_controllerlink.c */
diff --git a/src/testbed/test_testbed_api_hosts.c b/src/testbed/test_testbed_api_hosts.c
new file mode 100644
index 0000000..51284ea
--- /dev/null
+++ b/src/testbed/test_testbed_api_hosts.c
@@ -0,0 +1,130 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/test_testbed_api_hosts.c
+ * @brief tests cases for testbed_api_hosts.c
+ * @author Sree Harsha Totakura
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "testbed_api_hosts.h"
+
+
+#define TIME_REL_SECS(sec) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
+
+/**
+ * Host we are creating and using
+ */
+static struct GNUNET_TESTBED_Host *host;
+
+/**
+ * An array of hosts which are loaded from a file
+ */
+static struct GNUNET_TESTBED_Host **hosts;
+
+/**
+ * Number of hosts in the above list
+ */
+static unsigned int num_hosts;
+
+/**
+ * Global test status
+ */
+static int status;
+
+/**
+ * Shutdown task identifier
+ */
+GNUNET_SCHEDULER_TaskIdentifier shutdown_id;
+
+/**
+ * The shutdown task
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_TESTBED_host_destroy (host);
+ while (0 != num_hosts)
+ {
+ GNUNET_TESTBED_host_destroy (hosts[num_hosts - 1]);
+ num_hosts--;
+ }
+ GNUNET_free (hosts);
+}
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ host = GNUNET_TESTBED_host_create ("localhost", NULL, 0);
+ GNUNET_assert (NULL != host);
+ GNUNET_assert (0 != GNUNET_TESTBED_host_get_id_ (host));
+ GNUNET_TESTBED_host_destroy (host);
+ host = GNUNET_TESTBED_host_create (NULL, NULL, 0);
+ GNUNET_assert (NULL != host);
+ GNUNET_assert (0 == GNUNET_TESTBED_host_get_id_ (host));
+ GNUNET_assert (host == GNUNET_TESTBED_host_lookup_by_id_ (0));
+ hosts = NULL;
+ num_hosts = GNUNET_TESTBED_hosts_load_from_file ("sample_hosts.txt", &hosts);
+ GNUNET_assert (15 == num_hosts);
+ GNUNET_assert (NULL != hosts);
+ status = GNUNET_YES;
+ shutdown_id =
+ GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (2), &do_shutdown, NULL);
+}
+
+
+int
+main (int argc, char **argv)
+{
+ char *const argv2[] = { "test_testbed_api_hosts",
+ "-c", "test_testbed_api.conf",
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ status = GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api_hosts", "nohelp", options, &run,
+ NULL))
+ return 1;
+ return (GNUNET_OK == status) ? 0 : 1;
+}
+
+/* end of test_testbed_api_hosts.c */
diff --git a/src/testbed/test_testbed_api_operations.c b/src/testbed/test_testbed_api_operations.c
new file mode 100644
index 0000000..24f23be
--- /dev/null
+++ b/src/testbed/test_testbed_api_operations.c
@@ -0,0 +1,430 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/test_testbed_api_operations.c
+ * @brief tests cases for testbed_api_operations.c
+ * @author Sree Harsha Totakura
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "testbed_api_operations.h"
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Queue A. Initially the max active is set to 2 and then reduced to 0 - this
+ * should block op2 even after op1 has finished. Later the max active is set to
+ * 2 and this should start op2
+ */
+struct OperationQueue *q1;
+
+/**
+ * Queue B. Max active set to 2 is not changed throughout the test
+ */
+struct OperationQueue *q2;
+
+/**
+ * This operation should go into both queues and block op2 until it is done
+ */
+struct GNUNET_TESTBED_Operation *op1;
+
+/**
+ * This operation should go into q1 and q2
+ */
+struct GNUNET_TESTBED_Operation *op2;
+
+/**
+ * This operation should go into both queues and should consume 2 units of
+ * resources on both queues. Since op2 needs a resource from both queues and is
+ * queues before this operation, it will be blocked until op2 is released even
+ * though q1 has
+ */
+struct GNUNET_TESTBED_Operation *op3;
+
+/**
+ * Just like op3, this operation also consumes 2 units of resources on both
+ * queues. Since this is queued after op3 and both queues are at max active
+ * 2. This will be blocked until op3 is done.
+ */
+struct GNUNET_TESTBED_Operation *op4;
+
+/**
+ * This operation is started after op4 is released and should consume only 1
+ * resource on queue q1. It should be started along with op6 and op7
+ */
+struct GNUNET_TESTBED_Operation *op5;
+
+/**
+ * This operation is started after op4 is released and should consume only 1
+ * resource on q2. It should be started along with op5 and op7
+ */
+struct GNUNET_TESTBED_Operation *op6;
+
+/**
+ * This operation is started after op4 is released and should consume 1 resource
+ * on both queues q1 and q1. It should be started along with op5 and op6
+ */
+struct GNUNET_TESTBED_Operation *op7;
+
+/**
+ * The delay task identifier
+ */
+GNUNET_SCHEDULER_TaskIdentifier step_task;
+
+
+/**
+ * Enumeration of test stages
+ */
+enum Test
+{
+ /**
+ * Initial stage
+ */
+ TEST_INIT,
+
+ /**
+ * op1 has been started
+ */
+ TEST_OP1_STARTED,
+
+ /**
+ * op1 has been released
+ */
+ TEST_OP1_RELEASED,
+
+ /**
+ * Temporary pause where no operations should start as we set max active in q1
+ * to 0 in stage TEST_OP1_STARTED
+ */
+ TEST_PAUSE,
+
+ /**
+ * op2 has started
+ */
+ TEST_OP2_STARTED,
+
+ /**
+ * op2 released
+ */
+ TEST_OP2_RELEASED,
+
+ /**
+ * op3 has started
+ */
+ TEST_OP3_STARTED,
+
+ /**
+ * op3 has finished
+ */
+ TEST_OP3_RELEASED,
+
+ /**
+ * op4 has started
+ */
+ TEST_OP4_STARTED,
+
+ /**
+ * op4 has released
+ */
+ TEST_OP4_RELEASED,
+
+ /**
+ * op5, op6, op7 started
+ */
+ TEST_OP5_6_7_STARTED,
+
+ /**
+ * op5 has released
+ */
+ TEST_OP5_RELEASED,
+
+ /**
+ * op6 has released
+ */
+ TEST_OP6_RELEASED,
+
+ /**
+ * op7 has released
+ */
+ TEST_OP7_RELEASED
+};
+
+/**
+ * The test result
+ */
+enum Test result;
+
+
+/**
+ * Function to call to start an operation once all
+ * queues the operation is part of declare that the
+ * operation can be activated.
+ */
+static void
+start_cb (void *cls);
+
+
+/**
+ * Function to cancel an operation (release all associated resources). This can
+ * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
+ * operation generated an event) or AFTER the operation generated an event due
+ * to a call to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that
+ * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'.
+ * Implementations of this function are expected to clean up whatever state is
+ * in 'cls' and release all resources associated with the operation.
+ */
+static void
+release_cb (void *cls);
+
+
+/**
+ * Task to simulate artificial delay and change the test stage
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+step (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != step_task);
+ step_task = GNUNET_SCHEDULER_NO_TASK;
+ switch (result)
+ {
+ case TEST_OP1_STARTED:
+ GNUNET_TESTBED_operation_release_ (op1);
+ GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 0);
+ op3 = GNUNET_TESTBED_operation_create_ (&op3, &start_cb, &release_cb);
+ GNUNET_TESTBED_operation_queue_insert2_ (q1, op3, 2);
+ GNUNET_TESTBED_operation_queue_insert2_ (q2, op3, 2);
+ GNUNET_TESTBED_operation_begin_wait_ (op3);
+ op4 = GNUNET_TESTBED_operation_create_ (&op4, &start_cb, &release_cb);
+ GNUNET_TESTBED_operation_queue_insert2_ (q1, op4, 2);
+ GNUNET_TESTBED_operation_queue_insert2_ (q2, op4, 2);
+ GNUNET_TESTBED_operation_begin_wait_ (op4);
+ break;
+ case TEST_OP1_RELEASED:
+ result = TEST_PAUSE;
+ GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 2);
+ break;
+ case TEST_OP2_STARTED:
+ GNUNET_TESTBED_operation_release_ (op2);
+ break;
+ case TEST_OP3_STARTED:
+ GNUNET_TESTBED_operation_release_ (op3);
+ break;
+ case TEST_OP4_STARTED:
+ GNUNET_TESTBED_operation_release_ (op4);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Function to call to start an operation once all
+ * queues the operation is part of declare that the
+ * operation can be activated.
+ */
+static void
+start_cb (void *cls)
+{
+ switch (result)
+ {
+ case TEST_INIT:
+ GNUNET_assert (&op1 == cls);
+ result = TEST_OP1_STARTED;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
+ step_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
+ break;
+ case TEST_PAUSE:
+ GNUNET_assert (&op2 == cls);
+ result = TEST_OP2_STARTED;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
+ step_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
+ break;
+ case TEST_OP2_RELEASED:
+ GNUNET_assert (&op3 == cls);
+ result = TEST_OP3_STARTED;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
+ step_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
+ break;
+ case TEST_OP3_RELEASED:
+ GNUNET_assert (&op4 == cls);
+ result = TEST_OP4_STARTED;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
+ step_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
+ break;
+ case TEST_OP4_RELEASED:
+ {
+ static int nops;
+
+ nops++;
+ if (nops == 3)
+ {
+ result = TEST_OP5_6_7_STARTED;
+ GNUNET_TESTBED_operation_release_ (op5);
+ op5 = NULL;
+ }
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Function to cancel an operation (release all associated resources). This can
+ * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
+ * operation generated an event) or AFTER the operation generated an event due
+ * to a call to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that
+ * a callback to the 'OperationStart' preceeds the call to 'OperationRelease'.
+ * Implementations of this function are expected to clean up whatever state is
+ * in 'cls' and release all resources associated with the operation.
+ */
+static void
+release_cb (void *cls)
+{
+ switch (result)
+ {
+ case TEST_OP1_STARTED:
+ GNUNET_assert (&op1 == cls);
+ result = TEST_OP1_RELEASED;
+ op1 = NULL;
+ step_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
+ break;
+ case TEST_OP2_STARTED:
+ GNUNET_assert (&op2 == cls);
+ result = TEST_OP2_RELEASED;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
+ //step_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &step, NULL);
+ break;
+ case TEST_OP3_STARTED:
+ GNUNET_assert (&op3 == cls);
+ result = TEST_OP3_RELEASED;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
+ break;
+ case TEST_OP4_STARTED:
+ GNUNET_assert (&op4 == cls);
+ result = TEST_OP4_RELEASED;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == step_task);
+ op5 = GNUNET_TESTBED_operation_create_ (&op5, &start_cb, &release_cb);
+ GNUNET_TESTBED_operation_queue_insert2_ (q1, op5, 1);
+ GNUNET_TESTBED_operation_begin_wait_ (op5);
+ op6 = GNUNET_TESTBED_operation_create_ (&op6, &start_cb, &release_cb);
+ GNUNET_TESTBED_operation_queue_insert2_ (q2, op6, 1);
+ GNUNET_TESTBED_operation_begin_wait_ (op6);
+ op7 = GNUNET_TESTBED_operation_create_ (&op7, &start_cb, &release_cb);
+ GNUNET_TESTBED_operation_queue_insert2_ (q1, op7, 1);
+ GNUNET_TESTBED_operation_queue_insert2_ (q2, op7, 1);
+ GNUNET_TESTBED_operation_begin_wait_ (op7);
+ break;
+ case TEST_OP5_6_7_STARTED:
+ result = TEST_OP5_RELEASED;
+ op5 = NULL;
+ GNUNET_TESTBED_operation_release_ (op6);
+ break;
+ case TEST_OP5_RELEASED:
+ op6 = NULL;
+ result = TEST_OP6_RELEASED;
+ GNUNET_TESTBED_operation_release_ (op7);
+ break;
+ case TEST_OP6_RELEASED:
+ result = TEST_OP7_RELEASED;
+ op7 = NULL;
+ GNUNET_TESTBED_operation_queue_destroy_ (q1);
+ GNUNET_TESTBED_operation_queue_destroy_ (q2);
+ q1 = NULL;
+ q2 = NULL;
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ q1 = GNUNET_TESTBED_operation_queue_create_ (1);
+ GNUNET_assert (NULL != q1);
+ q2 = GNUNET_TESTBED_operation_queue_create_ (2);
+ GNUNET_assert (NULL != q2);
+ op1 = GNUNET_TESTBED_operation_create_ (&op1, start_cb, release_cb);
+ GNUNET_assert (NULL != op1);
+ op2 = GNUNET_TESTBED_operation_create_ (&op2, start_cb, release_cb);
+ GNUNET_TESTBED_operation_queue_insert_ (q1, op1);
+ GNUNET_TESTBED_operation_queue_insert_ (q2, op1);
+ GNUNET_TESTBED_operation_begin_wait_ (op1);
+ GNUNET_TESTBED_operation_queue_insert_ (q1, op2);
+ GNUNET_TESTBED_operation_queue_insert_ (q2, op2);
+ GNUNET_TESTBED_operation_begin_wait_ (op2);
+ result = TEST_INIT;
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ int ret;
+ char *const argv2[] =
+ { "test_testbed_api_operations", "-c", "test_testbed_api.conf", NULL };
+ struct GNUNET_GETOPT_CommandLineOption options[] =
+ { GNUNET_GETOPT_OPTION_END };
+
+ ret =
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api_operations", "nohelp", options,
+ &run, NULL);
+ if ((GNUNET_OK != ret) || (TEST_OP7_RELEASED != result))
+ return 1;
+ op1 = NULL;
+ op2 = NULL;
+ op3 = NULL;
+ q1 = NULL;
+ q2 = NULL;
+ return 0;
+}
+
+/* end of test_testbed_api_operations.c */
diff --git a/src/testbed/test_testbed_api_test.c b/src/testbed/test_testbed_api_test.c
new file mode 100644
index 0000000..705f52f
--- /dev/null
+++ b/src/testbed/test_testbed_api_test.c
@@ -0,0 +1,241 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 src/testbed/test_testbed_api_test.c
+ * @brief testing cases for testing high level testbed api helper functions
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_testbed_service.h"
+
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind,...) \
+ GNUNET_log (kind, __VA_ARGS__)
+
+/**
+ * Number of peers we want to start
+ */
+#define NUM_PEERS 25
+
+/**
+ * Array of peers
+ */
+static struct GNUNET_TESTBED_Peer **peers;
+
+/**
+ * Operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+/**
+ * Abort task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * shutdown task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+/**
+ * Testing result
+ */
+static int result;
+
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ if (NULL != op)
+ GNUNET_TESTBED_operation_done (op);
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * shortcut to exit during failure
+ */
+#define FAIL_TEST(cond) do { \
+ if (!(cond)) { \
+ GNUNET_break(0); \
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task) \
+ GNUNET_SCHEDULER_cancel (abort_task); \
+ abort_task = GNUNET_SCHEDULER_NO_TASK; \
+ if (GNUNET_SCHEDULER_NO_TASK == shutdown_task) \
+ shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL); \
+ return; \
+ } \
+ } while (0)
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
+}
+
+
+/**
+ * Callback to be called when the requested peer information is available
+ *
+ * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
+ * @param op the operation this callback corresponds to
+ * @param pinfo the result; will be NULL if the operation has failed
+ * @param emsg error message if the operation has failed; will be NULL if the
+ * operation is successfull
+ */
+static void
+peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
+ const struct GNUNET_TESTBED_PeerInformation *pinfo,
+ const char *emsg)
+{
+ FAIL_TEST (op == op_);
+ FAIL_TEST (NULL == cb_cls);
+ FAIL_TEST (NULL == emsg);
+ FAIL_TEST (GNUNET_TESTBED_PIT_IDENTITY == pinfo->pit);
+ FAIL_TEST (NULL != pinfo->result.id);
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ result = GNUNET_OK;
+ shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+}
+
+
+/**
+ * Callback to be called when an operation is completed
+ *
+ * @param cls the callback closure from functions generating an operation
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op_, const char *emsg)
+{
+ FAIL_TEST (NULL == cls);
+ FAIL_TEST (op == op_);
+ if (NULL != emsg)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "%s\n", emsg);
+ FAIL_TEST (0);
+ }
+ GNUNET_TESTBED_operation_done (op);
+ op = GNUNET_TESTBED_peer_get_information (peers[0],
+ GNUNET_TESTBED_PIT_IDENTITY,
+ &peerinfo_cb, NULL);
+}
+
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+ const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_CONNECT:
+ FAIL_TEST (event->details.peer_connect.peer1 == peers[0]);
+ FAIL_TEST (event->details.peer_connect.peer2 == peers[1]);
+ break;
+ default:
+ FAIL_TEST (0);
+ }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers_)
+{
+ unsigned int peer;
+
+ FAIL_TEST (NULL == cls);
+ FAIL_TEST (NUM_PEERS == num_peers);
+ FAIL_TEST (NULL != peers_);
+ for (peer = 0; peer < num_peers; peer++)
+ FAIL_TEST (NULL != peers_[peer]);
+ peers = peers_;
+ op = GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peers[0],
+ peers[1]);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ uint64_t event_mask;
+
+ result = GNUNET_SYSERR;
+ event_mask = 0;
+ event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
+ "test_testbed_api.conf", NUM_PEERS,
+ event_mask, &controller_event_cb, NULL,
+ &test_master, NULL);
+ if (GNUNET_OK != result)
+ return 1;
+ return 0;
+}
+
+/* end of test_testbed_api_test.c */
diff --git a/src/testbed/test_testbed_api_testbed_run.c b/src/testbed/test_testbed_api_testbed_run.c
new file mode 100644
index 0000000..9cad74a
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run.c
@@ -0,0 +1,223 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/test_testbed_api_testbed_run.c
+ * @brief Test cases for testing high-level testbed management
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_testbed_service.h"
+
+/**
+ * Number of peers we want to start
+ */
+#define NUM_PEERS 5
+
+/**
+ * The array of peers; we fill this as the peers are given to us by the testbed
+ */
+static struct GNUNET_TESTBED_Peer *peers[NUM_PEERS];
+
+/**
+ * Operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+/**
+ * Abort task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier abort_task;
+
+/**
+ * Current peer id
+ */
+unsigned int peer_id;
+
+/**
+ * Testing result
+ */
+static int result;
+
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (GNUNET_SCHEDULER_NO_TASK != abort_task)
+ GNUNET_SCHEDULER_cancel (abort_task);
+ GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */
+}
+
+
+/**
+ * abort task to run on test timed out
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
+ abort_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers_)
+{
+ result = GNUNET_OK;
+ GNUNET_assert (NULL != peers[0]);
+ op = GNUNET_TESTBED_peer_stop (peers[0], NULL, NULL);
+ GNUNET_assert (NULL != op);
+}
+
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+ const struct GNUNET_TESTBED_EventInformation *event)
+{
+
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_PEER_START:
+ GNUNET_assert (NULL == peers[peer_id]);
+ GNUNET_assert (NULL != event->details.peer_start.peer);
+ peers[peer_id++] = event->details.peer_start.peer;
+ break;
+ case GNUNET_TESTBED_ET_PEER_STOP:
+ GNUNET_assert (NULL != op);
+ GNUNET_TESTBED_operation_done (op);
+ GNUNET_assert (peers[0] == event->details.peer_stop.peer);
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ uint64_t event_mask;
+
+ event_mask = 0;
+ event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
+ event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
+ GNUNET_TESTBED_run (NULL, config, NUM_PEERS, event_mask, &controller_event_cb,
+ NULL, &test_master, NULL);
+ abort_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 300), &do_abort,
+ NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ char *argv2[] = {
+ "test_testbed_api_testbed_run",
+ "-c", NULL,
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ char *testname;
+ char *config_filename;
+ int ret;
+
+ if (NULL == (testname = strrchr (argv[0], (int) '_')))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ testname++;
+ testname = GNUNET_strdup (testname);
+#ifdef MINGW
+ {
+ char *period;
+
+ /* check and remove .exe extension */
+ period = strrchr (testname, (int) '.');
+ if (NULL != period)
+ *period = '\0';
+ else
+ GNUNET_break (0); /* Windows with no .exe? */
+ }
+#endif
+ if (0 != strcmp ("run", testname))
+ {
+ GNUNET_asprintf (&config_filename, "test_testbed_api_testbed_run_%s.conf",
+ testname);
+ }
+ else
+ config_filename = GNUNET_strdup ("test_testbed_api.conf");
+ GNUNET_free (testname);
+ argv2[2] = config_filename;
+ result = GNUNET_SYSERR;
+ ret =
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ "test_testbed_api_testbed_run", "nohelp", options,
+ &run, NULL);
+ GNUNET_free (config_filename);
+ if ((GNUNET_OK != ret) || (GNUNET_OK != result))
+ return 1;
+ return 0;
+}
+
+/* end of test_testbed_api_testbed_run.c */
diff --git a/src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf b/src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf
new file mode 100644
index 0000000..ee0480e
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf
@@ -0,0 +1,79 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+NEIGHBOUR_LIMIT = 100
+OVERLAY_TOPOLOGY = 2D_TORUS
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyclique.conf b/src/testbed/test_testbed_api_testbed_run_topologyclique.conf
new file mode 100644
index 0000000..4ac9266
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologyclique.conf
@@ -0,0 +1,79 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+NEIGHBOUR_LIMIT = 100
+OVERLAY_TOPOLOGY = CLIQUE
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf b/src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf
new file mode 100644
index 0000000..b66724f
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf
@@ -0,0 +1,80 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+NEIGHBOUR_LIMIT = 100
+OVERLAY_TOPOLOGY = FROM_FILE
+OVERLAY_TOPOLOGY_FILE = overlay_topology.txt
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyline.conf b/src/testbed/test_testbed_api_testbed_run_topologyline.conf
new file mode 100644
index 0000000..289ccba
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologyline.conf
@@ -0,0 +1,79 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+NEIGHBOUR_LIMIT = 100
+OVERLAY_TOPOLOGY = LINE
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyrandom.conf b/src/testbed/test_testbed_api_testbed_run_topologyrandom.conf
new file mode 100644
index 0000000..027602e
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologyrandom.conf
@@ -0,0 +1,79 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+OVERLAY_TOPOLOGY = RANDOM
+OVERLAY_RANDOM_LINKS = 5
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyring.conf b/src/testbed/test_testbed_api_testbed_run_topologyring.conf
new file mode 100644
index 0000000..22d934d
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologyring.conf
@@ -0,0 +1,79 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+NEIGHBOUR_LIMIT = 100
+OVERLAY_TOPOLOGY = RING
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf b/src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf
new file mode 100644
index 0000000..22d934d
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf
@@ -0,0 +1,79 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+NEIGHBOUR_LIMIT = 100
+OVERLAY_TOPOLOGY = RING
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
diff --git a/src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf b/src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf
new file mode 100644
index 0000000..fabc74f
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf
@@ -0,0 +1,83 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+OVERLAY_TOPOLOGY = SMALL_WORLD
+OVERLAY_RANDOM_LINKS = 3
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
+
+[consensus]
+AUTOSTART = NO
+
diff --git a/src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf b/src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf
new file mode 100644
index 0000000..7b26f4f
--- /dev/null
+++ b/src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf
@@ -0,0 +1,83 @@
+[testbed]
+AUTOSTART = NO
+PORT = 12113
+ACCEPT_FROM = 127.0.0.1;
+HOSTNAME = localhost
+OVERLAY_TOPOLOGY = SMALL_WORLD_RING
+OVERLAY_RANDOM_LINKS = 3
+#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
+
+[fs]
+AUTOSTART = NO
+
+[resolver]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[block]
+plugins = dht test
+
+[dhtcache]
+QUOTA = 1 MB
+DATABASE = sqlite
+
+[transport]
+PLUGINS = tcp
+ACCEPT_FROM6 = ::1;
+ACCEPT_FROM = 127.0.0.1;
+NEIGHBOUR_LIMIT = 50
+PORT = 12365
+
+[ats]
+WAN_QUOTA_OUT = 3932160
+WAN_QUOTA_IN = 3932160
+
+[core]
+PORT = 12092
+AUTOSTART = YES
+
+[arm]
+DEFAULTSERVICES = core transport
+PORT = 12366
+
+[transport-tcp]
+TIMEOUT = 300 s
+PORT = 12368
+
+[TESTING]
+NUM_PEERS = 5
+WEAKRANDOM = YES
+HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat
+MAX_CONCURRENT_SSH = 10
+USE_PROGRESSBARS = YES
+PEERGROUP_TIMEOUT = 2400 s
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[PATHS]
+SERVICEHOME = /tmp/test-testbed/
+
+[dns]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+
+[gns-helper-service-w32]
+AUTOSTART = NO
+
+[consensus]
+AUTOSTART = NO
+
diff --git a/src/testbed/test_testbed_api_topology.c b/src/testbed/test_testbed_api_topology.c
new file mode 100644
index 0000000..0098dbe
--- /dev/null
+++ b/src/testbed/test_testbed_api_topology.c
@@ -0,0 +1,172 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 src/testbed/test_testbed_api_topology.c
+ * @brief testing cases for testing high level testbed api helper functions
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_testbed_service.h"
+
+/**
+ * Number of peers we want to start
+ */
+#define NUM_PEERS 10
+
+/**
+ * Array of peers
+ */
+static struct GNUNET_TESTBED_Peer **peers;
+
+/**
+ * Operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+/**
+ * Shutdown task
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+/**
+ * Testing result
+ */
+static int result;
+
+/**
+ * Counter for counting overlay connections
+ */
+static unsigned int overlay_connects;
+
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL != op)
+ {
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ }
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+ const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_CONNECT:
+ overlay_connects++;
+ if ((NUM_PEERS) == overlay_connects)
+ {
+ result = GNUNET_OK;
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ }
+ break;
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+ GNUNET_assert (NULL != event->details.operation_finished.emsg);
+ break;
+ default:
+ GNUNET_break (0);
+ if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
+ (NULL != event->details.operation_finished.emsg))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "An operation failed with error: %s\n",
+ event->details.operation_finished.emsg);
+ result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers_)
+{
+ unsigned int peer;
+
+ GNUNET_assert (NULL == cls);
+ GNUNET_assert (NUM_PEERS == num_peers);
+ GNUNET_assert (NULL != peers_);
+ for (peer = 0; peer < num_peers; peer++)
+ GNUNET_assert (NULL != peers_[peer]);
+ peers = peers_;
+ overlay_connects = 0;
+ op = GNUNET_TESTBED_overlay_configure_topology (NULL, NUM_PEERS, peers, NULL,
+ NULL,
+ NULL,
+ GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI,
+ NUM_PEERS,
+ GNUNET_TESTBED_TOPOLOGY_OPTION_END);
+ GNUNET_assert (NULL != op);
+ shutdown_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 300),
+ do_shutdown, NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ uint64_t event_mask;
+
+ result = GNUNET_SYSERR;
+ event_mask = 0;
+ event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
+ "test_testbed_api.conf", NUM_PEERS,
+ event_mask, &controller_event_cb, NULL,
+ &test_master, NULL);
+ if (GNUNET_OK != result)
+ return 1;
+ return 0;
+}
+
+/* end of test_testbed_api_topology.c */
diff --git a/src/testbed/test_testbed_api_topology_clique.c b/src/testbed/test_testbed_api_topology_clique.c
new file mode 100644
index 0000000..3f1ed7a
--- /dev/null
+++ b/src/testbed/test_testbed_api_topology_clique.c
@@ -0,0 +1,168 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 src/testbed/test_testbed_api_topology.c
+ * @brief testing cases for testing high level testbed api helper functions
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_testbed_service.h"
+
+/**
+ * Number of peers we want to start
+ */
+#define NUM_PEERS 10
+
+/**
+ * Array of peers
+ */
+static struct GNUNET_TESTBED_Peer **peers;
+
+/**
+ * Operation handle
+ */
+static struct GNUNET_TESTBED_Operation *op;
+
+/**
+ * Shutdown task
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+/**
+ * Testing result
+ */
+static int result;
+
+/**
+ * Counter for counting overlay connections
+ */
+static unsigned int overlay_connects;
+
+
+/**
+ * Shutdown nicely
+ *
+ * @param cls NULL
+ * @param tc the task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL != op)
+ {
+ GNUNET_TESTBED_operation_done (op);
+ op = NULL;
+ }
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+/**
+ * Controller event callback
+ *
+ * @param cls NULL
+ * @param event the controller event
+ */
+static void
+controller_event_cb (void *cls,
+ const struct GNUNET_TESTBED_EventInformation *event)
+{
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_CONNECT:
+ overlay_connects++;
+ if ((NUM_PEERS * (NUM_PEERS - 1)) == overlay_connects)
+ {
+ result = GNUNET_OK;
+ GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ }
+ break;
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+ GNUNET_assert (NULL != event->details.operation_finished.emsg);
+ break;
+ default:
+ GNUNET_break (0);
+ result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
+ }
+}
+
+
+/**
+ * Signature of a main function for a testcase.
+ *
+ * @param cls closure
+ * @param num_peers number of peers in 'peers'
+ * @param peers handle to peers run in the testbed
+ */
+static void
+test_master (void *cls, unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers_)
+{
+ unsigned int peer;
+
+ GNUNET_assert (NULL == cls);
+ GNUNET_assert (NUM_PEERS == num_peers);
+ GNUNET_assert (NULL != peers_);
+ for (peer = 0; peer < num_peers; peer++)
+ GNUNET_assert (NULL != peers_[peer]);
+ peers = peers_;
+ overlay_connects = 0;
+ op = GNUNET_TESTBED_overlay_configure_topology (NULL, NUM_PEERS, peers, NULL,
+ NULL,
+ NULL,
+ GNUNET_TESTBED_TOPOLOGY_CLIQUE,
+ /* GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI, */
+ /* NUM_PEERS, */
+ GNUNET_TESTBED_TOPOLOGY_OPTION_END);
+ GNUNET_assert (NULL != op);
+ shutdown_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, 300),
+ do_shutdown, NULL);
+}
+
+
+/**
+ * Main function
+ */
+int
+main (int argc, char **argv)
+{
+ uint64_t event_mask;
+
+ result = GNUNET_SYSERR;
+ event_mask = 0;
+ event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
+ event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
+ "test_testbed_api.conf", NUM_PEERS,
+ event_mask, &controller_event_cb, NULL,
+ &test_master, NULL);
+ if (GNUNET_OK != result)
+ return 1;
+ return 0;
+}
+
+/* end of test_testbed_api_topology.c */
diff --git a/src/testbed/testbed.conf b/src/testbed/testbed.conf
deleted file mode 100644
index e69de29..0000000
--- a/src/testbed/testbed.conf
+++ /dev/null
diff --git a/src/testbed/testbed.conf.in b/src/testbed/testbed.conf.in
new file mode 100644
index 0000000..ec05c76
--- /dev/null
+++ b/src/testbed/testbed.conf.in
@@ -0,0 +1,18 @@
+[testbed]
+AUTOSTART = NO
+@UNIXONLY@ PORT = 2101
+HOSTNAME = localhost
+HOME = $SERVICEHOME
+BINARY = gnunet-service-testbed
+# Set this to the path where the testbed helper is installed
+# HELPER_BINARY_PATH = @prefix@/lib/gnunet/libexec/gnunet-helper-testbed
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+UNIXPATH = /tmp/gnunet-service-testbed.sock
+UNIX_MATCH_UID = YES
+UNIX_MATCH_GID = YES
+MAX_PARALLEL_OPERATIONS = 1000
+MAX_PARALLEL_SERVICE_CONNECTIONS = 256
+MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS = 1
+CACHE_SIZE = 30
+MAX_OPEN_FDS = 512
diff --git a/src/testbed/testbed.h b/src/testbed/testbed.h
index b7b10ff..180464b 100644
--- a/src/testbed/testbed.h
+++ b/src/testbed/testbed.h
@@ -24,28 +24,28 @@
* @author Christian Grothoff
*/
-#ifndef NEW_TESTING_H
-#define NEW_TESTING_H
+#ifndef TESTBED_H
+#define TESTBED_H
#include "gnunet_util_lib.h"
-
+GNUNET_NETWORK_STRUCT_BEGIN
/**
* Initial message from a client to a testing control service.
*/
-struct GNUNET_TESTBED_Message
+ struct GNUNET_TESTBED_InitMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_INIT
*/
struct GNUNET_MessageHeader header;
/**
- * Host ID that the controller is either given
- * (if this is the dominating client communicating
- * via stdin) or assumed to have (for peer-connections
- * between controllers).
+ * Host ID that the controller is either given (if this is the
+ * dominating client) or assumed to have (for peer-connections
+ * between controllers). A controller must check that all
+ * connections make consistent claims...
*/
uint32_t host_id GNUNET_PACKED;
@@ -55,6 +55,7 @@ struct GNUNET_TESTBED_Message
*/
uint64_t event_mask GNUNET_PACKED;
+ /* Followed by 0-terminated hostname of the controller */
};
@@ -65,7 +66,7 @@ struct GNUNET_TESTBED_AddHostMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST
*/
struct GNUNET_MessageHeader header;
@@ -96,12 +97,13 @@ struct GNUNET_TESTBED_AddHostMessage
/**
* Confirmation from the service that adding a host
* worked (or failed).
+ * FIXME: Where is this required?
*/
struct GNUNET_TESTBED_HostConfirmedMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS
*/
struct GNUNET_MessageHeader header;
@@ -110,9 +112,8 @@ struct GNUNET_TESTBED_HostConfirmedMessage
*/
uint32_t host_id GNUNET_PACKED;
- /* followed by the 0-terminated error message (on failure)
- (typical errors include failure to login and
- host-id already in use) */
+ /* followed by the 0-terminated error message (on failure)
+ * (typical errors include host-id already in use) */
};
@@ -125,7 +126,7 @@ struct GNUNET_TESTBED_ConfigureSharedServiceMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE
*/
struct GNUNET_MessageHeader header;
@@ -154,7 +155,7 @@ struct GNUNET_TESTBED_ControllerLinkMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS
*/
struct GNUNET_MessageHeader header;
@@ -164,35 +165,50 @@ struct GNUNET_TESTBED_ControllerLinkMessage
uint32_t delegated_host_id GNUNET_PACKED;
/**
+ * The id of the operation which created this message
+ */
+ uint64_t operation_id GNUNET_PACKED;
+
+ /**
* Which host is responsible for managing the delegation? NBO
*/
uint32_t slave_host_id GNUNET_PACKED;
/**
- * Is the receiving controller the master controller for
- * the slave host (and thus responsible for starting it?). NBO.
+ * The size of the uncompressed configuration
*/
- int32_t is_subordinate GNUNET_PACKED;
+ uint16_t config_size GNUNET_PACKED;
+
+ /**
+ * Set to 1 if the receiving controller is the master controller for
+ * the slave host (and thus responsible for starting it?). 0 if not
+ */
+ uint8_t is_subordinate;
/* followed by serialized slave configuration;
- gzip'ed configuration file in INI format */
+ * gzip'ed configuration file in INI format */
};
/**
- * Message sent from client to testing service to
+ * Message sent from client to testing service to
* create (configure, but not start) a peer.
*/
struct GNUNET_TESTBED_PeerCreateMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER
*/
struct GNUNET_MessageHeader header;
/**
+ * Unique operation id
+ */
+ uint64_t operation_id GNUNET_PACKED;
+
+ /**
* On which host should the peer be started?
*/
uint32_t host_id GNUNET_PACKED;
@@ -202,21 +218,26 @@ struct GNUNET_TESTBED_PeerCreateMessage
*/
uint32_t peer_id GNUNET_PACKED;
+ /**
+ * Size of the uncompressed configuration
+ */
+ uint32_t config_size GNUNET_PACKED;
+
/* followed by serialized peer configuration;
- gzip'ed configuration file in INI format */
-
+ * gzip'ed configuration file in INI format */
+
};
/**
- * Message sent from client to testing service to
+ * Message sent from client to testing service to
* reconfigure a (stopped) a peer.
*/
struct GNUNET_TESTBED_PeerReconfigureMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER
*/
struct GNUNET_MessageHeader header;
@@ -231,8 +252,8 @@ struct GNUNET_TESTBED_PeerReconfigureMessage
uint64_t operation_id GNUNET_PACKED;
/* followed by serialized peer configuration;
- gzip'ed configuration file in INI format */
-
+ * gzip'ed configuration file in INI format */
+
};
@@ -244,7 +265,7 @@ struct GNUNET_TESTBED_PeerStartMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_START_PEER
*/
struct GNUNET_MessageHeader header;
@@ -269,7 +290,7 @@ struct GNUNET_TESTBED_PeerStopMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER
*/
struct GNUNET_MessageHeader header;
@@ -294,7 +315,7 @@ struct GNUNET_TESTBED_PeerDestroyMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER
*/
struct GNUNET_MessageHeader header;
@@ -319,7 +340,7 @@ struct GNUNET_TESTBED_ConfigureUnderlayLinkMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_CONFIGURE_UNDERLAY_LINK
*/
struct GNUNET_MessageHeader header;
@@ -356,7 +377,7 @@ struct GNUNET_TESTBED_OverlayConnectMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT
*/
struct GNUNET_MessageHeader header;
@@ -375,6 +396,45 @@ struct GNUNET_TESTBED_OverlayConnectMessage
*/
uint32_t peer2 GNUNET_PACKED;
+ /**
+ * The ID of the host which runs peer2
+ */
+ uint32_t peer2_host_id GNUNET_PACKED;
+
+};
+
+
+/**
+ * Message sent from host controller of a peer(A) to the host controller of
+ * another peer(B) to request B to connect to A
+ */
+struct GNUNET_TESTBED_RemoteOverlayConnectMessage
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * The Unique ID of B
+ */
+ uint32_t peer GNUNET_PACKED;
+
+ /**
+ * The Operation ID that is used to identify this operation
+ */
+ uint64_t operation_id GNUNET_PACKED;
+
+ /**
+ * Identity of A
+ */
+ struct GNUNET_PeerIdentity peer_identity;
+
+ /**
+ * To be followed by the HELLO message of A
+ */
+ struct GNUNET_MessageHeader hello[0];
+
};
@@ -385,7 +445,7 @@ struct GNUNET_TESTBED_PeerEventMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT
*/
struct GNUNET_MessageHeader header;
@@ -394,7 +454,7 @@ struct GNUNET_TESTBED_PeerEventMessage
* either GNUNET_TESTBED_ET_PEER_START or GNUNET_TESTBED_ET_PEER_STOP.
*/
int32_t event_type GNUNET_PACKED;
-
+
/**
* Host where the peer is running.
*/
@@ -420,16 +480,16 @@ struct GNUNET_TESTBED_ConnectionEventMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT
*/
struct GNUNET_MessageHeader header;
/**
* 'enum GNUNET_TESTBED_EventType' (in NBO);
- * either GNUNET_TESTBED_ET_PEER_CONNECT or GNUNET_TESTBED_ET_PEER_DISCONNECT.
+ * either GNUNET_TESTBED_ET_CONNECT or GNUNET_TESTBED_ET_DISCONNECT.
*/
int32_t event_type GNUNET_PACKED;
-
+
/**
* First peer.
*/
@@ -455,7 +515,7 @@ struct GNUNET_TESTBED_OperationFailureEventMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT
*/
struct GNUNET_MessageHeader header;
@@ -464,7 +524,7 @@ struct GNUNET_TESTBED_OperationFailureEventMessage
* GNUNET_TESTBED_ET_OPERATION_FINISHED.
*/
int32_t event_type GNUNET_PACKED;
-
+
/**
* Operation ID of the operation that created this event.
*/
@@ -482,7 +542,7 @@ struct GNUNET_TESTBED_PeerCreateSuccessEventMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS
*/
struct GNUNET_MessageHeader header;
@@ -490,19 +550,12 @@ struct GNUNET_TESTBED_PeerCreateSuccessEventMessage
* Peer identity of the peer that was created.
*/
uint32_t peer_id GNUNET_PACKED;
-
+
/**
* Operation ID of the operation that created this event.
*/
uint64_t operation_id GNUNET_PACKED;
- /**
- * Identity of the peer.
- */
- struct GNUNET_PeerIdentity peer_id;
-
- /* followed by gzip-compressed configuration of the peer */
-
};
@@ -515,7 +568,7 @@ struct GNUNET_TESTBED_GenericOperationSuccessEventMessage
{
/**
- * Type is
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS
*/
struct GNUNET_MessageHeader header;
@@ -524,7 +577,7 @@ struct GNUNET_TESTBED_GenericOperationSuccessEventMessage
* GNUNET_TESTBED_ET_OPERATION_FINISHED.
*/
int32_t event_type GNUNET_PACKED;
-
+
/**
* Operation ID of the operation that created this event.
*/
@@ -532,4 +585,121 @@ struct GNUNET_TESTBED_GenericOperationSuccessEventMessage
};
+
+/**
+ * Message sent from client to testing service to
+ * obtain the configuration of a peer.
+ */
+struct GNUNET_TESTBED_PeerGetConfigurationMessage
+{
+
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique ID for the peer.
+ */
+ uint32_t peer_id GNUNET_PACKED;
+
+ /**
+ * Operation ID that is used to identify this operation.
+ */
+ uint64_t operation_id GNUNET_PACKED;
+
+};
+
+
+/**
+ * Peer configuration and identity reply from controller to a client.
+ */
+struct GNUNET_TESTBED_PeerConfigurationInformationMessage
+{
+
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * The id of the peer relevant to this information
+ */
+ uint32_t peer_id GNUNET_PACKED;
+
+ /**
+ * Operation ID of the operation that created this event.
+ */
+ uint64_t operation_id GNUNET_PACKED;
+
+ /**
+ * Identity of the peer.
+ */
+ struct GNUNET_PeerIdentity peer_identity;
+
+ /**
+ * The size of configuration when uncompressed
+ */
+ uint16_t config_size GNUNET_PACKED;
+
+ /* followed by gzip-compressed configuration of the peer */
+
+};
+
+
+/**
+ * Message to request configuration of a slave controller
+ */
+struct GNUNET_TESTBED_SlaveGetConfigurationMessage
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * The id of the slave host
+ */
+ uint32_t slave_id GNUNET_PACKED;
+
+ /**
+ * Operation ID
+ */
+ uint64_t operation_id GNUNET_PACKED;
+
+};
+
+
+/**
+ * Reply to GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIG message
+ */
+struct GNUNET_TESTBED_SlaveConfiguration
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * The id of the host where the slave is running
+ */
+ uint32_t slave_id GNUNET_PACKED;
+
+ /**
+ * Operation ID
+ */
+ uint64_t operation_id GNUNET_PACKED;
+
+ /**
+ * The size of the configuration when uncompressed
+ */
+ uint16_t config_size GNUNET_PACKED;
+
+ /* followed by gzip-compressed configuration of the peer */
+
+};
+
+
+GNUNET_NETWORK_STRUCT_END
#endif
+/* end of testbed.h */
diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c
index 5168081..054aa3b 100644
--- a/src/testbed/testbed_api.c
+++ b/src/testbed/testbed_api.c
@@ -24,15 +24,1772 @@
* This library is supposed to make it easier to write
* testcases and script large-scale benchmarks.
* @author Christian Grothoff
+ * @author Sree Harsha Totakura
*/
+
+
#include "platform.h"
#include "gnunet_testbed_service.h"
#include "gnunet_core_service.h"
#include "gnunet_constants.h"
#include "gnunet_transport_service.h"
#include "gnunet_hello_lib.h"
+#include <zlib.h>
+
+#include "testbed.h"
+#include "testbed_api.h"
+#include "testbed_api_hosts.h"
+#include "testbed_api_peers.h"
+#include "testbed_api_operations.h"
+
+/**
+ * Generic logging shorthand
+ */
+#define LOG(kind, ...) \
+ GNUNET_log_from (kind, "testbed-api", __VA_ARGS__);
+
+/**
+ * Debug logging
+ */
+#define LOG_DEBUG(...) \
+ LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
+
+/**
+ * Relative time seconds shorthand
+ */
+#define TIME_REL_SECS(sec) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
+
+
+/**
+ * Default server message sending retry timeout
+ */
+#define TIMEOUT_REL TIME_REL_SECS(1)
+
+
+/**
+ * Handle for controller process
+ */
+struct GNUNET_TESTBED_ControllerProc
+{
+ /**
+ * The process handle
+ */
+ struct GNUNET_HELPER_Handle *helper;
+
+ /**
+ * The arguments used to start the helper
+ */
+ char **helper_argv;
+
+ /**
+ * The host where the helper is run
+ */
+ struct GNUNET_TESTBED_Host *host;
+
+ /**
+ * The controller error callback
+ */
+ GNUNET_TESTBED_ControllerStatusCallback cb;
+
+ /**
+ * The closure for the above callback
+ */
+ void *cls;
+
+ /**
+ * The send handle for the helper
+ */
+ struct GNUNET_HELPER_SendHandle *shandle;
+
+ /**
+ * The message corresponding to send handle
+ */
+ struct GNUNET_MessageHeader *msg;
+
+ /**
+ * The configuration of the running testbed service
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+};
+
+
+/**
+ * The message queue for sending messages to the controller service
+ */
+struct MessageQueue
+{
+ /**
+ * The message to be sent
+ */
+ struct GNUNET_MessageHeader *msg;
+
+ /**
+ * next pointer for DLL
+ */
+ struct MessageQueue *next;
+
+ /**
+ * prev pointer for DLL
+ */
+ struct MessageQueue *prev;
+};
+
+
+/**
+ * Structure for a controller link
+ */
+struct ControllerLink
+{
+ /**
+ * The next ptr for DLL
+ */
+ struct ControllerLink *next;
+
+ /**
+ * The prev ptr for DLL
+ */
+ struct ControllerLink *prev;
+
+ /**
+ * The host which will be referred in the peer start request. This is the
+ * host where the peer should be started
+ */
+ struct GNUNET_TESTBED_Host *delegated_host;
+
+ /**
+ * The host which will contacted to delegate the peer start request
+ */
+ struct GNUNET_TESTBED_Host *slave_host;
+
+ /**
+ * The configuration to be used to connect to slave host
+ */
+ const struct GNUNET_CONFIGURATION_Handle *slave_cfg;
+
+ /**
+ * GNUNET_YES if the slave should be started (and stopped) by us; GNUNET_NO
+ * if we are just allowed to use the slave via TCP/IP
+ */
+ int is_subordinate;
+};
+
+
+/**
+ * handle for host registration
+ */
+struct GNUNET_TESTBED_HostRegistrationHandle
+{
+ /**
+ * The host being registered
+ */
+ struct GNUNET_TESTBED_Host *host;
+
+ /**
+ * The controller at which this host is being registered
+ */
+ struct GNUNET_TESTBED_Controller *c;
+
+ /**
+ * The Registartion completion callback
+ */
+ GNUNET_TESTBED_HostRegistrationCompletion cc;
+
+ /**
+ * The closure for above callback
+ */
+ void *cc_cls;
+};
+
+
+/**
+ * Context data for forwarded Operation
+ */
+struct ForwardedOperationData
+{
+
+ /**
+ * The callback to call when reply is available
+ */
+ GNUNET_CLIENT_MessageHandler cc;
+
+ /**
+ * The closure for the above callback
+ */
+ void *cc_cls;
+
+};
+
+
+/**
+ * Context data for get slave config operations
+ */
+struct GetSlaveConfigData
+{
+ /**
+ * The id of the slave controller
+ */
+ uint32_t slave_id;
+
+};
+
+
+/**
+ * Context data for controller link operations
+ */
+struct ControllerLinkData
+{
+ /**
+ * The controller link message
+ */
+ struct GNUNET_TESTBED_ControllerLinkMessage *msg;
+
+};
+
+
+struct SDEntry
+{
+ /**
+ * DLL next pointer
+ */
+ struct SDEntry *next;
+
+ /**
+ * DLL prev pointer
+ */
+ struct SDEntry *prev;
+
+ /**
+ * The value to store
+ */
+ unsigned int amount;
+};
+
+
+struct SDHandle
+{
+ /**
+ * DLL head for storing entries
+ */
+ struct SDEntry *head;
+
+ /**
+ * DLL tail for storing entries
+ */
+ struct SDEntry *tail;
+
+ /**
+ * Squared sum of data values
+ */
+ unsigned long long sqsum;
+
+ /**
+ * Sum of the data values
+ */
+ unsigned long sum;
+
+ /**
+ * The average of data amounts
+ */
+ float avg;
+
+ /**
+ * The variance
+ */
+ double vr;
+
+ /**
+ * Number of data values; also the length of DLL containing SDEntries
+ */
+ unsigned int cnt;
+
+ /**
+ * max number of entries we can have in the DLL
+ */
+ unsigned int max_cnt;
+};
+
+
+/**
+ * This variable is set to the operation that has been last marked as done. It
+ * is used to verify whether the state associated with an operation is valid
+ * after the first notify callback is called. Such checks are necessary for
+ * certain operations where we have 2 notify callbacks. Examples are
+ * OP_PEER_CREATE, OP_PEER_START/STOP, OP_OVERLAY_CONNECT.
+ *
+ * This variable should ONLY be used to compare; it is a dangling pointer!!
+ */
+static const struct GNUNET_TESTBED_Operation *last_finished_operation;
+
+/**
+ * Initialize standard deviation calculation handle
+ *
+ * @param max_cnt the maximum number of readings to keep
+ * @return the initialized handle
+ */
+static struct SDHandle *
+SD_init (unsigned int max_cnt)
+{
+ struct SDHandle *h;
+
+ GNUNET_assert (1 < max_cnt);
+ h = GNUNET_malloc (sizeof (struct SDHandle));
+ h->max_cnt = max_cnt;
+ return h;
+}
+
+
+/**
+ * Frees the memory allocated to the SD handle
+ *
+ * @param h the SD handle
+ */
+static void
+SD_destroy (struct SDHandle *h)
+{
+ struct SDEntry *entry;
+
+ while (NULL != (entry = h->head))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->head, h->tail, entry);
+ GNUNET_free (entry);
+ }
+ GNUNET_free (h);
+}
+
+
+/**
+ * Add a reading to SD
+ *
+ * @param h the SD handle
+ * @param amount the reading value
+ */
+static void
+SD_add_data (struct SDHandle *h, unsigned int amount)
+{
+ struct SDEntry *entry;
+ double sqavg;
+ double sqsum_avg;
+
+ entry = NULL;
+ if (h->cnt == h->max_cnt)
+ {
+ entry = h->head;
+ GNUNET_CONTAINER_DLL_remove (h->head, h->tail, entry);
+ h->sum -= entry->amount;
+ h->sqsum -=
+ ((unsigned long) entry->amount) * ((unsigned long) entry->amount);
+ h->cnt--;
+ }
+ GNUNET_assert (h->cnt < h->max_cnt);
+ if (NULL == entry)
+ entry = GNUNET_malloc (sizeof (struct SDEntry));
+ entry->amount = amount;
+ GNUNET_CONTAINER_DLL_insert_tail (h->head, h->tail, entry);
+ h->sum += amount;
+ h->cnt++;
+ h->avg = ((float) h->sum) / ((float) h->cnt);
+ h->sqsum += ((unsigned long) amount) * ((unsigned long) amount);
+ sqsum_avg = ((double) h->sqsum) / ((double) h->cnt);
+ sqavg = ((double) h->avg) * ((double) h->avg);
+ h->vr = sqsum_avg - sqavg;
+}
+
+
+/**
+ * Returns the factor by which the given amount differs from the standard deviation
+ *
+ * @param h the SDhandle
+ * @param amount the value for which the deviation is returned
+
+ * @return the deviation from the average; GNUNET_SYSERR if the deviation cannot
+ * be calculated OR 0 if the deviation is less than the average; a
+ * maximum of 4 is returned for deviations equal to or larger than 4
+ */
+static int
+SD_deviation_factor (struct SDHandle *h, unsigned int amount)
+{
+ double diff;
+ unsigned int n;
+
+ if (h->cnt < 2)
+ return GNUNET_SYSERR;
+ if (((float) amount) > h->avg)
+ diff = ((float) amount) - h->avg;
+ else
+ return 0; //diff = h->avg - ((float) amount);
+ diff *= diff;
+ for (n = 1; n < 4; n++)
+ if (diff < (((double) (n * n)) * h->vr))
+ break;
+ return n;
+}
+
+
+/**
+ * Returns the operation context with the given id if found in the Operation
+ * context queues of the controller
+ *
+ * @param c the controller whose queues are searched
+ * @param id the id which has to be checked
+ * @return the matching operation context; NULL if no match found
+ */
+static struct OperationContext *
+find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
+{
+ struct OperationContext *opc;
+
+ for (opc = c->ocq_head; NULL != opc; opc = opc->next)
+ {
+ if (id == opc->id)
+ return opc;
+ }
+ return NULL;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
+ * controller (testbed service)
+ *
+ * @param c the controller handler
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_addhostconfirm (struct GNUNET_TESTBED_Controller *c,
+ const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
+{
+ struct GNUNET_TESTBED_HostRegistrationHandle *rh;
+ char *emsg;
+ uint16_t msg_size;
+
+ rh = c->rh;
+ if (NULL == rh)
+ {
+ return GNUNET_OK;
+ }
+ if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
+ {
+ LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
+ GNUNET_TESTBED_host_get_id_ (rh->host), ntohl (msg->host_id));
+ return GNUNET_OK;
+ }
+ c->rh = NULL;
+ msg_size = ntohs (msg->header.size);
+ if (sizeof (struct GNUNET_TESTBED_HostConfirmedMessage) == msg_size)
+ {
+ LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
+ GNUNET_TESTBED_mark_host_registered_at_ (rh->host, c);
+ rh->cc (rh->cc_cls, NULL);
+ GNUNET_free (rh);
+ return GNUNET_OK;
+ }
+ /* We have an error message */
+ emsg = (char *) &msg[1];
+ if ('\0' !=
+ emsg[msg_size - sizeof (struct GNUNET_TESTBED_HostConfirmedMessage)])
+ {
+ GNUNET_break (0);
+ GNUNET_free (rh);
+ return GNUNET_NO;
+ }
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Adding host %u failed with error: %s\n"),
+ ntohl (msg->host_id), emsg);
+ rh->cc (rh->cc_cls, emsg);
+ GNUNET_free (rh);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handler for forwarded operations
+ *
+ * @param c the controller handle
+ * @param opc the opearation context
+ * @param msg the message
+ */
+static void
+handle_forwarded_operation_msg (struct GNUNET_TESTBED_Controller *c,
+ struct OperationContext *opc,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct ForwardedOperationData *fo_data;
+
+ fo_data = opc->data;
+ if (NULL != fo_data->cc)
+ fo_data->cc (fo_data->cc_cls, msg);
+ GNUNET_CONTAINER_DLL_remove (c->ocq_head, c->ocq_tail, opc);
+ GNUNET_free (fo_data);
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
+ * controller (testbed service)
+ *
+ * @param c the controller handler
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_opsuccess (struct GNUNET_TESTBED_Controller *c,
+ const struct
+ GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
+{
+ struct OperationContext *opc;
+ struct GNUNET_TESTBED_EventInformation event;
+ uint64_t op_id;
+
+ op_id = GNUNET_ntohll (msg->operation_id);
+ LOG_DEBUG ("Operation %lu successful\n", op_id);
+ if (NULL == (opc = find_opc (c, op_id)))
+ {
+ LOG_DEBUG ("Operation not found\n");
+ return GNUNET_YES;
+ }
+ event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
+ event.details.operation_finished.operation = opc->op;
+ event.details.operation_finished.op_cls = opc->op_cls;
+ event.details.operation_finished.emsg = NULL;
+ event.details.operation_finished.generic = NULL;
+ switch (opc->type)
+ {
+ case OP_FORWARDED:
+ {
+ handle_forwarded_operation_msg (c, opc,
+ (const struct GNUNET_MessageHeader *) msg);
+ return GNUNET_YES;
+ }
+ break;
+ case OP_PEER_DESTROY:
+ {
+ struct GNUNET_TESTBED_Peer *peer;
+
+ peer = opc->data;
+ GNUNET_free (peer);
+ opc->data = NULL;
+ //PEERDESTROYDATA
+ }
+ break;
+ case OP_LINK_CONTROLLERS:
+ {
+ struct ControllerLinkData *data;
+
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ GNUNET_free (data);
+ opc->data = NULL;
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ opc->state = OPC_STATE_FINISHED;
+ if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
+ {
+ if (NULL != c->cc)
+ c->cc (c->cc_cls, &event);
+ }
+ else
+ LOG_DEBUG ("Not calling callback\n");
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCREATESUCCESS message from
+ * controller (testbed service)
+ *
+ * @param c the controller handle
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_peer_create_success (struct GNUNET_TESTBED_Controller *c,
+ const struct
+ GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
+{
+ struct OperationContext *opc;
+ struct PeerCreateData *data;
+ struct GNUNET_TESTBED_Peer *peer;
+ GNUNET_TESTBED_PeerCreateCallback cb;
+ void *cls;
+ uint64_t op_id;
+
+ GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
+ ntohs (msg->header.size));
+ op_id = GNUNET_ntohll (msg->operation_id);
+ if (NULL == (opc = find_opc (c, op_id)))
+ {
+ LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
+ return GNUNET_YES;
+ }
+ if (OP_FORWARDED == opc->type)
+ {
+ handle_forwarded_operation_msg (c, opc,
+ (const struct GNUNET_MessageHeader *) msg);
+ return GNUNET_YES;
+ }
+ GNUNET_assert (OP_PEER_CREATE == opc->type);
+ GNUNET_assert (NULL != opc->data);
+ data = opc->data;
+ GNUNET_assert (NULL != data->peer);
+ peer = data->peer;
+ GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
+ peer->state = PS_CREATED;
+ cb = data->cb;
+ cls = data->cls;
+ GNUNET_free (opc->data);
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ opc->state = OPC_STATE_FINISHED;
+ if (NULL != cb)
+ cb (cls, peer, NULL);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEEREVENT message from
+ * controller (testbed service)
+ *
+ * @param c the controller handler
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_peer_event (struct GNUNET_TESTBED_Controller *c,
+ const struct GNUNET_TESTBED_PeerEventMessage *msg)
+{
+ struct OperationContext *opc;
+ struct GNUNET_TESTBED_Peer *peer;
+ struct PeerEventData *data;
+ GNUNET_TESTBED_PeerChurnCallback pcc;
+ void *pcc_cls;
+ struct GNUNET_TESTBED_EventInformation event;
+ uint64_t op_id;
+
+ GNUNET_assert (sizeof (struct GNUNET_TESTBED_PeerEventMessage) ==
+ ntohs (msg->header.size));
+ op_id = GNUNET_ntohll (msg->operation_id);
+ if (NULL == (opc = find_opc (c, op_id)))
+ {
+ LOG_DEBUG ("Operation not found\n");
+ return GNUNET_YES;
+ }
+ if (OP_FORWARDED == opc->type)
+ {
+ handle_forwarded_operation_msg (c, opc,
+ (const struct GNUNET_MessageHeader *) msg);
+ return GNUNET_YES;
+ }
+ GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ peer = data->peer;
+ GNUNET_assert (NULL != peer);
+ event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
+ switch (event.type)
+ {
+ case GNUNET_TESTBED_ET_PEER_START:
+ peer->state = PS_STARTED;
+ event.details.peer_start.host = peer->host;
+ event.details.peer_start.peer = peer;
+ break;
+ case GNUNET_TESTBED_ET_PEER_STOP:
+ peer->state = PS_STOPPED;
+ event.details.peer_stop.peer = peer;
+ break;
+ default:
+ GNUNET_assert (0); /* We should never reach this state */
+ }
+ pcc = data->pcc;
+ pcc_cls = data->pcc_cls;
+ GNUNET_free (data);
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ opc->state = OPC_STATE_FINISHED;
+ if (0 !=
+ ((GNUNET_TESTBED_ET_PEER_START | GNUNET_TESTBED_ET_PEER_STOP) &
+ c->event_mask))
+ {
+ if (NULL != c->cc)
+ c->cc (c->cc_cls, &event);
+ }
+ if (NULL != pcc)
+ pcc (pcc_cls, NULL);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONEVENT message from
+ * controller (testbed service)
+ *
+ * @param c the controller handler
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_peer_conevent (struct GNUNET_TESTBED_Controller *c,
+ const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
+{
+ struct OperationContext *opc;
+ struct OverlayConnectData *data;
+ GNUNET_TESTBED_OperationCompletionCallback cb;
+ void *cb_cls;
+ struct GNUNET_TESTBED_EventInformation event;
+ uint64_t op_id;
+
+ op_id = GNUNET_ntohll (msg->operation_id);
+ if (NULL == (opc = find_opc (c, op_id)))
+ {
+ LOG_DEBUG ("Operation not found\n");
+ return GNUNET_YES;
+ }
+ if (OP_FORWARDED == opc->type)
+ {
+ handle_forwarded_operation_msg (c, opc,
+ (const struct GNUNET_MessageHeader *) msg);
+ return GNUNET_YES;
+ }
+ GNUNET_assert (OP_OVERLAY_CONNECT == opc->type);
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
+ (ntohl (msg->peer2) == data->p2->unique_id));
+ event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
+ switch (event.type)
+ {
+ case GNUNET_TESTBED_ET_CONNECT:
+ event.details.peer_connect.peer1 = data->p1;
+ event.details.peer_connect.peer2 = data->p2;
+ break;
+ case GNUNET_TESTBED_ET_DISCONNECT:
+ GNUNET_assert (0); /* FIXME: implement */
+ break;
+ default:
+ GNUNET_assert (0); /* Should never reach here */
+ break;
+ }
+ cb = data->cb;
+ cb_cls = data->cb_cls;
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ opc->state = OPC_STATE_FINISHED;
+ if (NULL != cb)
+ cb (cb_cls, opc->op, NULL);
+ if (0 !=
+ ((GNUNET_TESTBED_ET_CONNECT | GNUNET_TESTBED_ET_DISCONNECT) &
+ c->event_mask))
+ {
+ if (NULL != c->cc)
+ c->cc (c->cc_cls, &event);
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG message from
+ * controller (testbed service)
+ *
+ * @param c the controller handler
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_peer_config (struct GNUNET_TESTBED_Controller *c,
+ const struct
+ GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
+{
+ struct OperationContext *opc;
+ struct GNUNET_TESTBED_Peer *peer;
+ struct PeerInfoData *data;
+ struct GNUNET_TESTBED_PeerInformation *pinfo;
+ GNUNET_TESTBED_PeerInfoCallback cb;
+ void *cb_cls;
+ uint64_t op_id;
+
+ op_id = GNUNET_ntohll (msg->operation_id);
+ if (NULL == (opc = find_opc (c, op_id)))
+ {
+ LOG_DEBUG ("Operation not found\n");
+ return GNUNET_YES;
+ }
+ if (OP_FORWARDED == opc->type)
+ {
+ handle_forwarded_operation_msg (c, opc,
+ (const struct GNUNET_MessageHeader *) msg);
+ return GNUNET_YES;
+ }
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ peer = data->peer;
+ GNUNET_assert (NULL != peer);
+ GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
+ pinfo = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerInformation));
+ pinfo->pit = data->pit;
+ cb = data->cb;
+ cb_cls = data->cb_cls;
+ GNUNET_free (data);
+ opc->data = NULL;
+ switch (pinfo->pit)
+ {
+ case GNUNET_TESTBED_PIT_IDENTITY:
+ pinfo->result.id = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
+ (void) memcpy (pinfo->result.id, &msg->peer_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ break;
+ case GNUNET_TESTBED_PIT_CONFIGURATION:
+ pinfo->result.cfg = /* Freed in oprelease_peer_getinfo */
+ GNUNET_TESTBED_extract_config_ (&msg->header);
+ break;
+ case GNUNET_TESTBED_PIT_GENERIC:
+ GNUNET_assert (0); /* never reach here */
+ break;
+ }
+ opc->data = pinfo;
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ opc->state = OPC_STATE_FINISHED;
+ if (NULL != cb)
+ cb (cb_cls, opc->op, pinfo, NULL);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_OPERATIONFAILEVENT message from
+ * controller (testbed service)
+ *
+ * @param c the controller handler
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_op_fail_event (struct GNUNET_TESTBED_Controller *c,
+ const struct GNUNET_TESTBED_OperationFailureEventMessage
+ *msg)
+{
+ struct OperationContext *opc;
+ const char *emsg;
+ uint64_t op_id;
+ struct GNUNET_TESTBED_EventInformation event;
+
+ op_id = GNUNET_ntohll (msg->operation_id);
+ if (NULL == (opc = find_opc (c, op_id)))
+ {
+ LOG_DEBUG ("Operation not found\n");
+ return GNUNET_YES;
+ }
+ if (OP_FORWARDED == opc->type)
+ {
+ handle_forwarded_operation_msg (c, opc,
+ (const struct GNUNET_MessageHeader *) msg);
+ return GNUNET_YES;
+ }
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ opc->state = OPC_STATE_FINISHED;
+ emsg = GNUNET_TESTBED_parse_error_string_ (msg);
+ if (NULL == emsg)
+ emsg = "Unknown error";
+ if (OP_PEER_INFO == opc->type)
+ {
+ struct PeerInfoData *data;
+
+ data = opc->data;
+ if (NULL != data->cb)
+ data->cb (data->cb_cls, opc->op, NULL, emsg);
+ GNUNET_free (data);
+ return GNUNET_YES; /* We do not call controller callback for peer info */
+ }
+ if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
+ (NULL != c->cc))
+ {
+ event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
+ event.details.operation_finished.operation = opc->op;
+ event.details.operation_finished.op_cls = opc->op_cls;
+ event.details.operation_finished.emsg = emsg;
+ event.details.operation_finished.generic = NULL;
+ c->cc (c->cc_cls, &event);
+ if (event.details.operation_finished.operation == last_finished_operation)
+ return GNUNET_YES;
+ }
+ switch (opc->type)
+ {
+ case OP_PEER_CREATE:
+ {
+ struct PeerCreateData *data;
+
+ data = opc->data;
+ GNUNET_free (data->peer);
+ if (NULL != data->cb)
+ data->cb (data->cls, NULL, emsg);
+ GNUNET_free (data);
+ }
+ break;
+ case OP_PEER_START:
+ case OP_PEER_STOP:
+ {
+ struct PeerEventData *data;
+
+ data = opc->data;
+ if (NULL != data->pcc)
+ data->pcc (data->pcc_cls, emsg);
+ GNUNET_free (data);
+ }
+ break;
+ case OP_PEER_DESTROY:
+ break;
+ case OP_PEER_INFO:
+ GNUNET_assert (0);
+ case OP_OVERLAY_CONNECT:
+ {
+ struct OverlayConnectData *data;
+
+ data = opc->data;
+ data->failed = GNUNET_YES;
+ if (NULL != data->cb)
+ data->cb (data->cb_cls, opc->op, emsg);
+ }
+ break;
+ case OP_FORWARDED:
+ GNUNET_assert (0);
+ case OP_LINK_CONTROLLERS: /* No secondary callback */
+ break;
+ default:
+ GNUNET_break (0);
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Function to build GET_SLAVE_CONFIG message
+ *
+ * @param op_id the id this message should contain in its operation id field
+ * @param slave_id the id this message should contain in its slave id field
+ * @return newly allocated SlaveGetConfigurationMessage
+ */
+static struct GNUNET_TESTBED_SlaveGetConfigurationMessage *
+GNUNET_TESTBED_generate_slavegetconfig_msg_ (uint64_t op_id, uint32_t slave_id)
+{
+ struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
+ uint16_t msize;
+
+ msize = sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage);
+ msg = GNUNET_malloc (msize);
+ msg->header.size = htons (msize);
+ msg->header.type =
+ htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION);
+ msg->operation_id = GNUNET_htonll (op_id);
+ msg->slave_id = htonl (slave_id);
+ return msg;
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG message from controller
+ * (testbed service)
+ *
+ * @param c the controller handler
+ * @param msg message received
+ * @return GNUNET_YES if we can continue receiving from service; GNUNET_NO if
+ * not
+ */
+static int
+handle_slave_config (struct GNUNET_TESTBED_Controller *c,
+ const struct GNUNET_TESTBED_SlaveConfiguration *msg)
+{
+ struct OperationContext *opc;
+ uint64_t op_id;
+ struct GNUNET_TESTBED_EventInformation event;
+
+ op_id = GNUNET_ntohll (msg->operation_id);
+ if (NULL == (opc = find_opc (c, op_id)))
+ {
+ LOG_DEBUG ("Operation not found\n");
+ return GNUNET_YES;
+ }
+ if (OP_GET_SLAVE_CONFIG != opc->type)
+ {
+ GNUNET_break (0);
+ return GNUNET_YES;
+ }
+ GNUNET_free (opc->data);
+ opc->data = NULL;
+ opc->state = OPC_STATE_FINISHED;
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
+ (NULL != c->cc))
+ {
+ opc->data = GNUNET_TESTBED_extract_config_ (&msg->header);
+ event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
+ event.details.operation_finished.generic = opc->data;
+ event.details.operation_finished.operation = opc->op;
+ event.details.operation_finished.op_cls = opc->op_cls;
+ event.details.operation_finished.emsg = NULL;
+ c->cc (c->cc_cls, &event);
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for messages from controller (testbed service)
+ *
+ * @param cls the controller handler
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_TESTBED_Controller *c = cls;
+ int status;
+ uint16_t msize;
+
+ c->in_receive = GNUNET_NO;
+ /* FIXME: Add checks for message integrity */
+ if (NULL == msg)
+ {
+ LOG_DEBUG ("Receive timed out or connection to service dropped\n");
+ return;
+ }
+ status = GNUNET_OK;
+ msize = ntohs (msg->size);
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS:
+ GNUNET_assert (msize >=
+ sizeof (struct GNUNET_TESTBED_HostConfirmedMessage));
+ status =
+ handle_addhostconfirm (c,
+ (const struct GNUNET_TESTBED_HostConfirmedMessage
+ *) msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS:
+ GNUNET_assert (msize ==
+ sizeof (struct
+ GNUNET_TESTBED_GenericOperationSuccessEventMessage));
+ status =
+ handle_opsuccess (c,
+ (const struct
+ GNUNET_TESTBED_GenericOperationSuccessEventMessage *)
+ msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS:
+ GNUNET_assert (msize ==
+ sizeof (struct
+ GNUNET_TESTBED_PeerCreateSuccessEventMessage));
+ status =
+ handle_peer_create_success (c,
+ (const struct
+ GNUNET_TESTBED_PeerCreateSuccessEventMessage
+ *) msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT:
+ GNUNET_assert (msize == sizeof (struct GNUNET_TESTBED_PeerEventMessage));
+ status =
+ handle_peer_event (c,
+ (const struct GNUNET_TESTBED_PeerEventMessage *)
+ msg);
+
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION:
+ GNUNET_assert (msize >=
+ sizeof (struct
+ GNUNET_TESTBED_PeerConfigurationInformationMessage));
+ status =
+ handle_peer_config (c,
+ (const struct
+ GNUNET_TESTBED_PeerConfigurationInformationMessage
+ *) msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT:
+ GNUNET_assert (msize ==
+ sizeof (struct GNUNET_TESTBED_ConnectionEventMessage));
+ status =
+ handle_peer_conevent (c,
+ (const struct
+ GNUNET_TESTBED_ConnectionEventMessage *) msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT:
+ GNUNET_assert (msize >=
+ sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage));
+ status =
+ handle_op_fail_event (c,
+ (const struct
+ GNUNET_TESTBED_OperationFailureEventMessage *)
+ msg);
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION:
+ GNUNET_assert (msize > sizeof (struct GNUNET_TESTBED_SlaveConfiguration));
+ status =
+ handle_slave_config (c,
+ (const struct GNUNET_TESTBED_SlaveConfiguration *)
+ msg);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ if ((GNUNET_OK == status) && (GNUNET_NO == c->in_receive))
+ {
+ c->in_receive = GNUNET_YES;
+ GNUNET_CLIENT_receive (c->client, &message_handler, c,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+}
+
+
+/**
+ * Function called to notify a client about the connection begin ready to queue
+ * more data. "buf" will be NULL and "size" zero if the connection was closed
+ * for writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_ready_notify (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_TESTBED_Controller *c = cls;
+ struct MessageQueue *mq_entry;
+
+ c->th = NULL;
+ mq_entry = c->mq_head;
+ GNUNET_assert (NULL != mq_entry);
+ if ((0 == size) && (NULL == buf)) /* Timeout */
+ {
+ LOG_DEBUG ("Message sending timed out -- retrying\n");
+ c->th =
+ GNUNET_CLIENT_notify_transmit_ready (c->client,
+ ntohs (mq_entry->msg->size),
+ TIMEOUT_REL, GNUNET_YES,
+ &transmit_ready_notify, c);
+ return 0;
+ }
+ GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
+ size = ntohs (mq_entry->msg->size);
+ memcpy (buf, mq_entry->msg, size);
+ LOG_DEBUG ("Message of type: %u and size: %u sent\n",
+ ntohs (mq_entry->msg->type), size);
+ GNUNET_free (mq_entry->msg);
+ GNUNET_CONTAINER_DLL_remove (c->mq_head, c->mq_tail, mq_entry);
+ GNUNET_free (mq_entry);
+ mq_entry = c->mq_head;
+ if (NULL != mq_entry)
+ c->th =
+ GNUNET_CLIENT_notify_transmit_ready (c->client,
+ ntohs (mq_entry->msg->size),
+ TIMEOUT_REL, GNUNET_YES,
+ &transmit_ready_notify, c);
+ if (GNUNET_NO == c->in_receive)
+ {
+ c->in_receive = GNUNET_YES;
+ GNUNET_CLIENT_receive (c->client, &message_handler, c,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ }
+ return size;
+}
+
+
+/**
+ * Queues a message in send queue for sending to the service
+ *
+ * @param controller the handle to the controller
+ * @param msg the message to queue
+ */
+void
+GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
+ struct GNUNET_MessageHeader *msg)
+{
+ struct MessageQueue *mq_entry;
+ uint16_t type;
+ uint16_t size;
+
+ type = ntohs (msg->type);
+ size = ntohs (msg->size);
+ GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
+ (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
+ mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
+ mq_entry->msg = msg;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Queueing message of type %u, size %u for sending\n", type,
+ ntohs (msg->size));
+ GNUNET_CONTAINER_DLL_insert_tail (controller->mq_head, controller->mq_tail,
+ mq_entry);
+ if (NULL == controller->th)
+ controller->th =
+ GNUNET_CLIENT_notify_transmit_ready (controller->client, size,
+ TIMEOUT_REL, GNUNET_YES,
+ &transmit_ready_notify,
+ controller);
+}
+
+
+/**
+ * Sends the given message as an operation. The given callback is called when a
+ * reply for the operation is available. Call
+ * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
+ * operation context if the cc hasn't been called
+ *
+ * @param controller the controller to which the message has to be sent
+ * @param operation_id the operation id of the message
+ * @param msg the message to send
+ * @param cc the callback to call when reply is available
+ * @param cc_cls the closure for the above callback
+ * @return the operation context which can be used to cancel the forwarded
+ * operation
+ */
+struct OperationContext *
+GNUNET_TESTBED_forward_operation_msg_ (struct GNUNET_TESTBED_Controller
+ *controller, uint64_t operation_id,
+ const struct GNUNET_MessageHeader *msg,
+ GNUNET_CLIENT_MessageHandler cc,
+ void *cc_cls)
+{
+ struct OperationContext *opc;
+ struct ForwardedOperationData *data;
+ struct GNUNET_MessageHeader *dup_msg;
+ uint16_t msize;
+
+ data = GNUNET_malloc (sizeof (struct ForwardedOperationData));
+ data->cc = cc;
+ data->cc_cls = cc_cls;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->c = controller;
+ opc->type = OP_FORWARDED;
+ opc->data = data;
+ opc->id = operation_id;
+ msize = ntohs (msg->size);
+ dup_msg = GNUNET_malloc (msize);
+ (void) memcpy (dup_msg, msg, msize);
+ GNUNET_TESTBED_queue_message_ (opc->c, dup_msg);
+ GNUNET_CONTAINER_DLL_insert_tail (controller->ocq_head, controller->ocq_tail,
+ opc);
+ return opc;
+}
+
+
+/**
+ * Function to cancel an operation created by simply forwarding an operation
+ * message.
+ *
+ * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
+ */
+void
+GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
+{
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_free (opc->data);
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * Do not call GNUNET_SERVER_mst_destroy in callback
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ *
+ * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
+ */
+static int
+helper_mst (void *cls, void *client, const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_TESTBED_ControllerProc *cp = cls;
+ const struct GNUNET_TESTBED_HelperReply *msg;
+ const char *hostname;
+ char *config;
+ uLongf config_size;
+ uLongf xconfig_size;
+
+ msg = (const struct GNUNET_TESTBED_HelperReply *) message;
+ GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) <
+ ntohs (msg->header.size));
+ GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
+ ntohs (msg->header.type));
+ config_size = (uLongf) ntohs (msg->config_size);
+ xconfig_size =
+ (uLongf) (ntohs (msg->header.size) -
+ sizeof (struct GNUNET_TESTBED_HelperReply));
+ config = GNUNET_malloc (config_size);
+ GNUNET_assert (Z_OK ==
+ uncompress ((Bytef *) config, &config_size,
+ (const Bytef *) &msg[1], xconfig_size));
+ GNUNET_assert (NULL == cp->cfg);
+ cp->cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_assert (GNUNET_CONFIGURATION_deserialize
+ (cp->cfg, config, config_size, GNUNET_NO));
+ GNUNET_free (config);
+ if ((NULL == cp->host) ||
+ (NULL == (hostname = GNUNET_TESTBED_host_get_hostname (cp->host))))
+ hostname = "localhost";
+ /* Change the hostname so that we can connect to it */
+ GNUNET_CONFIGURATION_set_value_string (cp->cfg, "testbed", "hostname",
+ hostname);
+ cp->cb (cp->cls, cp->cfg, GNUNET_OK);
+ return GNUNET_OK;
+}
+
+/**
+ * Continuation function from GNUNET_HELPER_send()
+ *
+ * @param cls closure
+ * @param result GNUNET_OK on success,
+ * GNUNET_NO if helper process died
+ * GNUNET_SYSERR during GNUNET_HELPER_stop
+ */
+static void
+clear_msg (void *cls, int result)
+{
+ struct GNUNET_TESTBED_ControllerProc *cp = cls;
+
+ GNUNET_assert (NULL != cp->shandle);
+ cp->shandle = NULL;
+ GNUNET_free (cp->msg);
+}
+
+
+/**
+ * Callback that will be called when the helper process dies. This is not called
+ * when the helper process is stoped using GNUNET_HELPER_stop()
+ *
+ * @param cls the closure from GNUNET_HELPER_start()
+ */
+static void
+helper_exp_cb (void *cls)
+{
+ struct GNUNET_TESTBED_ControllerProc *cp = cls;
+ GNUNET_TESTBED_ControllerStatusCallback cb;
+ void *cb_cls;
+ cb = cp->cb;
+ cb_cls = cp->cls;
+ cp->helper = NULL;
+ GNUNET_TESTBED_controller_stop (cp);
+ if (NULL != cb)
+ cb (cb_cls, NULL, GNUNET_SYSERR);
+}
+
+
+/**
+ * Function to call to start a link-controllers type operation once all queues
+ * the operation is part of declare that the operation can be activated.
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_link_controllers (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct ControllerLinkData *data;
+ struct GNUNET_TESTBED_ControllerLinkMessage *msg;
+
+ GNUNET_assert (NULL != opc->data);
+ data = opc->data;
+ msg = data->msg;
+ data->msg = NULL;
+ opc->state = OPC_STATE_STARTED;
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
+}
+
+
+/**
+ * Callback which will be called when link-controllers type operation is released
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_link_controllers (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct ControllerLinkData *data;
+
+ data = opc->data;
+ switch (opc->state)
+ {
+ case OPC_STATE_INIT:
+ GNUNET_free (data->msg);
+ break;
+ case OPC_STATE_STARTED:
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ break;
+ case OPC_STATE_FINISHED:
+ break;
+ }
+ GNUNET_free_non_null (data);
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Function to be called when get slave config operation is ready
+ *
+ * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
+ */
+static void
+opstart_get_slave_config (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct GetSlaveConfigData *data;
+ struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
+
+ data = opc->data;
+ msg = GNUNET_TESTBED_generate_slavegetconfig_msg_ (opc->id, data->slave_id);
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
+ opc->state = OPC_STATE_STARTED;
+}
+
+
+/**
+ * Function to be called when get slave config operation is cancelled or finished
+ *
+ * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
+ */
+static void
+oprelease_get_slave_config (void *cls)
+{
+ struct OperationContext *opc = cls;
+
+ switch (opc->state)
+ {
+ case OPC_STATE_INIT:
+ GNUNET_free (opc->data);
+ break;
+ case OPC_STATE_STARTED:
+ GNUNET_free (opc->data);
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ break;
+ case OPC_STATE_FINISHED:
+ if (NULL != opc->data)
+ GNUNET_CONFIGURATION_destroy (opc->data);
+ break;
+ }
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Initializes the operation queue for parallel overlay connects
+ *
+ * @param c the controller handle
+ * @param npoc the number of parallel overlay connects - the queue size
+ */
+static void
+GNUNET_TESTBED_set_num_parallel_overlay_connects_ (struct
+ GNUNET_TESTBED_Controller *c,
+ unsigned int npoc)
+{
+ fprintf (stderr, "%d", npoc);
+ GNUNET_free_non_null (c->tslots);
+ c->tslots_filled = 0;
+ c->num_parallel_connects = npoc;
+ c->tslots = GNUNET_malloc (npoc * sizeof (struct TimeSlot));
+ GNUNET_TESTBED_operation_queue_reset_max_active_
+ (c->opq_parallel_overlay_connect_operations, npoc);
+}
+
+
+/**
+ * Function to copy NULL terminated list of arguments
+ *
+ * @param argv the NULL terminated list of arguments. Cannot be NULL.
+ * @return the copied NULL terminated arguments
+ */
+static char **
+copy_argv (const char *const *argv)
+{
+ char **argv_dup;
+ unsigned int argp;
+
+ GNUNET_assert (NULL != argv);
+ for (argp = 0; NULL != argv[argp]; argp++) ;
+ argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
+ for (argp = 0; NULL != argv[argp]; argp++)
+ argv_dup[argp] = strdup (argv[argp]);
+ return argv_dup;
+}
+
+
+/**
+ * Function to join NULL terminated list of arguments
+ *
+ * @param argv1 the NULL terminated list of arguments. Cannot be NULL.
+ * @param argv2 the NULL terminated list of arguments. Cannot be NULL.
+ * @return the joined NULL terminated arguments
+ */
+static char **
+join_argv (const char *const *argv1, const char *const *argv2)
+{
+ char **argvj;
+ char *argv;
+ unsigned int carg;
+ unsigned int cnt;
+
+ carg = 0;
+ argvj = NULL;
+ for (cnt = 0; NULL != argv1[cnt]; cnt++)
+ {
+ argv = GNUNET_strdup (argv1[cnt]);
+ GNUNET_array_append (argvj, carg, argv);
+ }
+ for (cnt = 0; NULL != argv2[cnt]; cnt++)
+ {
+ argv = GNUNET_strdup (argv2[cnt]);
+ GNUNET_array_append (argvj, carg, argv);
+ }
+ GNUNET_array_append (argvj, carg, NULL);
+ return argvj;
+}
+
+
+/**
+ * Frees the given NULL terminated arguments
+ *
+ * @param argv the NULL terminated list of arguments
+ */
+static void
+free_argv (char **argv)
+{
+ unsigned int argp;
+
+ for (argp = 0; NULL != argv[argp]; argp++)
+ GNUNET_free (argv[argp]);
+ GNUNET_free (argv);
+}
+
+
+/**
+ * Generates arguments for opening a remote shell. Builds up the arguments
+ * from the environment variable GNUNET_TESTBED_RSH_CMD. The variable
+ * should not mention `-p' (port) option and destination address as these will
+ * be set locally in the function from its parameteres. If the environmental
+ * variable is not found then it defaults to `ssh -o BatchMode=yes -o
+ * NoHostAuthenticationForLocalhost=yes'
+ *
+ * @param port the destination port number
+ * @param dst the destination address
+ * @return NULL terminated list of arguments
+ */
+static char **
+gen_rsh_args (const char *port, const char *dst)
+{
+ static const char *default_ssh_args[] = {
+ "ssh",
+ "-o",
+ "BatchMode=yes",
+ "-o",
+ "NoHostAuthenticationForLocalhost=yes",
+ NULL
+ };
+ char **ssh_args;
+ char *ssh_cmd;
+ char *ssh_cmd_cp;
+ char *arg;
+ unsigned int cnt;
+
+ ssh_args = NULL;
+ if (NULL != (ssh_cmd = getenv ("GNUNET_TESTBED_RSH_CMD")))
+ {
+ ssh_cmd = GNUNET_strdup (ssh_cmd);
+ ssh_cmd_cp = ssh_cmd;
+ for (cnt = 0; NULL != (arg = strtok (ssh_cmd, " ")); ssh_cmd = NULL)
+ GNUNET_array_append (ssh_args, cnt, GNUNET_strdup (arg));
+ GNUNET_free (ssh_cmd_cp);
+ }
+ else
+ {
+ ssh_args = copy_argv (default_ssh_args);
+ cnt = (sizeof (default_ssh_args)) / (sizeof (const char *));
+ GNUNET_array_grow (ssh_args, cnt, cnt - 1);
+ }
+ GNUNET_array_append (ssh_args, cnt, GNUNET_strdup ("-p"));
+ GNUNET_array_append (ssh_args, cnt, GNUNET_strdup (port));
+ GNUNET_array_append (ssh_args, cnt, GNUNET_strdup (dst));
+ GNUNET_array_append (ssh_args, cnt, NULL);
+ return ssh_args;
+}
+
+
+/**
+ * Generates the arguments needed for executing the given binary in a remote
+ * shell. Builds the arguments from the environmental variable
+ * GNUNET_TETSBED_RSH_CMD_SUFFIX. If the environmental variable is not found,
+ * only the given binary name will be present in the returned arguments
+ *
+ * @param helper_binary_path the path of the binary to execute
+ * @return NULL-terminated args
+ */
+static char **
+gen_rsh_suffix_args (const char *helper_binary_path)
+{
+ char **rshell_args;
+ char *rshell_cmd;
+ char *rshell_cmd_cp;
+ char *arg;
+ unsigned int cnt;
+
+ rshell_args = NULL;
+ cnt = 0;
+ if (NULL != (rshell_cmd = getenv ("GNUNET_TESTBED_RSH_CMD_SUFFIX")))
+ {
+ rshell_cmd = GNUNET_strdup (rshell_cmd);
+ rshell_cmd_cp = rshell_cmd;
+ for (; NULL != (arg = strtok (rshell_cmd, " ")); rshell_cmd = NULL)
+ GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (arg));
+ GNUNET_free (rshell_cmd_cp);
+ }
+ GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (helper_binary_path));
+ GNUNET_array_append (rshell_args, cnt, NULL);
+ return rshell_args;
+}
+
+
+/**
+ * Starts a controller process at the given host
+ *
+ * @param trusted_ip the ip address of the controller which will be set as TRUSTED
+ * HOST(all connections form this ip are permitted by the testbed) when
+ * starting testbed controller at host. This can either be a single ip
+ * address or a network address in CIDR notation.
+ * @param host the host where the controller has to be started; NULL for
+ * localhost
+ * @param cfg template configuration to use for the remote controller; the
+ * remote controller will be started with a slightly modified
+ * configuration (port numbers, unix domain sockets and service home
+ * values are changed as per TESTING library on the remote host)
+ * @param cb function called when the controller is successfully started or
+ * dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
+ * called if cb is called with GNUNET_SYSERR as status. Will never be
+ * called in the same task as 'GNUNET_TESTBED_controller_start'
+ * (synchronous errors will be signalled by returning NULL). This
+ * parameter cannot be NULL.
+ * @param cls closure for above callbacks
+ * @return the controller process handle, NULL on errors
+ */
+struct GNUNET_TESTBED_ControllerProc *
+GNUNET_TESTBED_controller_start (const char *trusted_ip,
+ struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_TESTBED_ControllerStatusCallback cb,
+ void *cls)
+{
+ struct GNUNET_TESTBED_ControllerProc *cp;
+ struct GNUNET_TESTBED_HelperInit *msg;
+ const char *hostname;
+
+ static char *const binary_argv[] = {
+ HELPER_TESTBED_BINARY, NULL
+ };
+
+ hostname = NULL;
+ cp = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_ControllerProc));
+ if ((NULL == host) || (0 == GNUNET_TESTBED_host_get_id_ (host)))
+ {
+ cp->helper =
+ GNUNET_HELPER_start (GNUNET_YES, HELPER_TESTBED_BINARY, binary_argv,
+ &helper_mst, &helper_exp_cb, cp);
+ }
+ else
+ {
+ char *helper_binary_path;
+ char **ssh_args;
+ char **rshell_args;
+ const char *username;
+ char *port;
+ char *dst;
+
+ username = GNUNET_TESTBED_host_get_username_ (host);
+ hostname = GNUNET_TESTBED_host_get_hostname (host);
+ GNUNET_asprintf (&port, "%u", GNUNET_TESTBED_host_get_ssh_port_ (host));
+ if (NULL == username)
+ GNUNET_asprintf (&dst, "%s", hostname);
+ else
+ GNUNET_asprintf (&dst, "%s@%s", username, hostname);
+ LOG_DEBUG ("Starting SSH to destination %s\n", dst);
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
+ "HELPER_BINARY_PATH",
+ &helper_binary_path))
+ helper_binary_path =
+ GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
+ ssh_args = gen_rsh_args (port, dst);
+ rshell_args = gen_rsh_suffix_args (helper_binary_path);
+ cp->helper_argv =
+ join_argv ((const char **) ssh_args, (const char **) rshell_args);
+ free_argv (ssh_args);
+ free_argv (rshell_args);
+ GNUNET_free (port);
+ GNUNET_free (dst);
+ cp->helper =
+ GNUNET_HELPER_start (GNUNET_NO, "ssh", cp->helper_argv, &helper_mst,
+ &helper_exp_cb, cp);
+ GNUNET_free (helper_binary_path);
+ }
+ if (NULL == cp->helper)
+ {
+ if (NULL != cp->helper_argv)
+ free_argv (cp->helper_argv);
+ GNUNET_free (cp);
+ return NULL;
+ }
+ cp->host = host;
+ cp->cb = cb;
+ cp->cls = cls;
+ msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, hostname, cfg);
+ cp->msg = &msg->header;
+ cp->shandle =
+ GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
+ if (NULL == cp->shandle)
+ {
+ GNUNET_free (msg);
+ GNUNET_TESTBED_controller_stop (cp);
+ return NULL;
+ }
+ return cp;
+}
+
+
+/**
+ * Stop the controller process (also will terminate all peers and controllers
+ * dependent on this controller). This function blocks until the testbed has
+ * been fully terminated (!). The controller status cb from
+ * GNUNET_TESTBED_controller_start() will not be called.
+ *
+ * @param cproc the controller process handle
+ */
+void
+GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
+{
+ if (NULL != cproc->shandle)
+ GNUNET_HELPER_send_cancel (cproc->shandle);
+ if (NULL != cproc->helper)
+ GNUNET_HELPER_stop (cproc->helper);
+ if (NULL != cproc->cfg)
+ GNUNET_CONFIGURATION_destroy (cproc->cfg);
+ if (NULL != cproc->helper_argv)
+ free_argv (cproc->helper_argv);
+ GNUNET_free (cproc);
+}
/**
@@ -40,7 +1797,9 @@
* given host.
*
* @param cfg configuration to use
- * @param host host to run the controller on, NULL for 'localhost'
+ * @param host host to run the controller on; This should be the same host if
+ * the controller was previously started with
+ * GNUNET_TESTBED_controller_start; NULL for localhost
* @param event_mask bit mask with set of events to call 'cc' for;
* or-ed values of "1LL" shifted by the
* respective 'enum GNUNET_TESTBED_EventType'
@@ -50,14 +1809,101 @@
* @return handle to the controller
*/
struct GNUNET_TESTBED_Controller *
-GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_TESTBED_Host *host,
- uint64_t event_mask,
- GNUNET_TESTBED_ControllerCallback cc,
- void *cc_cls)
+GNUNET_TESTBED_controller_connect (const struct GNUNET_CONFIGURATION_Handle
+ *cfg, struct GNUNET_TESTBED_Host *host,
+ uint64_t event_mask,
+ GNUNET_TESTBED_ControllerCallback cc,
+ void *cc_cls)
{
- GNUNET_break (0);
- return NULL;
+ struct GNUNET_TESTBED_Controller *controller;
+ struct GNUNET_TESTBED_InitMessage *msg;
+ const char *controller_hostname;
+ unsigned long long max_parallel_operations;
+ unsigned long long max_parallel_service_connections;
+ unsigned long long max_parallel_topology_config_operations;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
+ "MAX_PARALLEL_OPERATIONS",
+ &max_parallel_operations))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
+ "MAX_PARALLEL_SERVICE_CONNECTIONS",
+ &max_parallel_service_connections))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, "testbed",
+ "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
+ &max_parallel_topology_config_operations))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ controller = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Controller));
+ controller->cc = cc;
+ controller->cc_cls = cc_cls;
+ controller->event_mask = event_mask;
+ controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ controller->client = GNUNET_CLIENT_connect ("testbed", controller->cfg);
+ if (NULL == controller->client)
+ {
+ GNUNET_TESTBED_controller_disconnect (controller);
+ return NULL;
+ }
+ if (NULL == host)
+ {
+ host = GNUNET_TESTBED_host_create_by_id_ (0);
+ if (NULL == host) /* If the above host create fails */
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Treating NULL host as localhost. Multiple references to localhost "
+ "may break when localhost freed before calling disconnect \n");
+ host = GNUNET_TESTBED_host_lookup_by_id_ (0);
+ }
+ else
+ {
+ controller->aux_host = GNUNET_YES;
+ }
+ }
+ GNUNET_assert (NULL != host);
+ GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
+ controller->host = host;
+ controller->opq_parallel_operations =
+ GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
+ max_parallel_operations);
+ controller->opq_parallel_service_connections =
+ GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
+ max_parallel_service_connections);
+ controller->opq_parallel_topology_config_operations =
+ GNUNET_TESTBED_operation_queue_create_ ((unsigned int)
+ max_parallel_topology_config_operations);
+ controller->opq_parallel_overlay_connect_operations =
+ GNUNET_TESTBED_operation_queue_create_ (0);
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (controller, 1);
+ controller->poc_sd = SD_init (10);
+ controller_hostname = GNUNET_TESTBED_host_get_hostname (host);
+ if (NULL == controller_hostname)
+ controller_hostname = "127.0.0.1";
+ msg =
+ GNUNET_malloc (sizeof (struct GNUNET_TESTBED_InitMessage) +
+ strlen (controller_hostname) + 1);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_INIT);
+ msg->header.size =
+ htons (sizeof (struct GNUNET_TESTBED_InitMessage) +
+ strlen (controller_hostname) + 1);
+ msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
+ msg->event_mask = GNUNET_htonll (controller->event_mask);
+ strcpy ((char *) &msg[1], controller_hostname);
+ GNUNET_TESTBED_queue_message_ (controller,
+ (struct GNUNET_MessageHeader *) msg);
+ return controller;
}
@@ -67,7 +1913,7 @@ GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
* should not be run for each peer but instead be shared
* across N peers on the specified host. This function
* must be called before any peers are created at the host.
- *
+ *
* @param controller controller to configure
* @param service_name name of the service to share
* @param num_peers number of peers that should share one instance
@@ -75,58 +1921,462 @@ GNUNET_TESTBED_controller_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
* use 0 to disable the service
*/
void
-GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller *controller,
- const char *service_name,
- uint32_t num_peers)
+GNUNET_TESTBED_controller_configure_sharing (struct GNUNET_TESTBED_Controller
+ *controller,
+ const char *service_name,
+ uint32_t num_peers)
{
- GNUNET_break (0);
+ struct GNUNET_TESTBED_ConfigureSharedServiceMessage *msg;
+ uint16_t service_name_size;
+ uint16_t msg_size;
+
+ service_name_size = strlen (service_name) + 1;
+ msg_size =
+ sizeof (struct GNUNET_TESTBED_ConfigureSharedServiceMessage) +
+ service_name_size;
+ msg = GNUNET_malloc (msg_size);
+ msg->header.size = htons (msg_size);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE);
+ msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (controller->host));
+ msg->num_peers = htonl (num_peers);
+ memcpy (&msg[1], service_name, service_name_size);
+ GNUNET_TESTBED_queue_message_ (controller,
+ (struct GNUNET_MessageHeader *) msg);
+ GNUNET_break (0); /* This function is not yet implemented on the
+ * testbed service */
}
/**
- * Stop the given controller (also will terminate all peers and
- * controllers dependent on this controller). This function
- * blocks until the testbed has been fully terminated (!).
+ * disconnects from the controller.
*
* @param controller handle to controller to stop
*/
void
-GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_Controller *controller)
+GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller
+ *controller)
{
- GNUNET_break (0);
+ struct MessageQueue *mq_entry;
+
+ if (NULL != controller->th)
+ GNUNET_CLIENT_notify_transmit_ready_cancel (controller->th);
+ /* Clear the message queue */
+ while (NULL != (mq_entry = controller->mq_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (controller->mq_head, controller->mq_tail,
+ mq_entry);
+ GNUNET_free (mq_entry->msg);
+ GNUNET_free (mq_entry);
+ }
+ if (NULL != controller->client)
+ GNUNET_CLIENT_disconnect (controller->client);
+ GNUNET_CONFIGURATION_destroy (controller->cfg);
+ if (GNUNET_YES == controller->aux_host)
+ GNUNET_TESTBED_host_destroy (controller->host);
+ GNUNET_TESTBED_operation_queue_destroy_ (controller->opq_parallel_operations);
+ GNUNET_TESTBED_operation_queue_destroy_
+ (controller->opq_parallel_service_connections);
+ GNUNET_TESTBED_operation_queue_destroy_
+ (controller->opq_parallel_topology_config_operations);
+ GNUNET_TESTBED_operation_queue_destroy_
+ (controller->opq_parallel_overlay_connect_operations);
+ SD_destroy (controller->poc_sd);
+ GNUNET_free_non_null (controller->tslots);
+ GNUNET_free (controller);
+}
+
+
+/**
+ * Register a host with the controller
+ *
+ * @param controller the controller handle
+ * @param host the host to register
+ * @param cc the completion callback to call to inform the status of
+ * registration. After calling this callback the registration handle
+ * will be invalid. Cannot be NULL.
+ * @param cc_cls the closure for the cc
+ * @return handle to the host registration which can be used to cancel the
+ * registration
+ */
+struct GNUNET_TESTBED_HostRegistrationHandle *
+GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
+ struct GNUNET_TESTBED_Host *host,
+ GNUNET_TESTBED_HostRegistrationCompletion cc,
+ void *cc_cls)
+{
+ struct GNUNET_TESTBED_HostRegistrationHandle *rh;
+ struct GNUNET_TESTBED_AddHostMessage *msg;
+ const char *username;
+ const char *hostname;
+ uint16_t msg_size;
+ uint16_t user_name_length;
+
+ if (NULL != controller->rh)
+ return NULL;
+ hostname = GNUNET_TESTBED_host_get_hostname (host);
+ if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Host hostname: %s already registered\n",
+ (NULL == hostname) ? "localhost" : hostname);
+ return NULL;
+ }
+ rh = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostRegistrationHandle));
+ rh->host = host;
+ rh->c = controller;
+ GNUNET_assert (NULL != cc);
+ rh->cc = cc;
+ rh->cc_cls = cc_cls;
+ controller->rh = rh;
+ username = GNUNET_TESTBED_host_get_username_ (host);
+ msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
+ user_name_length = 0;
+ if (NULL != username)
+ {
+ user_name_length = strlen (username) + 1;
+ msg_size += user_name_length;
+ }
+ /* FIXME: what happens when hostname is NULL? localhost */
+ GNUNET_assert (NULL != hostname);
+ msg_size += strlen (hostname) + 1;
+ msg = GNUNET_malloc (msg_size);
+ msg->header.size = htons (msg_size);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST);
+ msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
+ msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
+ if (NULL != username)
+ {
+ msg->user_name_length = htons (user_name_length - 1);
+ memcpy (&msg[1], username, user_name_length);
+ }
+ else
+ msg->user_name_length = htons (user_name_length);
+ strcpy (((void *) &msg[1]) + user_name_length, hostname);
+ GNUNET_TESTBED_queue_message_ (controller,
+ (struct GNUNET_MessageHeader *) msg);
+ return rh;
+}
+
+
+/**
+ * Cancel the pending registration. Note that if the registration message is
+ * already sent to the service the cancellation has only the effect that the
+ * registration completion callback for the registration is never called.
+ *
+ * @param handle the registration handle to cancel
+ */
+void
+GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
+ *handle)
+{
+ if (handle != handle->c->rh)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ handle->c->rh = NULL;
+ GNUNET_free (handle);
+}
+
+
+/**
+ * Same as the GNUNET_TESTBED_controller_link_2, but with ids for delegated host
+ * and slave host
+ *
+ * @param op_cls the operation closure for the event which is generated to
+ * signal success or failure of this operation
+ * @param master handle to the master controller who creates the association
+ * @param delegated_host_id id of the host to which requests should be delegated
+ * @param slave_host_id id of the host which is used to run the slave controller
+ * @param sxcfg serialized and compressed configuration
+ * @param sxcfg_size the size sxcfg
+ * @param scfg_size the size of uncompressed serialized configuration
+ * @param is_subordinate GNUNET_YES if the controller at delegated_host should
+ * be started by the slave controller; GNUNET_NO if the slave
+ * controller has to connect to the already started delegated
+ * controller via TCP/IP
+ * @return the operation handle
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_controller_link_2_ (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ uint32_t delegated_host_id,
+ uint32_t slave_host_id, const char *sxcfg,
+ size_t sxcfg_size, size_t scfg_size,
+ int is_subordinate)
+{
+ struct OperationContext *opc;
+ struct GNUNET_TESTBED_ControllerLinkMessage *msg;
+ struct ControllerLinkData *data;
+ uint16_t msg_size;
+
+ msg_size = sxcfg_size + sizeof (struct GNUNET_TESTBED_ControllerLinkMessage);
+ msg = GNUNET_malloc (msg_size);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS);
+ msg->header.size = htons (msg_size);
+ msg->delegated_host_id = htonl (delegated_host_id);
+ msg->slave_host_id = htonl (slave_host_id);
+ msg->config_size = htons ((uint16_t) scfg_size);
+ msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
+ memcpy (&msg[1], sxcfg, sxcfg_size);
+ data = GNUNET_malloc (sizeof (struct ControllerLinkData));
+ data->msg = msg;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->c = master;
+ opc->data = data;
+ opc->type = OP_LINK_CONTROLLERS;
+ opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
+ opc->state = OPC_STATE_INIT;
+ opc->op_cls = op_cls;
+ msg->operation_id = GNUNET_htonll (opc->id);
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_link_controllers,
+ &oprelease_link_controllers);
+ GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
}
/**
- * Create a link from a 'master' controller to a slave controller.
- * Whenever the master controller is asked to start a peer at the
- * given 'delegated_host', it will delegate the request to the
- * specified slave controller. Note that the slave controller runs at
- * the 'slave_host', which may or may not be the same host as the
- * 'delegated_host' (for hierarchical delegations). The configuration
- * of the slave controller is given and to be used to either create
- * the slave controller or to connect to an existing slave controller
- * process. 'is_subordinate' specifies if the given slave controller
- * should be started and managed by the master controller, or if the
- * slave already has a master and this is just a secondary master that
- * is also allowed to use the existing slave.
+ * Same as the GNUNET_TESTBED_controller_link, however expects configuration in
+ * serialized and compressed
*
+ * @param op_cls the operation closure for the event which is generated to
+ * signal success or failure of this operation
* @param master handle to the master controller who creates the association
- * @param delegated_host requests to which host should be delegated
- * @param slave_host which host is used to run the slave controller
+ * @param delegated_host requests to which host should be delegated; cannot be NULL
+ * @param slave_host which host is used to run the slave controller; use NULL to
+ * make the master controller connect to the delegated host
+ * @param sxcfg serialized and compressed configuration
+ * @param sxcfg_size the size sxcfg
+ * @param scfg_size the size of uncompressed serialized configuration
+ * @param is_subordinate GNUNET_YES if the controller at delegated_host should
+ * be started by the slave controller; GNUNET_NO if the slave
+ * controller has to connect to the already started delegated
+ * controller via TCP/IP
+ * @return the operation handle
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_controller_link_2 (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ struct GNUNET_TESTBED_Host *delegated_host,
+ struct GNUNET_TESTBED_Host *slave_host,
+ const char *sxcfg, size_t sxcfg_size,
+ size_t scfg_size, int is_subordinate)
+{
+ uint32_t delegated_host_id;
+ uint32_t slave_host_id;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
+ delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
+ slave_host_id =
+ GNUNET_TESTBED_host_get_id_ ((NULL !=
+ slave_host) ? slave_host : master->host);
+ if ((NULL != slave_host) && (0 != GNUNET_TESTBED_host_get_id_ (slave_host)))
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_TESTBED_is_host_registered_ (slave_host, master));
+
+ return GNUNET_TESTBED_controller_link_2_ (op_cls, master, delegated_host_id,
+ slave_host_id, sxcfg, sxcfg_size,
+ scfg_size, is_subordinate);
+}
+
+
+/**
+ * Compresses given configuration using zlib compress
+ *
+ * @param config the serialized configuration
+ * @param size the size of config
+ * @param xconfig will be set to the compressed configuration (memory is fresly
+ * allocated)
+ * @return the size of the xconfig
+ */
+size_t
+GNUNET_TESTBED_compress_config_ (const char *config, size_t size,
+ char **xconfig)
+{
+ size_t xsize;
+
+ xsize = compressBound ((uLong) size);
+ *xconfig = GNUNET_malloc (xsize);
+ GNUNET_assert (Z_OK ==
+ compress2 ((Bytef *) * xconfig, (uLongf *) & xsize,
+ (const Bytef *) config, (uLongf) size,
+ Z_BEST_SPEED));
+ return xsize;
+}
+
+
+/**
+ * Same as the GNUNET_TESTBED_controller_link, but with ids for delegated host
+ * and slave host
+ *
+ * @param op_cls the operation closure for the event which is generated to
+ * signal success or failure of this operation
+ * @param master handle to the master controller who creates the association
+ * @param delegated_host_id id of the host to which requests should be
+ * delegated; cannot be NULL
+ * @param slave_host_id id of the host which should connect to controller
+ * running on delegated host ; use NULL to make the master controller
+ * connect to the delegated host
* @param slave_cfg configuration to use for the slave controller
- * @param is_subordinate GNUNET_YES if the slave should be started (and stopped)
- * by the master controller; GNUNET_NO if we are just
- * allowed to use the slave via TCP/IP
+ * @param is_subordinate GNUNET_YES if the controller at delegated_host should
+ * be started by the slave controller; GNUNET_NO if the slave
+ * controller has to connect to the already started delegated
+ * controller via TCP/IP
+ * @return the operation handle
*/
-void
-GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
- struct GNUNET_TESTBED_Host *delegated_host,
- struct GNUNET_TESTBED_Host *slave_host,
- const struct GNUNET_CONFIGURATION_Handle *slave_cfg,
- int is_subordinate)
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_controller_link_ (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ uint32_t delegated_host_id,
+ uint32_t slave_host_id,
+ const struct GNUNET_CONFIGURATION_Handle
+ *slave_cfg, int is_subordinate)
{
- GNUNET_break (0);
+ struct GNUNET_TESTBED_Operation *op;
+ char *config;
+ char *cconfig;
+ size_t cc_size;
+ size_t config_size;
+
+ config = GNUNET_CONFIGURATION_serialize (slave_cfg, &config_size);
+ cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
+ GNUNET_free (config);
+ /* Configuration doesn't fit in 1 message */
+ GNUNET_assert ((UINT16_MAX -
+ sizeof (struct GNUNET_TESTBED_ControllerLinkMessage)) >=
+ cc_size);
+ op = GNUNET_TESTBED_controller_link_2_ (op_cls, master, delegated_host_id,
+ slave_host_id, (const char *) cconfig,
+ cc_size, config_size, is_subordinate);
+ GNUNET_free (cconfig);
+ return op;
+}
+
+
+/**
+ * Create a link from slave controller to delegated controller. Whenever the
+ * master controller is asked to start a peer at the delegated controller the
+ * request will be routed towards slave controller (if a route exists). The
+ * slave controller will then route it to the delegated controller. The
+ * configuration of the delegated controller is given and is used to either
+ * create the delegated controller or to connect to an existing controller. Note
+ * that while starting the delegated controller the configuration will be
+ * modified to accommodate available free ports. the 'is_subordinate' specifies
+ * if the given delegated controller should be started and managed by the slave
+ * controller, or if the delegated controller already has a master and the slave
+ * controller connects to it as a non master controller. The success or failure
+ * of this operation will be signalled through the
+ * GNUNET_TESTBED_ControllerCallback() with an event of type
+ * GNUNET_TESTBED_ET_OPERATION_FINISHED
+ *
+ * @param op_cls the operation closure for the event which is generated to
+ * signal success or failure of this operation
+ * @param master handle to the master controller who creates the association
+ * @param delegated_host requests to which host should be delegated; cannot be NULL
+ * @param slave_host which host is used to run the slave controller; use NULL to
+ * make the master controller connect to the delegated host
+ * @param slave_cfg configuration to use for the slave controller
+ * @param is_subordinate GNUNET_YES if the controller at delegated_host should
+ * be started by the slave controller; GNUNET_NO if the slave
+ * controller has to connect to the already started delegated
+ * controller via TCP/IP
+ * @return the operation handle
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_controller_link (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ struct GNUNET_TESTBED_Host *delegated_host,
+ struct GNUNET_TESTBED_Host *slave_host,
+ const struct GNUNET_CONFIGURATION_Handle
+ *slave_cfg, int is_subordinate)
+{
+ uint32_t slave_host_id;
+ uint32_t delegated_host_id;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
+ slave_host_id =
+ GNUNET_TESTBED_host_get_id_ ((NULL !=
+ slave_host) ? slave_host : master->host);
+ delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
+ if ((NULL != slave_host) && (0 != slave_host_id))
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_TESTBED_is_host_registered_ (slave_host, master));
+ return GNUNET_TESTBED_controller_link_ (op_cls, master, delegated_host_id,
+ slave_host_id, slave_cfg,
+ is_subordinate);
+
+}
+
+
+/**
+ * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
+ * check. Another difference is that this function takes the id of the slave
+ * host.
+ *
+ * @param op_cls the closure for the operation
+ * @param master the handle to master controller
+ * @param slave_host_id id of the host where the slave controller is running to
+ * the slave_host should remain valid until this operation is cancelled
+ * or marked as finished
+ * @return the operation handle;
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_get_slave_config_ (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ uint32_t slave_host_id)
+{
+ struct OperationContext *opc;
+ struct GetSlaveConfigData *data;
+
+ data = GNUNET_malloc (sizeof (struct GetSlaveConfigData));
+ data->slave_id = slave_host_id;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->state = OPC_STATE_INIT;
+ opc->c = master;
+ opc->id = GNUNET_TESTBED_get_next_op_id (master);
+ opc->type = OP_GET_SLAVE_CONFIG;
+ opc->data = data;
+ opc->op_cls = op_cls;
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_get_slave_config,
+ &oprelease_get_slave_config);
+ GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
+}
+
+
+/**
+ * Function to acquire the configuration of a running slave controller. The
+ * completion of the operation is signalled through the controller_cb from
+ * GNUNET_TESTBED_controller_connect(). If the operation is successful the
+ * handle to the configuration is available in the generic pointer of
+ * operation_finished field of struct GNUNET_TESTBED_EventInformation.
+ *
+ * @param op_cls the closure for the operation
+ * @param master the handle to master controller
+ * @param slave_host the host where the slave controller is running; the handle
+ * to the slave_host should remain valid until this operation is
+ * cancelled or marked as finished
+ * @return the operation handle; NULL if the slave_host is not registered at
+ * master
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_get_slave_config (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ struct GNUNET_TESTBED_Host *slave_host)
+{
+ if (GNUNET_NO == GNUNET_TESTBED_is_host_registered_ (slave_host, master))
+ return NULL;
+ return GNUNET_TESTBED_get_slave_config_ (op_cls, master,
+ GNUNET_TESTBED_host_get_id_
+ (slave_host));
}
@@ -140,11 +2390,375 @@ GNUNET_TESTBED_controller_link (struct GNUNET_TESTBED_Controller *master,
* be written to.
*/
void
-GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller *controller,
- const char *filename)
+GNUNET_TESTBED_overlay_write_topology_to_file (struct GNUNET_TESTBED_Controller
+ *controller,
+ const char *filename)
{
+ GNUNET_break (0);
}
+/**
+ * Creates a helper initialization message. This function is here because we
+ * want to use this in testing
+ *
+ * @param trusted_ip the ip address of the controller which will be set as TRUSTED
+ * HOST(all connections form this ip are permitted by the testbed) when
+ * starting testbed controller at host. This can either be a single ip
+ * address or a network address in CIDR notation.
+ * @param hostname the hostname of the destination this message is intended for
+ * @param cfg the configuration that has to used to start the testbed service
+ * thru helper
+ * @return the initialization message
+ */
+struct GNUNET_TESTBED_HelperInit *
+GNUNET_TESTBED_create_helper_init_msg_ (const char *trusted_ip,
+ const char *hostname,
+ const struct GNUNET_CONFIGURATION_Handle
+ *cfg)
+{
+ struct GNUNET_TESTBED_HelperInit *msg;
+ char *config;
+ char *xconfig;
+ size_t config_size;
+ size_t xconfig_size;
+ uint16_t trusted_ip_len;
+ uint16_t hostname_len;
+ uint16_t msg_size;
+
+ config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
+ GNUNET_assert (NULL != config);
+ xconfig_size =
+ GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
+ GNUNET_free (config);
+ trusted_ip_len = strlen (trusted_ip);
+ hostname_len = (NULL == hostname) ? 0 : strlen (hostname);
+ msg_size =
+ xconfig_size + trusted_ip_len + 1 +
+ sizeof (struct GNUNET_TESTBED_HelperInit);
+ msg_size += hostname_len;
+ msg = GNUNET_realloc (xconfig, msg_size);
+ (void) memmove (((void *) &msg[1]) + trusted_ip_len + 1 + hostname_len, msg,
+ xconfig_size);
+ msg->header.size = htons (msg_size);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
+ msg->trusted_ip_size = htons (trusted_ip_len);
+ msg->hostname_size = htons (hostname_len);
+ msg->config_size = htons (config_size);
+ (void) strcpy ((char *) &msg[1], trusted_ip);
+ if (0 != hostname_len)
+ (void) strncpy (((char *) &msg[1]) + trusted_ip_len + 1, hostname,
+ hostname_len);
+ return msg;
+}
+
+
+/**
+ * Cancel a pending operation. Releases all resources
+ * of the operation and will ensure that no event
+ * is generated for the operation. Does NOT guarantee
+ * that the operation will be fully undone (or that
+ * nothing ever happened).
+ *
+ * @param operation operation to cancel
+ */
+void
+GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation)
+{
+ GNUNET_TESTBED_operation_done (operation);
+}
+
+
+/**
+ * Signal that the information from an operation has been fully
+ * processed. This function MUST be called for each event
+ * of type 'operation_finished' to fully remove the operation
+ * from the operation queue. After calling this function, the
+ * 'op_result' becomes invalid (!).
+ *
+ * @param operation operation to signal completion for
+ */
+void
+GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
+{
+ last_finished_operation = operation;
+ GNUNET_TESTBED_operation_release_ (operation);
+}
+
+
+/**
+ * Generates configuration by uncompressing configuration in given message. The
+ * given message should be of the following types:
+ * GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG,
+ * GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG
+ *
+ * @param msg the message containing compressed configuration
+ * @return handle to the parsed configuration
+ */
+struct GNUNET_CONFIGURATION_Handle *
+GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ Bytef *data;
+ const Bytef *xdata;
+ uLong data_len;
+ uLong xdata_len;
+ int ret;
+
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION:
+ {
+ const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *imsg;
+
+ imsg =
+ (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
+ data_len = (uLong) ntohs (imsg->config_size);
+ xdata_len =
+ ntohs (imsg->header.size) -
+ sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
+ xdata = (const Bytef *) &imsg[1];
+ }
+ break;
+ case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION:
+ {
+ const struct GNUNET_TESTBED_SlaveConfiguration *imsg;
+
+ imsg = (const struct GNUNET_TESTBED_SlaveConfiguration *) msg;
+ data_len = (uLong) ntohs (imsg->config_size);
+ xdata_len =
+ ntohs (imsg->header.size) -
+ sizeof (struct GNUNET_TESTBED_SlaveConfiguration);
+ xdata = (const Bytef *) &imsg[1];
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ data = GNUNET_malloc (data_len);
+ if (Z_OK != (ret = uncompress (data, &data_len, xdata, xdata_len)))
+ GNUNET_assert (0);
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_deserialize (cfg, (const char *) data,
+ (size_t) data_len,
+ GNUNET_NO));
+ GNUNET_free (data);
+ return cfg;
+}
+
+
+/**
+ * Checks the integrity of the OperationFailureEventMessage and if good returns
+ * the error message it contains.
+ *
+ * @param msg the OperationFailureEventMessage
+ * @return the error message
+ */
+const char *
+GNUNET_TESTBED_parse_error_string_ (const struct
+ GNUNET_TESTBED_OperationFailureEventMessage
+ *msg)
+{
+ uint16_t msize;
+ const char *emsg;
+
+ msize = ntohs (msg->header.size);
+ if (sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
+ return NULL;
+ msize -= sizeof (struct GNUNET_TESTBED_OperationFailureEventMessage);
+ emsg = (const char *) &msg[1];
+ if ('\0' != emsg[msize - 1])
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ return emsg;
+}
+
+
+/**
+ * Function to return the operation id for a controller. The operation id is
+ * created from the controllers host id and its internal operation counter.
+ *
+ * @param controller the handle to the controller whose operation id has to be incremented
+ * @return the incremented operation id.
+ */
+uint64_t
+GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller * controller)
+{
+ uint64_t op_id;
+
+ op_id = (uint64_t) GNUNET_TESTBED_host_get_id_ (controller->host);
+ op_id = op_id << 32;
+ op_id |= (uint64_t) controller->operation_counter++;
+ return op_id;
+}
+
+
+/**
+ * Returns a timing slot which will be exclusively locked
+ *
+ * @param c the controller handle
+ * @param key a pointer which is associated to the returned slot; should not be
+ * NULL. It serves as a key to determine the correct owner of the slot
+ * @return the time slot index in the array of time slots in the controller
+ * handle
+ */
+unsigned int
+GNUNET_TESTBED_get_tslot_ (struct GNUNET_TESTBED_Controller *c, void *key)
+{
+ unsigned int slot;
+
+ GNUNET_assert (NULL != c->tslots);
+ GNUNET_assert (NULL != key);
+ for (slot = 0; slot < c->num_parallel_connects; slot++)
+ if (NULL == c->tslots[slot].key)
+ {
+ c->tslots[slot].key = key;
+ return slot;
+ }
+ GNUNET_assert (0); /* We should always find a free tslot */
+}
+
+
+/**
+ * Decides whether any change in the number of parallel overlay connects is
+ * necessary to adapt to the load on the system
+ *
+ * @param c the controller handle
+ */
+static void
+decide_npoc (struct GNUNET_TESTBED_Controller *c)
+{
+ struct GNUNET_TIME_Relative avg;
+ int sd;
+ unsigned int slot;
+ unsigned int nvals;
+
+ if (c->tslots_filled != c->num_parallel_connects)
+ return;
+ avg = GNUNET_TIME_UNIT_ZERO;
+ nvals = 0;
+ for (slot = 0; slot < c->num_parallel_connects; slot++)
+ {
+ avg = GNUNET_TIME_relative_add (avg, c->tslots[slot].time);
+ nvals += c->tslots[slot].nvals;
+ }
+ GNUNET_assert (nvals >= c->num_parallel_connects);
+ avg = GNUNET_TIME_relative_divide (avg, nvals);
+ GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != avg.rel_value);
+ sd = SD_deviation_factor (c->poc_sd, (unsigned int) avg.rel_value);
+ if ( (sd <= 5) ||
+ (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ c->num_parallel_connects)) )
+ SD_add_data (c->poc_sd, (unsigned int) avg.rel_value);
+ if (GNUNET_SYSERR == sd)
+ {
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c,
+ c->num_parallel_connects);
+ return;
+ }
+ GNUNET_assert (0 <= sd);
+ if (0 == sd)
+ {
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c,
+ c->num_parallel_connects
+ * 2);
+ return;
+ }
+ if (1 == sd)
+ {
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c,
+ c->num_parallel_connects
+ + 1);
+ return;
+ }
+ if (1 == c->num_parallel_connects)
+ {
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c, 1);
+ return;
+ }
+ if (2 == sd)
+ {
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c,
+ c->num_parallel_connects
+ - 1);
+ return;
+ }
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c,
+ c->num_parallel_connects /
+ 2);
+}
+
+
+/**
+ * Releases a time slot thus making it available for be used again
+ *
+ * @param c the controller handle
+ * @param index the index of the the time slot
+ * @param key the key to prove ownership of the timeslot
+ * @return GNUNET_YES if the time slot is successfully removed; GNUNET_NO if the
+ * time slot cannot be removed - this could be because of the index
+ * greater than existing number of time slots or `key' being different
+ */
+int
+GNUNET_TESTBED_release_time_slot_ (struct GNUNET_TESTBED_Controller *c,
+ unsigned int index, void *key)
+{
+ struct TimeSlot *slot;
+
+ GNUNET_assert (NULL != key);
+ if (index >= c->num_parallel_connects)
+ return GNUNET_NO;
+ slot = &c->tslots[index];
+ if (key != slot->key)
+ return GNUNET_NO;
+ slot->key = NULL;
+ return GNUNET_YES;
+}
+
+
+/**
+ * Function to update a time slot
+ *
+ * @param c the controller handle
+ * @param index the index of the time slot to update
+ * @param key the key to identify ownership of the slot
+ * @param time the new time
+ * @param failed should this reading be treated as coming from a fail event
+ */
+void
+GNUNET_TESTBED_update_time_slot_ (struct GNUNET_TESTBED_Controller *c,
+ unsigned int index, void *key,
+ struct GNUNET_TIME_Relative time, int failed)
+{
+ struct TimeSlot *slot;
+
+ if (GNUNET_YES == failed)
+ {
+ if (1 == c->num_parallel_connects)
+ {
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c, 1);
+ return;
+ }
+ GNUNET_TESTBED_set_num_parallel_overlay_connects_ (c,
+ c->num_parallel_connects
+ - 1);
+ }
+ if (GNUNET_NO == GNUNET_TESTBED_release_time_slot_ (c, index, key))
+ return;
+ slot = &c->tslots[index];
+ slot->nvals++;
+ if (GNUNET_TIME_UNIT_ZERO.rel_value == slot->time.rel_value)
+ {
+ slot->time = time;
+ c->tslots_filled++;
+ decide_npoc (c);
+ return;
+ }
+ slot->time = GNUNET_TIME_relative_add (slot->time, time);
+}
+
/* end of testbed_api.c */
diff --git a/src/testbed/testbed_api.h b/src/testbed/testbed_api.h
new file mode 100644
index 0000000..d6c04a6
--- /dev/null
+++ b/src/testbed/testbed_api.h
@@ -0,0 +1,590 @@
+/*
+ This file is part of GNUnet
+ (C) 2012 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 3, 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 testbed/testbed_api.h
+ * @brief Interface for functions internally exported from testbed_api.c
+ * @author Sree Harsha Totakura
+ */
+
+#ifndef TESTBED_API_H
+#define TESTBED_API_H
+
+#include "gnunet_testbed_service.h"
+#include "testbed.h"
+
+
+/**
+ * Testbed Helper binary name
+ */
+#define HELPER_TESTBED_BINARY "gnunet-helper-testbed"
+
+
+/**
+ * Enumeration of operations
+ */
+enum OperationType
+{
+ /**
+ * Peer create operation
+ */
+ OP_PEER_CREATE,
+
+ /**
+ * Peer start operation
+ */
+ OP_PEER_START,
+
+ /**
+ * Peer stop operation
+ */
+ OP_PEER_STOP,
+
+ /**
+ * Peer destroy operation
+ */
+ OP_PEER_DESTROY,
+
+ /**
+ * Get peer information operation
+ */
+ OP_PEER_INFO,
+
+ /**
+ * Overlay connection operation
+ */
+ OP_OVERLAY_CONNECT,
+
+ /**
+ * Forwarded operation
+ */
+ OP_FORWARDED,
+
+ /**
+ * Link controllers operation
+ */
+ OP_LINK_CONTROLLERS,
+
+ /**
+ * Get slave config operation
+ */
+ OP_GET_SLAVE_CONFIG
+};
+
+
+/**
+ * The message queue for sending messages to the controller service
+ */
+struct MessageQueue;
+
+/**
+ * Structure for a controller link
+ */
+struct ControllerLink;
+
+
+/**
+ * Enumeration of states of OperationContext
+ */
+enum OperationContextState
+{
+ /**
+ * The initial state where the associated operation has just been created
+ * and is waiting in the operation queues to be started
+ */
+ OPC_STATE_INIT = 0,
+
+ /**
+ * The operation has been started. It may occupy some resources which are to
+ * be freed if cancelled.
+ */
+ OPC_STATE_STARTED,
+
+ /**
+ * The operation has finished. The end results of this operation may occupy
+ * some resources which are to be freed by operation_done
+ */
+ OPC_STATE_FINISHED
+};
+
+
+/**
+ * Context information for GNUNET_TESTBED_Operation
+ */
+struct OperationContext
+{
+ /**
+ * next ptr for DLL
+ */
+ struct OperationContext *next;
+
+ /**
+ * prev ptr for DLL
+ */
+ struct OperationContext *prev;
+
+ /**
+ * The controller to which this operation context belongs to
+ */
+ struct GNUNET_TESTBED_Controller *c;
+
+ /**
+ * The operation
+ */
+ struct GNUNET_TESTBED_Operation *op;
+
+ /**
+ * The operation closure
+ */
+ void *op_cls;
+
+ /**
+ * Data relevant to the operation
+ */
+ void *data;
+
+ /**
+ * The id of the opearation
+ */
+ uint64_t id;
+
+ /**
+ * The type of operation
+ */
+ enum OperationType type;
+
+ /**
+ * The state of the operation
+ */
+ enum OperationContextState state;
+};
+
+
+/**
+ * Opaque handle for SD calculations
+ */
+struct SDHandle;
+
+
+/**
+ * A slot to record time taken by an overlay connect operation
+ */
+struct TimeSlot
+{
+ /**
+ * A key to identify this timeslot
+ */
+ void *key;
+
+ /**
+ * Time
+ */
+ struct GNUNET_TIME_Relative time;
+
+ /**
+ * Number of timing values accumulated
+ */
+ unsigned int nvals;
+};
+
+
+/**
+ * Handle to interact with a GNUnet testbed controller. Each
+ * controller has at least one master handle which is created when the
+ * controller is created; this master handle interacts with the
+ * controller process, destroying it destroys the controller (by
+ * closing stdin of the controller process). Additionally,
+ * controllers can interact with each other (in a P2P fashion); those
+ * links are established via TCP/IP on the controller's service port.
+ */
+struct GNUNET_TESTBED_Controller
+{
+ /**
+ * The host where the controller is running
+ */
+ struct GNUNET_TESTBED_Host *host;
+
+ /**
+ * The controller callback
+ */
+ GNUNET_TESTBED_ControllerCallback cc;
+
+ /**
+ * The closure for controller callback
+ */
+ void *cc_cls;
+
+ /**
+ * The configuration to use while connecting to controller
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * The client connection handle to the controller service
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * The head of the message queue
+ */
+ struct MessageQueue *mq_head;
+
+ /**
+ * The tail of the message queue
+ */
+ struct MessageQueue *mq_tail;
+
+ /**
+ * The head of the ControllerLink list
+ */
+ struct ControllerLink *cl_head;
+
+ /**
+ * The tail of the ControllerLink list
+ */
+ struct ControllerLink *cl_tail;
+
+ /**
+ * The client transmit handle
+ */
+ struct GNUNET_CLIENT_TransmitHandle *th;
+
+ /**
+ * The host registration handle; NULL if no current registration requests are
+ * present
+ */
+ struct GNUNET_TESTBED_HostRegistrationHandle *rh;
+
+ /**
+ * The head of the opeartion context queue
+ */
+ struct OperationContext *ocq_head;
+
+ /**
+ * The tail of the operation context queue
+ */
+ struct OperationContext *ocq_tail;
+
+ /**
+ * Operation queue for simultaneous operations
+ */
+ struct OperationQueue *opq_parallel_operations;
+
+ /**
+ * Operation queue for simultaneous service connections
+ */
+ struct OperationQueue *opq_parallel_service_connections;
+
+ /**
+ * Operation queue for simultaneous topology configuration operations
+ */
+ struct OperationQueue *opq_parallel_topology_config_operations;
+
+ /**
+ * Operation queue for simultaneous overlay connect operations
+ */
+ struct OperationQueue *opq_parallel_overlay_connect_operations;
+
+ /**
+ * An array of timing slots; size should be equal to the current number of parallel
+ * overlay connects
+ */
+ struct TimeSlot *tslots;
+
+ /**
+ * Handle for SD calculations amount parallel overlay connect operation finish
+ * times
+ */
+ struct SDHandle *poc_sd;
+
+ /**
+ * The controller event mask
+ */
+ uint64_t event_mask;
+
+ /**
+ * Did we start the receive loop yet?
+ */
+ int in_receive;
+
+ /**
+ * Did we create the host for this?
+ */
+ int aux_host;
+
+ /**
+ * The number of parallel overlay connects we do currently
+ */
+ unsigned int num_parallel_connects;
+
+ /**
+ * Counter to indicate when all the available time slots are filled
+ */
+ unsigned int tslots_filled;
+
+ /**
+ * The operation id counter. use current value and increment
+ */
+ uint32_t operation_counter;
+
+};
+
+
+/**
+ * Queues a message in send queue for sending to the service
+ *
+ * @param controller the handle to the controller
+ * @param msg the message to queue
+ */
+void
+GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
+ struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * Compresses given configuration using zlib compress
+ *
+ * @param config the serialized configuration
+ * @param size the size of config
+ * @param xconfig will be set to the compressed configuration (memory is fresly
+ * allocated)
+ * @return the size of the xconfig
+ */
+size_t
+GNUNET_TESTBED_compress_config_ (const char *config, size_t size,
+ char **xconfig);
+
+
+/**
+ * Adds an operation to the queue of operations
+ *
+ * @param op the operation to add
+ */
+void
+GNUNET_TESTBED_operation_add_ (struct GNUNET_TESTBED_Operation *op);
+
+
+/**
+ * Creates a helper initialization message. This function is here because we
+ * want to use this in testing
+ *
+ * @param trusted_ip the ip address of the controller which will be set as TRUSTED
+ * HOST(all connections form this ip are permitted by the testbed) when
+ * starting testbed controller at host. This can either be a single ip
+ * address or a network address in CIDR notation.
+ * @param hostname the hostname of the destination this message is intended for
+ * @param cfg the configuration that has to used to start the testbed service
+ * thru helper
+ * @return the initialization message
+ */
+struct GNUNET_TESTBED_HelperInit *
+GNUNET_TESTBED_create_helper_init_msg_ (const char *cname, const char *hostname,
+ const struct GNUNET_CONFIGURATION_Handle
+ *cfg);
+
+
+/**
+ * Sends the given message as an operation. The given callback is called when a
+ * reply for the operation is available. Call
+ * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
+ * operation context if the cc hasn't been called
+ *
+ * @param controller the controller to which the message has to be sent
+ * @param operation_id the operation id of the message
+ * @param msg the message to send
+ * @param cc the callback to call when reply is available
+ * @param cc_cls the closure for the above callback
+ * @return the operation context which can be used to cancel the forwarded
+ * operation
+ */
+struct OperationContext *
+GNUNET_TESTBED_forward_operation_msg_ (struct GNUNET_TESTBED_Controller
+ *controller, uint64_t operation_id,
+ const struct GNUNET_MessageHeader *msg,
+ GNUNET_CLIENT_MessageHandler cc,
+ void *cc_cls);
+
+/**
+ * Function to cancel an operation created by simply forwarding an operation
+ * message.
+ *
+ * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
+ */
+void
+GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc);
+
+
+/**
+ * Generates configuration by uncompressing configuration in given message. The
+ * given message should be of the following types:
+ * GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG,
+ * GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG
+ *
+ * @param msg the message containing compressed configuration
+ * @return handle to the parsed configuration
+ */
+struct GNUNET_CONFIGURATION_Handle *
+GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * Checks the integrity of the OpeationFailureEventMessage and if good returns
+ * the error message it contains.
+ *
+ * @param msg the OperationFailureEventMessage
+ * @return the error message
+ */
+const char *
+GNUNET_TESTBED_parse_error_string_ (const struct
+ GNUNET_TESTBED_OperationFailureEventMessage
+ *msg);
+
+
+/**
+ * Function to return the operation id for a controller. The operation id is
+ * created from the controllers host id and its internal operation counter.
+ *
+ * @param controller the handle to the controller whose operation id has to be incremented
+ * @return the incremented operation id.
+ */
+uint64_t
+GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller *controller);
+
+
+/**
+ * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
+ * check. Another difference is that this function takes the id of the slave
+ * host.
+ *
+ * @param op_cls the closure for the operation
+ * @param master the handle to master controller
+ * @param slave_host_id id of the host where the slave controller is running to
+ * the slave_host should remain valid until this operation is cancelled
+ * or marked as finished
+ * @return the operation handle;
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_get_slave_config_ (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ uint32_t slave_host_id);
+
+
+/**
+ * Same as the GNUNET_TESTBED_controller_link_2, but with ids for delegated host
+ * and slave host
+ *
+ * @param op_cls the operation closure for the event which is generated to
+ * signal success or failure of this operation
+ * @param master handle to the master controller who creates the association
+ * @param delegated_host_id id of the host to which requests should be delegated
+ * @param slave_host_id id of the host which is used to run the slave controller
+ * @param sxcfg serialized and compressed configuration
+ * @param sxcfg_size the size sxcfg
+ * @param scfg_size the size of uncompressed serialized configuration
+ * @param is_subordinate GNUNET_YES if the controller at delegated_host should
+ * be started by the slave controller; GNUNET_NO if the slave
+ * controller has to connect to the already started delegated
+ * controller via TCP/IP
+ * @return the operation handle
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_controller_link_2_ (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ uint32_t delegated_host_id,
+ uint32_t slave_host_id, const char *sxcfg,
+ size_t sxcfg_size, size_t scfg_size,
+ int is_subordinate);
+
+
+/**
+ * Same as the GNUNET_TESTBED_controller_link, but with ids for delegated host
+ * and slave host
+ *
+ * @param op_cls the operation closure for the event which is generated to
+ * signal success or failure of this operation
+ * @param master handle to the master controller who creates the association
+ * @param delegated_host_id id of the host to which requests should be
+ * delegated; cannot be NULL
+ * @param slave_host_id id of the host which should connect to controller
+ * running on delegated host ; use NULL to make the master controller
+ * connect to the delegated host
+ * @param slave_cfg configuration to use for the slave controller
+ * @param is_subordinate GNUNET_YES if the controller at delegated_host should
+ * be started by the slave controller; GNUNET_NO if the slave
+ * controller has to connect to the already started delegated
+ * controller via TCP/IP
+ * @return the operation handle
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_controller_link_ (void *op_cls,
+ struct GNUNET_TESTBED_Controller *master,
+ uint32_t delegated_host_id,
+ uint32_t slave_host_id,
+ const struct GNUNET_CONFIGURATION_Handle
+ *slave_cfg, int is_subordinate);
+
+
+/**
+ * Returns a timing slot which will be exclusively locked
+ *
+ * @param c the controller handle
+ * @param key a pointer which is associated to the returned slot; should not be
+ * NULL. It serves as a key to determine the correct owner of the slot
+ * @return the time slot index in the array of time slots in the controller
+ * handle
+ */
+unsigned int
+GNUNET_TESTBED_get_tslot_ (struct GNUNET_TESTBED_Controller *c, void *key);
+
+
+/**
+ * Function to update a time slot
+ *
+ * @param c the controller handle
+ * @param index the index of the time slot to update
+ * @param key the key to identify ownership of the slot
+ * @param time the new time
+ * @param failed should this reading be treated as coming from a fail event
+ */
+void
+GNUNET_TESTBED_update_time_slot_ (struct GNUNET_TESTBED_Controller *c,
+ unsigned int index, void *key,
+ struct GNUNET_TIME_Relative time, int failed);
+
+
+/**
+ * Releases a time slot thus making it available for be used again
+ *
+ * @param c the controller handle
+ * @param index the index of the the time slot
+ * @param key the key to prove ownership of the timeslot
+ * @return GNUNET_YES if the time slot is successfully removed; GNUNET_NO if the
+ * time slot cannot be removed - this could be because of the index
+ * greater than existing number of time slots or `key' being different
+ */
+int
+GNUNET_TESTBED_release_time_slot_ (struct GNUNET_TESTBED_Controller *c,
+ unsigned int index, void *key);
+
+
+
+
+#endif
+/* end of testbed_api.h */
diff --git a/src/testbed/testbed_api_hosts.c b/src/testbed/testbed_api_hosts.c
index 1b293b3..293f349 100644
--- a/src/testbed/testbed_api_hosts.c
+++ b/src/testbed/testbed_api_hosts.c
@@ -26,12 +26,46 @@
* @author Christian Grothoff
*/
#include "platform.h"
+#include "gnunet_util_lib.h"
#include "gnunet_testbed_service.h"
#include "gnunet_core_service.h"
-#include "gnunet_constants.h"
#include "gnunet_transport_service.h"
-#include "gnunet_hello_lib.h"
+#include "testbed_api.h"
+#include "testbed_api_hosts.h"
+
+/**
+ * Generic logging shorthand
+ */
+#define LOG(kind, ...) \
+ GNUNET_log_from (kind, "testbed-api-hosts", __VA_ARGS__);
+
+/**
+ * Number of extra elements we create space for when we grow host list
+ */
+#define HOST_LIST_GROW_STEP 10
+
+
+/**
+ * A list entry for registered controllers list
+ */
+struct RegisteredController
+{
+ /**
+ * The controller at which this host is registered
+ */
+ const struct GNUNET_TESTBED_Controller *controller;
+
+ /**
+ * The next ptr for DLL
+ */
+ struct RegisteredController *next;
+
+ /**
+ * The prev ptr for DLL
+ */
+ struct RegisteredController *prev;
+};
/**
@@ -42,32 +76,73 @@
struct GNUNET_TESTBED_Host
{
+ /**
+ * The next pointer for DLL
+ */
+ struct GNUNET_TESTBED_Host *next;
+
+ /**
+ * The prev pointer for DLL
+ */
+ struct GNUNET_TESTBED_Host *prev;
+ /**
+ * The hostname of the host; NULL for localhost
+ */
const char *hostname;
+ /**
+ * The username to be used for SSH login
+ */
const char *username;
/**
+ * The head for the list of controllers where this host is registered
+ */
+ struct RegisteredController *rc_head;
+
+ /**
+ * The tail for the list of controllers where this host is registered
+ */
+ struct RegisteredController *rc_tail;
+
+ /**
* Global ID we use to refer to a host on the network
*/
- uint32_t unique_id;
+ uint32_t id;
+ /**
+ * The port which is to be used for SSH
+ */
uint16_t port;
+
};
/**
+ * Array of available hosts
+ */
+static struct GNUNET_TESTBED_Host **host_list;
+
+/**
+ * The size of the available hosts list
+ */
+static unsigned int host_list_size;
+
+
+/**
* Lookup a host by ID.
- *
+ *
* @param id global host ID assigned to the host; 0 is
* reserved to always mean 'localhost'
- * @return handle to the host, NULL on error
+ * @return handle to the host, NULL if host not found
*/
struct GNUNET_TESTBED_Host *
GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id)
{
- GNUNET_break (0);
- return NULL;
+ if (host_list_size <= id)
+ return NULL;
+ return host_list[id];
}
@@ -75,7 +150,7 @@ GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id)
* Create a host by ID; given this host handle, we could not
* run peers at the host, but we can talk about the host
* internally.
- *
+ *
* @param id global host ID assigned to the host; 0 is
* reserved to always mean 'localhost'
* @return handle to the host, NULL on error
@@ -83,28 +158,66 @@ GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id)
struct GNUNET_TESTBED_Host *
GNUNET_TESTBED_host_create_by_id_ (uint32_t id)
{
- return NULL;
+ return GNUNET_TESTBED_host_create_with_id (id, NULL, NULL, 0);
}
/**
- * Obtain a host's unique global ID.
- *
+ * Obtain the host's unique global ID.
+ *
* @param host handle to the host, NULL means 'localhost'
* @return id global host ID assigned to the host (0 is
* 'localhost', but then obviously not globally unique)
*/
uint32_t
-GNUNET_TESTBED_host_get_id_ (struct GNUNET_TESTBED_Host *host)
+GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host * host)
+{
+ return host->id;
+}
+
+
+/**
+ * Obtain the host's hostname.
+ *
+ * @param host handle to the host, NULL means 'localhost'
+ * @return hostname of the host
+ */
+const char *
+GNUNET_TESTBED_host_get_hostname (const struct GNUNET_TESTBED_Host *host)
{
- GNUNET_break (0);
- return 0;
+ return host->hostname;
+}
+
+
+/**
+ * Obtain the host's username
+ *
+ * @param host handle to the host, NULL means 'localhost'
+ * @return username to login to the host
+ */
+const char *
+GNUNET_TESTBED_host_get_username_ (const struct GNUNET_TESTBED_Host *host)
+{
+ return host->username;
+}
+
+
+/**
+ * Obtain the host's ssh port
+ *
+ * @param host handle to the host, NULL means 'localhost'
+ * @return username to login to the host
+ */
+uint16_t
+GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host * host)
+{
+ return host->port;
}
/**
* Create a host to run peers and controllers on.
- *
+ *
* @param id global host ID assigned to the host; 0 is
* reserved to always mean 'localhost'
* @param hostname name of the host, use "NULL" for localhost
@@ -113,34 +226,52 @@ GNUNET_TESTBED_host_get_id_ (struct GNUNET_TESTBED_Host *host)
* @return handle to the host, NULL on error
*/
struct GNUNET_TESTBED_Host *
-GNUNET_TESTBED_host_create_with_id_ (uint32_t id,
- const char *hostname,
- const char *username,
- uint16_t port)
+GNUNET_TESTBED_host_create_with_id (uint32_t id, const char *hostname,
+ const char *username, uint16_t port)
{
- GNUNET_break (0);
- return NULL;
+ struct GNUNET_TESTBED_Host *host;
+ unsigned int new_size;
+
+ if ((id < host_list_size) && (NULL != host_list[id]))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Host with id: %u already created\n", id);
+ return NULL;
+ }
+ host = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host));
+ host->hostname = (NULL != hostname) ? GNUNET_strdup (hostname) : NULL;
+ host->username = (NULL != username) ? GNUNET_strdup (username) : NULL;
+ host->id = id;
+ host->port = (0 == port) ? 22 : port;
+ new_size = host_list_size;
+ while (id >= new_size)
+ new_size += HOST_LIST_GROW_STEP;
+ if (new_size != host_list_size)
+ GNUNET_array_grow (host_list, host_list_size, new_size);
+ GNUNET_assert (id < host_list_size);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding host with id: %u\n", host->id);
+ host_list[id] = host;
+ return host;
}
/**
* Create a host to run peers and controllers on.
- *
+ *
* @param hostname name of the host, use "NULL" for localhost
* @param username username to use for the login; may be NULL
* @param port port number to use for ssh; use 0 to let ssh decide
* @return handle to the host, NULL on error
*/
struct GNUNET_TESTBED_Host *
-GNUNET_TESTBED_host_create (const char *hostname,
- const char *username,
- uint16_t port)
+GNUNET_TESTBED_host_create (const char *hostname, const char *username,
+ uint16_t port)
{
static uint32_t uid_generator;
- return GNUNET_TESTBED_host_create_with_id_ (++uid_generator,
- hostname, username,
- port);
+ if (NULL == hostname)
+ return GNUNET_TESTBED_host_create_with_id (0, hostname, username, port);
+ return GNUNET_TESTBED_host_create_with_id (++uid_generator, hostname,
+ username, port);
}
@@ -148,15 +279,90 @@ GNUNET_TESTBED_host_create (const char *hostname,
* Load a set of hosts from a configuration file.
*
* @param filename file with the host specification
- * @param hosts set to the hosts found in the file
+ * @param hosts set to the hosts found in the file; caller must free this if
+ * number of hosts returned is greater than 0
* @return number of hosts returned in 'hosts', 0 on error
*/
unsigned int
GNUNET_TESTBED_hosts_load_from_file (const char *filename,
- struct GNUNET_TESTBED_Host **hosts)
+ struct GNUNET_TESTBED_Host ***hosts)
{
- GNUNET_break (0);
- return 0;
+ //struct GNUNET_TESTBED_Host **host_array;
+ struct GNUNET_TESTBED_Host *starting_host;
+ char *data;
+ char *buf;
+ char username[256];
+ char hostname[256];
+ uint64_t fs;
+ short int port;
+ int ret;
+ unsigned int offset;
+ unsigned int count;
+
+
+ GNUNET_assert (NULL != filename);
+ if (GNUNET_YES != GNUNET_DISK_file_test (filename))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s not found\n"), filename);
+ return 0;
+ }
+ if (GNUNET_OK !=
+ GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
+ fs = 0;
+ if (0 == fs)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s has no data\n"), filename);
+ return 0;
+ }
+ data = GNUNET_malloc (fs);
+ if (fs != GNUNET_DISK_fn_read (filename, data, fs))
+ {
+ GNUNET_free (data);
+ LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s cannot be read\n"),
+ filename);
+ return 0;
+ }
+ buf = data;
+ offset = 0;
+ starting_host = NULL;
+ count = 0;
+ while (offset < (fs - 1))
+ {
+ offset++;
+ if (((data[offset] == '\n')) && (buf != &data[offset]))
+ {
+ data[offset] = '\0';
+ ret =
+ SSCANF (buf, "%255[a-zA-Z0-9_]@%255[a-zA-Z0-9.]:%5hd", username,
+ hostname, &port);
+ if (3 == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Successfully read host %s, port %d and user %s from file\n",
+ hostname, port, username);
+ /* We store hosts in a static list; hence we only require the starting
+ * host pointer in that list to access the newly created list of hosts */
+ if (NULL == starting_host)
+ starting_host = GNUNET_TESTBED_host_create (hostname, username, port);
+ else
+ (void) GNUNET_TESTBED_host_create (hostname, username, port);
+ count++;
+ }
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Error reading line `%s' in hostfile\n", buf);
+ buf = &data[offset + 1];
+ }
+ else if ((data[offset] == '\n') || (data[offset] == '\0'))
+ buf = &data[offset + 1];
+ }
+ GNUNET_free (data);
+ if (NULL == starting_host)
+ return 0;
+ *hosts = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * count);
+ memcpy (*hosts, &host_list[GNUNET_TESTBED_host_get_id_ (starting_host)],
+ sizeof (struct GNUNET_TESTBED_Host *) * count);
+ return count;
}
@@ -169,32 +375,290 @@ GNUNET_TESTBED_hosts_load_from_file (const char *filename,
void
GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host)
{
- GNUNET_break (0);
+ struct RegisteredController *rc;
+ uint32_t id;
+
+ GNUNET_assert (host->id < host_list_size);
+ GNUNET_assert (host_list[host->id] == host);
+ host_list[host->id] = NULL;
+ /* clear registered controllers list */
+ for (rc = host->rc_head; NULL != rc; rc = host->rc_head)
+ {
+ GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
+ GNUNET_free (rc);
+ }
+ GNUNET_free_non_null ((char *) host->username);
+ GNUNET_free_non_null ((char *) host->hostname);
+ GNUNET_free (host);
+ while (host_list_size >= HOST_LIST_GROW_STEP)
+ {
+ for (id = host_list_size - 1; id > host_list_size - HOST_LIST_GROW_STEP;
+ id--)
+ if (NULL != host_list[id])
+ break;
+ if (id != host_list_size - HOST_LIST_GROW_STEP)
+ break;
+ if (NULL != host_list[id])
+ break;
+ host_list_size -= HOST_LIST_GROW_STEP;
+ }
+ host_list =
+ GNUNET_realloc (host_list,
+ sizeof (struct GNUNET_TESTBED_Host *) * host_list_size);
+}
+
+
+/**
+ * Marks a host as registered with a controller
+ *
+ * @param host the host to mark
+ * @param controller the controller at which this host is registered
+ */
+void
+GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_TESTBED_Controller
+ *const controller)
+{
+ struct RegisteredController *rc;
+
+ for (rc = host->rc_head; NULL != rc; rc = rc->next)
+ {
+ if (controller == rc->controller) /* already registered at controller */
+ {
+ GNUNET_break (0);
+ return;
+ }
+ }
+ rc = GNUNET_malloc (sizeof (struct RegisteredController));
+ rc->controller = controller;
+ GNUNET_CONTAINER_DLL_insert_tail (host->rc_head, host->rc_tail, rc);
+}
+
+
+/**
+ * Checks whether a host has been registered
+ *
+ * @param host the host to check
+ * @param controller the controller at which host's registration is checked
+ * @return GNUNET_YES if registered; GNUNET_NO if not
+ */
+int
+GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_TESTBED_Controller
+ *const controller)
+{
+ struct RegisteredController *rc;
+
+ for (rc = host->rc_head; NULL != rc; rc = rc->next)
+ {
+ if (controller == rc->controller) /* already registered at controller */
+ {
+ return GNUNET_YES;
+ }
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * The handle for whether a host is habitable or not
+ */
+struct GNUNET_TESTBED_HostHabitableCheckHandle
+{
+ /**
+ * The host to check
+ */
+ const struct GNUNET_TESTBED_Host *host;
+
+ /* /\** */
+ /* * the configuration handle to lookup the path of the testbed helper */
+ /* *\/ */
+ /* const struct GNUNET_CONFIGURATION_Handle *cfg; */
+
+ /**
+ * The callback to call once we have the status
+ */
+ GNUNET_TESTBED_HostHabitableCallback cb;
+
+ /**
+ * The callback closure
+ */
+ void *cb_cls;
+
+ /**
+ * The process handle for the SSH process
+ */
+ struct GNUNET_OS_Process *auxp;
+
+ /**
+ * The SSH destination address string
+ */
+ char *ssh_addr;
+
+ /**
+ * The destination port string
+ */
+ char *portstr;
+
+ /**
+ * The path for hte testbed helper binary
+ */
+ char *helper_binary_path;
+
+ /**
+ * Task id for the habitability check task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier habitability_check_task;
+
+ /**
+ * How long we wait before checking the process status. Should grow
+ * exponentially
+ */
+ struct GNUNET_TIME_Relative wait_time;
+
+};
+
+
+/**
+ * Task for checking whether a host is habitable or not
+ *
+ * @param cls GNUNET_TESTBED_HostHabitableCheckHandle
+ * @param tc the scheduler task context
+ */
+static void
+habitability_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TESTBED_HostHabitableCheckHandle *h = cls;
+ void *cb_cls;
+ GNUNET_TESTBED_HostHabitableCallback cb;
+ const struct GNUNET_TESTBED_Host *host;
+ unsigned long code;
+ enum GNUNET_OS_ProcessStatusType type;
+ int ret;
+
+ h->habitability_check_task = GNUNET_SCHEDULER_NO_TASK;
+ ret = GNUNET_OS_process_status (h->auxp, &type, &code);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ ret = GNUNET_NO;
+ goto call_cb;
+ }
+ if (GNUNET_NO == ret)
+ {
+ h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
+ h->habitability_check_task =
+ GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
+ return;
+ }
+ GNUNET_OS_process_destroy (h->auxp);
+ h->auxp = NULL;
+ ret = (0 != code) ? GNUNET_NO : GNUNET_YES;
+
+call_cb:
+ GNUNET_free (h->ssh_addr);
+ GNUNET_free (h->portstr);
+ GNUNET_free (h->helper_binary_path);
+ if (NULL != h->auxp)
+ GNUNET_OS_process_destroy (h->auxp);
+ cb = h->cb;
+ cb_cls = h->cb_cls;
+ host = h->host;
+ GNUNET_free (h);
+ if (NULL != cb)
+ cb (cb_cls, host, ret);
}
/**
- * Run a given helper process at the given host. Communication
- * with the helper will be via GNUnet messages on stdin/stdout.
- * Runs the process via 'ssh' at the specified host, or locally.
- * Essentially an SSH-wrapper around the 'gnunet_helper_lib.h' API.
- *
- * @param host host to use, use "NULL" for localhost
- * @param binary_argv binary name and command-line arguments to give to the binary
- * @param cb function to call for messages received from the binary
- * @param cb_cls closure for cb
- * @return handle to terminate the command, NULL on error
+ * Checks whether a host can be used to start testbed service
+ *
+ * @param host the host to check
+ * @param config the configuration handle to lookup the path of the testbed
+ * helper
+ * @param cb the callback to call to inform about habitability of the given host
+ * @param cb_cls the closure for the callback
+ * @return NULL upon any error or a handle which can be passed to
+ * GNUNET_TESTBED_is_host_habitable_cancel()
*/
-struct GNUNET_HELPER_Handle *
-GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host,
- char *const binary_argv[],
- GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls)
+struct GNUNET_TESTBED_HostHabitableCheckHandle *
+GNUNET_TESTBED_is_host_habitable (const struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_CONFIGURATION_Handle
+ *config,
+ GNUNET_TESTBED_HostHabitableCallback cb,
+ void *cb_cls)
{
- /* FIXME: decide on the SSH command line, prepend it and
- run GNUNET_HELPER_start with the modified binary_name and binary_argv! */
- GNUNET_break (0);
- return NULL;
+ struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
+ char *remote_args[11];
+ const char *hostname;
+ unsigned int argp;
+
+ h = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostHabitableCheckHandle));
+ h->cb = cb;
+ h->cb_cls = cb_cls;
+ h->host = host;
+ hostname = (NULL == host->hostname) ? "127.0.0.1" : host->hostname;
+ if (NULL == host->username)
+ h->ssh_addr = GNUNET_strdup (hostname);
+ else
+ GNUNET_asprintf (&h->ssh_addr, "%s@%s", host->username, hostname);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (config, "testbed",
+ "HELPER_BINARY_PATH",
+ &h->helper_binary_path))
+ h->helper_binary_path =
+ GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
+ argp = 0;
+ remote_args[argp++] = "ssh";
+ GNUNET_asprintf (&h->portstr, "%u", host->port);
+ remote_args[argp++] = "-p";
+ remote_args[argp++] = h->portstr;
+ remote_args[argp++] = "-o";
+ remote_args[argp++] = "BatchMode=yes";
+ remote_args[argp++] = "-o";
+ remote_args[argp++] = "NoHostAuthenticationForLocalhost=yes";
+ remote_args[argp++] = h->ssh_addr;
+ remote_args[argp++] = "stat";
+ remote_args[argp++] = h->helper_binary_path;
+ remote_args[argp++] = NULL;
+ GNUNET_assert (argp == 11);
+ h->auxp =
+ GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ERR, NULL,
+ NULL, "ssh", remote_args);
+ if (NULL == h->auxp)
+ {
+ GNUNET_break (0); /* Cannot exec SSH? */
+ GNUNET_free (h->ssh_addr);
+ GNUNET_free (h->portstr);
+ GNUNET_free (h->helper_binary_path);
+ GNUNET_free (h);
+ return NULL;
+ }
+ h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
+ h->habitability_check_task =
+ GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
+ return h;
}
+/**
+ * Function to cancel a request started using GNUNET_TESTBED_is_host_habitable()
+ *
+ * @param handle the habitability check handle
+ */
+void
+GNUNET_TESTBED_is_host_habitable_cancel (struct
+ GNUNET_TESTBED_HostHabitableCheckHandle
+ *handle)
+{
+ GNUNET_SCHEDULER_cancel (handle->habitability_check_task);
+ (void) GNUNET_OS_process_kill (handle->auxp, SIGTERM);
+ (void) GNUNET_OS_process_wait (handle->auxp);
+ GNUNET_OS_process_destroy (handle->auxp);
+ GNUNET_free (handle->ssh_addr);
+ GNUNET_free (handle->portstr);
+ GNUNET_free (handle->helper_binary_path);
+ GNUNET_free (handle);
+}
+
/* end of testbed_api_hosts.c */
diff --git a/src/testbed/testbed_api_hosts.h b/src/testbed/testbed_api_hosts.h
index 401d4e0..c0f4290 100644
--- a/src/testbed/testbed_api_hosts.h
+++ b/src/testbed/testbed_api_hosts.h
@@ -23,16 +23,17 @@
* @brief internal API to access the 'hosts' subsystem
* @author Christian Grothoff
*/
+
#ifndef NEW_TESTING_API_HOSTS_H
#define NEW_TESTING_API_HOSTS_H
#include "gnunet_testbed_service.h"
-#include "gnunet_helper_lib.h"
+#include "testbed_helper.h"
/**
* Lookup a host by ID.
- *
+ *
* @param id global host ID assigned to the host; 0 is
* reserved to always mean 'localhost'
* @return handle to the host, NULL on error
@@ -45,7 +46,7 @@ GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id);
* Create a host by ID; given this host handle, we could not
* run peers at the host, but we can talk about the host
* internally.
- *
+ *
* @param id global host ID assigned to the host; 0 is
* reserved to always mean 'localhost'
* @return handle to the host, NULL on error
@@ -55,51 +56,104 @@ GNUNET_TESTBED_host_create_by_id_ (uint32_t id);
/**
- * Create a host to run peers and controllers on. This function is used
- * if a peer learns about a host via IPC between controllers (and thus
- * some higher-level controller has already determined the unique IDs).
- *
- * @param id global host ID assigned to the host; 0 is
- * reserved to always mean 'localhost'
- * @param hostname name of the host, use "NULL" for localhost
- * @param username username to use for the login; may be NULL
- * @param port port number to use for ssh; use 0 to let ssh decide
- * @return handle to the host, NULL on error
- */
-struct GNUNET_TESTBED_Host *
-GNUNET_TESTBED_host_create_with_id_ (uint32_t id,
- const char *hostname,
- const char *username,
- uint16_t port);
-
-
-/**
* Obtain a host's unique global ID.
- *
+ *
* @param host handle to the host, NULL means 'localhost'
* @return id global host ID assigned to the host (0 is
* 'localhost', but then obviously not globally unique)
*/
uint32_t
-GNUNET_TESTBED_host_get_id_ (struct GNUNET_TESTBED_Host *host);
+GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host);
/**
- * Run a given helper process at the given host. Communication
- * with the helper will be via GNUnet messages on stdin/stdout.
- * Runs the process via 'ssh' at the specified host, or locally.
- * Essentially an SSH-wrapper around the 'gnunet_helper_lib.h' API.
- *
- * @param host host to use, use "NULL" for localhost
- * @param binary_argv binary name and command-line arguments to give to the binary
- * @param cb function to call for messages received from the binary
- * @param cb_cls closure for cb
- * @return handle to terminate the command, NULL on error
+ * Obtain the host's username
+ *
+ * @param host handle to the host, NULL means 'localhost'
+ * @return username to login to the host
+ */
+const char *
+GNUNET_TESTBED_host_get_username_ (const struct GNUNET_TESTBED_Host *host);
+
+
+/**
+ * Obtain the host's ssh port
+ *
+ * @param host handle to the host, NULL means 'localhost'
+ * @return username to login to the host
*/
-struct GNUNET_HELPER_Handle *
-GNUNET_TESTBED_host_run_ (struct GNUNET_TESTBED_Host *host,
- char *const binary_argv[],
- GNUNET_SERVER_MessageTokenizerCallback cb, void *cb_cls);
+uint16_t
+GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host *host);
+
+
+/**
+ * Opaque wrapper around GNUNET_HELPER_Handle
+ */
+struct GNUNET_TESTBED_HelperHandle;
+
+
+/* /\** */
+/* * Run a given helper process at the given host. Communication */
+/* * with the helper will be via GNUnet messages on stdin/stdout. */
+/* * Runs the process via 'ssh' at the specified host, or locally. */
+/* * Essentially an SSH-wrapper around the 'gnunet_helper_lib.h' API. */
+/* * */
+/* * @param controller_ip the ip address of the controller. Will be set as TRUSTED */
+/* * host when starting testbed controller at host */
+/* * @param host host to use, use "NULL" for localhost */
+/* * @param binary_argv binary name and command-line arguments to give to the */
+/* * binary */
+/* * @param cfg template configuration to use for the remote controller; the */
+/* * remote controller will be started with a slightly modified */
+/* * configuration (port numbers, unix domain sockets and service home */
+/* * values are changed as per TESTING library on the remote host) */
+/* * @param cb the callback to run when helper process dies; cannot be NULL */
+/* * @param cb_cls the closure for the above callback */
+/* * @return handle to terminate the command, NULL on error */
+/* *\/ */
+/* struct GNUNET_TESTBED_HelperHandle * */
+/* GNUNET_TESTBED_host_run_ (const char *controller_ip, */
+/* const struct GNUNET_TESTBED_Host *host, */
+/* const struct GNUNET_CONFIGURATION_Handle *cfg, */
+/* GNUNET_HELPER_ExceptionCallback cb, */
+/* void *cb_cls); */
+
+
+
+/* /\** */
+/* * Stops a helper in the HelperHandle using GNUNET_HELPER_stop */
+/* * */
+/* * @param handle the handle returned from GNUNET_TESTBED_host_start_ */
+/* *\/ */
+/* void */
+/* GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle); */
+
+
+/**
+ * Marks a host as registered with a controller
+ *
+ * @param host the host to mark
+ * @param controller the controller at which this host is registered
+ */
+void
+GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_TESTBED_Controller
+ *controller);
+
+
+/**
+ * Checks whether a host has been registered with the given controller
+ *
+ * @param host the host to check
+ * @param controller the controller at which host's registration is checked
+ * @return GNUNET_YES if registered; GNUNET_NO if not
+ */
+int
+GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_TESTBED_Controller
+ *controller);
+
+
#endif
/* end of testbed_api_hosts.h */
diff --git a/src/testbed/testbed_api_operations.c b/src/testbed/testbed_api_operations.c
index c98998b..3e7eb91 100644
--- a/src/testbed/testbed_api_operations.c
+++ b/src/testbed/testbed_api_operations.c
@@ -28,6 +28,89 @@
/**
+ * An entry in the operation queue
+ */
+struct QueueEntry
+{
+ /**
+ * The next DLL pointer
+ */
+ struct QueueEntry *next;
+
+ /**
+ * The prev DLL pointer
+ */
+ struct QueueEntry *prev;
+
+ /**
+ * The operation this entry holds
+ */
+ struct GNUNET_TESTBED_Operation *op;
+
+ /**
+ * How many units of resources does the operation need
+ */
+ unsigned int nres;
+};
+
+
+/**
+ * Queue of operations where we can only support a certain
+ * number of concurrent operations of a particular type.
+ */
+struct OperationQueue
+{
+ /**
+ * The head of the operation queue
+ */
+ struct QueueEntry *head;
+
+ /**
+ * The tail of the operation queue
+ */
+ struct QueueEntry *tail;
+
+ /**
+ * Number of operations that are currently active in this queue.
+ */
+ unsigned int active;
+
+ /**
+ * Max number of operations which can be active at any time in this queue
+ */
+ unsigned int max_active;
+
+};
+
+
+/**
+ * Operation state
+ */
+enum OperationState
+{
+ /**
+ * The operation is just created and is in initial state
+ */
+ OP_STATE_INIT,
+
+ /**
+ * The operation is currently waiting for resources
+ */
+ OP_STATE_WAITING,
+
+ /**
+ * The operation is ready to be started
+ */
+ OP_STATE_READY,
+
+ /**
+ * The operation has started
+ */
+ OP_STATE_STARTED
+};
+
+
+/**
* Opaque handle to an abstract operation to be executed by the testing framework.
*/
struct GNUNET_TESTBED_Operation
@@ -42,33 +125,125 @@ struct GNUNET_TESTBED_Operation
* not have been started yet).
*/
OperationRelease release;
-
+
/**
* Closure for callbacks.
*/
void *cb_cls;
- // FIXME!
+ /**
+ * Array of operation queues this Operation belongs to.
+ */
+ struct OperationQueue **queues;
+
+ /**
+ * Array of number resources an operation need from each queue. This numbers
+ * in this array should correspond to the queues array
+ */
+ unsigned int *nres;
+
+ /**
+ * The id of the task which calls OperationStart for this operation
+ */
+ GNUNET_SCHEDULER_TaskIdentifier start_task_id;
+
+ /**
+ * Number of queues in the operation queues array
+ */
+ unsigned int nqueues;
+
+ /**
+ * The state of the operation
+ */
+ enum OperationState state;
};
/**
- * Queue of operations where we can only support a certain
- * number of concurrent operations of a particular type.
+ * Task for calling OperationStart on operation
+ *
+ * @param cls the Operation
+ * @param tc the TaskContext from scheduler
*/
-struct OperationQueue
+static void
+call_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
+ struct GNUNET_TESTBED_Operation *op = cls;
- /**
- * Maximum number of operationst that can be concurrently
- * active in this queue.
- */
- unsigned int max_active;
+ op->start_task_id = GNUNET_SCHEDULER_NO_TASK;
+ op->state = OP_STATE_STARTED;
+ if (NULL != op->start)
+ op->start (op->cb_cls);
+}
- // FIXME!
-};
+/**
+ * Checks for the readiness of an operation and schedules a operation start task
+ *
+ * @param op the operation
+ */
+static void
+check_readiness (struct GNUNET_TESTBED_Operation *op)
+{
+ unsigned int i;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == op->start_task_id);
+ for (i = 0; i < op->nqueues; i++)
+ {
+ GNUNET_assert (0 < op->nres[i]);
+ if ((op->queues[i]->active + op->nres[i]) > op->queues[i]->max_active)
+ return;
+ }
+ for (i = 0; i < op->nqueues; i++)
+ op->queues[i]->active += op->nres[i];
+ op->state = OP_STATE_READY;
+ op->start_task_id = GNUNET_SCHEDULER_add_now (&call_start, op);
+}
+
+
+/**
+ * Defers a ready to be executed operation back to waiting
+ *
+ * @param op the operation to defer
+ */
+static void
+defer (struct GNUNET_TESTBED_Operation *op)
+{
+ unsigned int i;
+
+ GNUNET_assert (OP_STATE_READY == op->state);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != op->start_task_id);
+ GNUNET_SCHEDULER_cancel (op->start_task_id);
+ op->start_task_id = GNUNET_SCHEDULER_NO_TASK;
+ for (i = 0; i < op->nqueues; i++)
+ op->queues[i]->active--;
+ op->state = OP_STATE_WAITING;
+}
+
+
+/**
+ * Create an 'operation' to be performed.
+ *
+ * @param cls closure for the callbacks
+ * @param start function to call to start the operation
+ * @param release function to call to close down the operation
+ * @return handle to the operation
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_operation_create_ (void *cls, OperationStart start,
+ OperationRelease release)
+{
+ struct GNUNET_TESTBED_Operation *op;
+
+ op = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Operation));
+ op->start = start;
+ op->state = OP_STATE_INIT;
+ op->release = release;
+ op->cb_cls = cls;
+ op->start_task_id = GNUNET_SCHEDULER_NO_TASK;
+ return op;
+}
/**
@@ -98,97 +273,188 @@ GNUNET_TESTBED_operation_queue_create_ (unsigned int max_active)
void
GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue)
{
- GNUNET_break (0);
+ GNUNET_break (NULL == queue->head);
+ GNUNET_break (NULL == queue->tail);
GNUNET_free (queue);
}
/**
- * Add an operation to a queue. An operation can be in multiple
- * queues at once. Once all queues permit the operation to become
- * active, the operation will be activated. The actual activation
- * will occur in a separate task (thus allowing multiple queue
- * insertions to be made without having the first one instantly
- * trigger the operation if the first queue has sufficient
- * resources).
+ * Function to reset the maximum number of operations in the given queue. If
+ * max_active is lesser than the number of currently active operations, the
+ * active operations are not stopped immediately.
+ *
+ * @param queue the operation queue which has to be modified
+ * @param max_active the new maximum number of active operations
+ */
+void
+GNUNET_TESTBED_operation_queue_reset_max_active_ (struct OperationQueue *queue,
+ unsigned int max_active)
+{
+ struct QueueEntry *entry;
+
+ queue->max_active = max_active;
+ /* if (queue->active >= queue->max_active) */
+ /* return; */
+
+ entry = queue->head;
+ while ((queue->active > queue->max_active) && (NULL != entry))
+ {
+ if (entry->op->state == OP_STATE_READY)
+ defer (entry->op);
+ entry = entry->next;
+ }
+
+ entry = queue->head;
+ while ((NULL != entry) && (queue->active < queue->max_active))
+ {
+ if (OP_STATE_WAITING == entry->op->state)
+ check_readiness (entry->op);
+ entry = entry->next;
+ }
+}
+
+
+/**
+ * Add an operation to a queue. An operation can be in multiple queues at
+ * once. Once the operation is inserted into all the queues
+ * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
+ * waiting for the operation to become active.
*
* @param queue queue to add the operation to
* @param operation operation to add to the queue
+ * @param nres the number of units of the resources of queue needed by the
+ * operation. Should be greater than 0.
*/
void
-GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue,
- struct GNUNET_TESTBED_Operation *operation)
+GNUNET_TESTBED_operation_queue_insert2_ (struct OperationQueue *queue,
+ struct GNUNET_TESTBED_Operation
+ *operation, unsigned int nres)
{
- GNUNET_break (0);
+ struct QueueEntry *entry;
+ unsigned int qsize;
+
+ GNUNET_assert (0 < nres);
+ entry = GNUNET_malloc (sizeof (struct QueueEntry));
+ entry->op = operation;
+ entry->nres = nres;
+ GNUNET_CONTAINER_DLL_insert_tail (queue->head, queue->tail, entry);
+ qsize = operation->nqueues;
+ GNUNET_array_append (operation->queues, operation->nqueues, queue);
+ GNUNET_array_append (operation->nres, qsize, nres);
+ GNUNET_assert (qsize == operation->nqueues);
}
/**
- * Remove an operation from a queue. This can be because the
- * oeration was active and has completed (and the resources have
- * been released), or because the operation was cancelled and
- * thus scheduling the operation is no longer required.
+ * Add an operation to a queue. An operation can be in multiple queues at
+ * once. Once the operation is inserted into all the queues
+ * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
+ * waiting for the operation to become active. The operation is assumed to take
+ * 1 queue resource. Use GNUNET_TESTBED_operation_queue_insert2_() if it
+ * requires more than 1
*
* @param queue queue to add the operation to
* @param operation operation to add to the queue
*/
void
-GNUNET_TESTBED_operation_queue_remove_ (struct OperationQueue *queue,
- struct GNUNET_TESTBED_Operation *operation)
+GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue,
+ struct GNUNET_TESTBED_Operation
+ *operation)
{
- GNUNET_break (0);
+ return GNUNET_TESTBED_operation_queue_insert2_ (queue, operation, 1);
}
/**
- * An operation is 'done' (was cancelled or finished); remove
- * it from the queues and release associated resources.
+ * Marks the given operation as waiting on the queues. Once all queues permit
+ * the operation to become active, the operation will be activated. The actual
+ * activation will occur in a separate task (thus allowing multiple queue
+ * insertions to be made without having the first one instantly trigger the
+ * operation if the first queue has sufficient resources).
*
- * @param operation operation that finished
+ * @param operation the operation to marks as waiting
*/
-static void
-operation_release (struct GNUNET_TESTBED_Operation *operation)
+void
+GNUNET_TESTBED_operation_begin_wait_ (struct GNUNET_TESTBED_Operation
+ *operation)
{
- // call operation->release, remove from queues
- GNUNET_break (0);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == operation->start_task_id);
+ operation->state = OP_STATE_WAITING;
+ check_readiness (operation);
}
/**
- * Cancel a pending operation. Releases all resources
- * of the operation and will ensure that no event
- * is generated for the operation. Does NOT guarantee
- * that the operation will be fully undone (or that
- * nothing ever happened).
- *
- * @param operation operation to cancel
+ * Remove an operation from a queue. This can be because the
+ * oeration was active and has completed (and the resources have
+ * been released), or because the operation was cancelled and
+ * thus scheduling the operation is no longer required.
+ *
+ * @param queue queue to add the operation to
+ * @param operation operation to add to the queue
*/
void
-GNUNET_TESTBED_operation_cancel (struct GNUNET_TESTBED_Operation *operation)
+GNUNET_TESTBED_operation_queue_remove_ (struct OperationQueue *queue,
+ struct GNUNET_TESTBED_Operation
+ *operation)
{
- // test that operation had not yet generated an event
- GNUNET_break (0);
- operation_release (operation);
+ struct QueueEntry *entry;
+ struct QueueEntry *entry2;
+
+ for (entry = queue->head; NULL != entry; entry = entry->next)
+ if (entry->op == operation)
+ break;
+ GNUNET_assert (NULL != entry);
+ GNUNET_assert (0 < entry->nres);
+ switch (operation->state)
+ {
+ case OP_STATE_INIT:
+ case OP_STATE_WAITING:
+ break;
+ case OP_STATE_READY:
+ case OP_STATE_STARTED:
+ GNUNET_assert (0 != queue->active);
+ GNUNET_assert (queue->active >= entry->nres);
+ queue->active -= entry->nres;
+ break;
+ }
+ entry2 = entry->next;
+ GNUNET_CONTAINER_DLL_remove (queue->head, queue->tail, entry);
+ GNUNET_free (entry);
+ for (; NULL != entry2; entry2 = entry2->next)
+ if (OP_STATE_WAITING == entry2->op->state)
+ break;
+ if (NULL == entry2)
+ return;
+ check_readiness (entry2->op);
}
/**
- * Signal that the information from an operation has been fully
- * processed. This function MUST be called for each event
- * of type 'operation_finished' to fully remove the operation
- * from the operation queue. After calling this function, the
- * 'op_result' becomes invalid (!).
- *
- * @param operation operation to signal completion for
+ * An operation is 'done' (was cancelled or finished); remove
+ * it from the queues and release associated resources.
+ *
+ * @param operation operation that finished
*/
void
-GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
+GNUNET_TESTBED_operation_release_ (struct GNUNET_TESTBED_Operation *operation)
{
- // test that operation was started and had generated an event
- GNUNET_break (0);
- operation_release (operation);
+ unsigned int i;
+
+ if (GNUNET_SCHEDULER_NO_TASK != operation->start_task_id)
+ {
+ GNUNET_SCHEDULER_cancel (operation->start_task_id);
+ operation->start_task_id = GNUNET_SCHEDULER_NO_TASK;
+ }
+ for (i = 0; i < operation->nqueues; i++)
+ GNUNET_TESTBED_operation_queue_remove_ (operation->queues[i], operation);
+ GNUNET_free (operation->queues);
+ GNUNET_free (operation->nres);
+ if (NULL != operation->release)
+ operation->release (operation->cb_cls);
+ GNUNET_free (operation);
}
-
/* end of testbed_api_operations.c */
diff --git a/src/testbed/testbed_api_operations.h b/src/testbed/testbed_api_operations.h
index 4c888d5..61b45e2 100644
--- a/src/testbed/testbed_api_operations.h
+++ b/src/testbed/testbed_api_operations.h
@@ -59,20 +59,62 @@ GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue);
/**
- * Add an operation to a queue. An operation can be in multiple
- * queues at once. Once all queues permit the operation to become
- * active, the operation will be activated. The actual activation
- * will occur in a separate task (thus allowing multiple queue
- * insertions to be made without having the first one instantly
- * trigger the operation if the first queue has sufficient
- * resources).
+ * Function to reset the maximum number of operations in the given queue. If
+ * max_active is lesser than the number of currently active operations, the
+ * active operations are not stopped immediately.
+ *
+ * @param queue the operation queue which has to be modified
+ * @param max_active the new maximum number of active operations
+ */
+void
+GNUNET_TESTBED_operation_queue_reset_max_active_ (struct OperationQueue *queue,
+ unsigned int max_active);
+
+
+/**
+ * Add an operation to a queue. An operation can be in multiple queues at
+ * once. Once the operation is inserted into all the queues
+ * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
+ * waiting for the operation to become active.
+ *
+ * @param queue queue to add the operation to
+ * @param operation operation to add to the queue
+ * @param nres the number of units of the resources of queue needed by the
+ * operation. Should be greater than 0.
+ */
+void
+GNUNET_TESTBED_operation_queue_insert2_ (struct OperationQueue *queue,
+ struct GNUNET_TESTBED_Operation
+ *operation, unsigned int nres);
+
+
+/**
+ * Add an operation to a queue. An operation can be in multiple queues at
+ * once. Once the operation is inserted into all the queues
+ * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
+ * waiting for the operation to become active.
*
* @param queue queue to add the operation to
* @param operation operation to add to the queue
*/
void
GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue,
- struct GNUNET_TESTBED_Operation *operation);
+ struct GNUNET_TESTBED_Operation
+ *operation);
+
+
+/**
+ * Marks the given operation as waiting on the queues. Once all queues permit
+ * the operation to become active, the operation will be activated. The actual
+ * activation will occur in a separate task (thus allowing multiple queue
+ * insertions to be made without having the first one instantly trigger the
+ * operation if the first queue has sufficient resources).
+ *
+ * @param operation the operation to marks as waiting
+ */
+void
+GNUNET_TESTBED_operation_begin_wait_ (struct GNUNET_TESTBED_Operation
+ *operation);
/**
@@ -86,7 +128,8 @@ GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue,
*/
void
GNUNET_TESTBED_operation_queue_remove_ (struct OperationQueue *queue,
- struct GNUNET_TESTBED_Operation *operation);
+ struct GNUNET_TESTBED_Operation
+ *operation);
@@ -94,8 +137,10 @@ GNUNET_TESTBED_operation_queue_remove_ (struct OperationQueue *queue,
* Function to call to start an operation once all
* queues the operation is part of declare that the
* operation can be activated.
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
-typedef void (*OperationStart)(void *cls);
+typedef void (*OperationStart) (void *cls);
/**
@@ -107,9 +152,11 @@ typedef void (*OperationStart)(void *cls);
* a callback to the 'OperationStart' preceeds the call to
* 'OperationRelease'. Implementations of this function are expected
* to clean up whatever state is in 'cls' and release all resources
- * associated with the operation.
+ * associated with the operation.
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
-typedef void (*OperationRelease)(void *cls);
+typedef void (*OperationRelease) (void *cls);
/**
@@ -118,14 +165,21 @@ typedef void (*OperationRelease)(void *cls);
* @param cls closure for the callbacks
* @param start function to call to start the operation
* @param release function to call to close down the operation
- * @param ... FIXME
* @return handle to the operation
*/
struct GNUNET_TESTBED_Operation *
-GNUNET_TESTBED_operation_create_ (void *cls,
- OperationStart start,
- OperationRelease release,
- ...);
+GNUNET_TESTBED_operation_create_ (void *cls, OperationStart start,
+ OperationRelease release);
+
+
+/**
+ * An operation is 'done' (was cancelled or finished); remove
+ * it from the queues and release associated resources.
+ *
+ * @param operation operation that finished
+ */
+void
+GNUNET_TESTBED_operation_release_ (struct GNUNET_TESTBED_Operation *operation);
#endif
diff --git a/src/testbed/testbed_api_peers.c b/src/testbed/testbed_api_peers.c
index 7ee0dd1..908428a 100644
--- a/src/testbed/testbed_api_peers.c
+++ b/src/testbed/testbed_api_peers.c
@@ -23,118 +23,380 @@
* @brief management of the knowledge about peers in this library
* (we know the peer ID, its host, pending operations, etc.)
* @author Christian Grothoff
+ * @author Sree Harsha Totakura
*/
+
#include "platform.h"
#include "testbed_api_peers.h"
+#include "testbed_api.h"
+#include "testbed.h"
+#include "testbed_api_hosts.h"
+#include "testbed_api_operations.h"
+
+/**
+ * Function to call to start a peer_create type operation once all
+ * queues the operation is part of declare that the
+ * operation can be activated.
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_peer_create (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct PeerCreateData *data;
+ struct GNUNET_TESTBED_PeerCreateMessage *msg;
+ char *config;
+ char *xconfig;
+ size_t c_size;
+ size_t xc_size;
+ uint16_t msize;
+
+ GNUNET_assert (OP_PEER_CREATE == opc->type);
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ GNUNET_assert (NULL != data->peer);
+ opc->state = OPC_STATE_STARTED;
+ config = GNUNET_CONFIGURATION_serialize (data->cfg, &c_size);
+ xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
+ GNUNET_free (config);
+ msize = xc_size + sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
+ msg = GNUNET_realloc (xconfig, msize);
+ memmove (&msg[1], msg, xc_size);
+ msg->header.size = htons (msize);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER);
+ msg->operation_id = GNUNET_htonll (opc->id);
+ msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->peer->host));
+ msg->peer_id = htonl (data->peer->unique_id);
+ msg->config_size = htonl (c_size);
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
+}
/**
- * Details about a peer; kept in a separate struct to avoid bloating
- * memory consumption everywhere...
+ * Callback which will be called when peer_create type operation is released
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
-struct PeerDetails
+static void
+oprelease_peer_create (void *cls)
{
- /**
- * Configuration of the peer; NULL if we are not sure what the peer's correct
- * configuration actually is; non-NULL if this peer is controlled by this
- * process.
- */
- struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct OperationContext *opc = cls;
+
+ switch (opc->state)
+ {
+ case OPC_STATE_STARTED:
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ /* No break we continue flow */
+ case OPC_STATE_INIT:
+ GNUNET_free (((struct PeerCreateData *) opc->data)->peer);
+ GNUNET_free (opc->data);
+ break;
+ case OPC_STATE_FINISHED:
+ break;
+ }
+ GNUNET_free (opc);
+}
- /**
- * If this process has started this peer's ARM process, this is the handle
- * to the 'gnunet-service-arm' process of the peer.
- */
- struct GNUNET_OS_Process *arm;
-
- // ...
-};
+/**
+ * Function called when a peer destroy operation is ready
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_peer_destroy (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct GNUNET_TESTBED_Peer *peer;
+ struct GNUNET_TESTBED_PeerDestroyMessage *msg;
+
+ GNUNET_assert (OP_PEER_DESTROY == opc->type);
+ peer = opc->data;
+ GNUNET_assert (NULL != peer);
+ opc->state = OPC_STATE_STARTED;
+ msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerDestroyMessage));
+ msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerDestroyMessage));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER);
+ msg->peer_id = htonl (peer->unique_id);
+ msg->operation_id = GNUNET_htonll (opc->id);
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
+}
/**
- * A peer controlled by the testing framework. A peer runs
- * at a particular host.
- */
-struct GNUNET_TESTBED_Peer
+ * Callback which will be called when peer_create type operation is released
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_peer_destroy (void *cls)
{
- /**
- * Our controller context (not necessarily the controller
- * that is responsible for starting/running the peer!).
- */
- struct GNUNET_TESTBED_Controller *controller;
-
- /**
- * Which host does this peer run on?
- */
- struct GNUENT_TESTING_Host *host;
-
- /**
- * Globally unique ID of the peer.
- */
- uint32_t unique_id;
-
- /**
- * Internals of the peer for the controlling process; NULL if
- * this process is not controlling this peer.
- */
- struct PeerDetails *details;
-
-};
+ struct OperationContext *opc = cls;
+
+ if (OPC_STATE_FINISHED != opc->state)
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_free (opc);
+}
/**
- * Lookup a peer by ID.
- *
- * @param id global peer ID assigned to the peer
- * @return handle to the host, NULL on error
+ * Function called when a peer start operation is ready
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
-struct GNUNET_TESTBED_Peer *
-GNUNET_TESTBED_peer_lookup_by_id_ (uint32_t id)
+static void
+opstart_peer_start (void *cls)
{
- GNUNET_break (0);
- return NULL;
+ struct OperationContext *opc = cls;
+ struct GNUNET_TESTBED_PeerStartMessage *msg;
+ struct PeerEventData *data;
+ struct GNUNET_TESTBED_Peer *peer;
+
+ GNUNET_assert (OP_PEER_START == opc->type);
+ GNUNET_assert (NULL != opc->data);
+ data = opc->data;
+ GNUNET_assert (NULL != data->peer);
+ peer = data->peer;
+ GNUNET_assert ((PS_CREATED == peer->state) || (PS_STOPPED == peer->state));
+ opc->state = OPC_STATE_STARTED;
+ msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerStartMessage));
+ msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerStartMessage));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_START_PEER);
+ msg->peer_id = htonl (peer->unique_id);
+ msg->operation_id = GNUNET_htonll (opc->id);
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
}
/**
- * Create the given peer at the specified host using the given
- * controller. If the given controller is not running on the target
- * host, it should find or create a controller at the target host and
- * delegate creating the peer. Explicit delegation paths can be setup
- * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation
- * path exists, a direct link with a subordinate controller is setup
- * for the first delegated peer to a particular host; the subordinate
- * controller is then destroyed once the last peer that was delegated
- * to the remote host is stopped. This function is used in particular
- * if some other controller has already assigned a unique ID to the
- * peer.
+ * Callback which will be called when peer start type operation is released
*
- * Creating the peer only creates the handle to manipulate and further
- * configure the peer; use "GNUNET_TESTBED_peer_start" and
- * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
- * processes.
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_peer_start (void *cls)
+{
+ struct OperationContext *opc = cls;
+
+ if (OPC_STATE_FINISHED != opc->state)
+ {
+ GNUNET_free (opc->data);
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ }
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Function called when a peer stop operation is ready
*
- * Note that the given configuration will be adjusted by the
- * controller to avoid port/path conflicts with other peers.
- * The "final" configuration can be obtained using
- * 'GNUNET_TESTBED_peer_get_information'.
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_peer_stop (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct GNUNET_TESTBED_PeerStopMessage *msg;
+ struct PeerEventData *data;
+ struct GNUNET_TESTBED_Peer *peer;
+
+ GNUNET_assert (NULL != opc->data);
+ data = opc->data;
+ GNUNET_assert (NULL != data->peer);
+ peer = data->peer;
+ GNUNET_assert (PS_STARTED == peer->state);
+ opc->state = OPC_STATE_STARTED;
+ msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerStopMessage));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER);
+ msg->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerStopMessage));
+ msg->peer_id = htonl (peer->unique_id);
+ msg->operation_id = GNUNET_htonll (opc->id);
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (peer->controller, &msg->header);
+}
+
+
+/**
+ * Callback which will be called when peer stop type operation is released
*
- * @param unique_id unique ID for this peer
- * @param controller controller process to use
- * @param host host to run the peer on
- * @param cfg configuration to use for the peer
- * @return handle to the peer (actual startup will happen asynchronously)
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_peer_stop (void *cls)
+{
+ struct OperationContext *opc = cls;
+
+ if (OPC_STATE_FINISHED != opc->state)
+ {
+ GNUNET_free (opc->data);
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ }
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Generate PeerGetConfigurationMessage
+ *
+ * @param peer_id the id of the peer whose information we have to get
+ * @param operation_id the ip of the operation that should be represented in the
+ * message
+ * @return the PeerGetConfigurationMessage
+ */
+struct GNUNET_TESTBED_PeerGetConfigurationMessage *
+GNUNET_TESTBED_generate_peergetconfig_msg_ (uint32_t peer_id,
+ uint64_t operation_id)
+{
+ struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
+
+ msg =
+ GNUNET_malloc (sizeof
+ (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
+ msg->header.size =
+ htons (sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION);
+ msg->peer_id = htonl (peer_id);
+ msg->operation_id = GNUNET_htonll (operation_id);
+ return msg;
+}
+
+
+/**
+ * Function called when a peer get information operation is ready
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_peer_getinfo (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct PeerInfoData *data;
+ struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
+
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ opc->state = OPC_STATE_STARTED;
+ msg =
+ GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id,
+ opc->id);
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
+}
+
+
+/**
+ * Callback which will be called when peer stop type operation is released
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_peer_getinfo (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct GNUNET_TESTBED_PeerInformation *data;
+
+ if (OPC_STATE_FINISHED != opc->state)
+ {
+ GNUNET_free_non_null (opc->data);
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ }
+ else
+ {
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ switch (data->pit)
+ {
+ case GNUNET_TESTBED_PIT_CONFIGURATION:
+ GNUNET_CONFIGURATION_destroy (data->result.cfg);
+ break;
+ case GNUNET_TESTBED_PIT_IDENTITY:
+ GNUNET_free (data->result.id);
+ break;
+ default:
+ GNUNET_assert (0); /* We should never reach here */
+ }
+ GNUNET_free (data);
+ }
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Function called when a overlay connect operation is ready
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_overlay_connect (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct GNUNET_TESTBED_OverlayConnectMessage *msg;
+ struct OverlayConnectData *data;
+
+ opc->state = OPC_STATE_STARTED;
+ data = opc->data;
+ GNUNET_assert (NULL != data);
+ data->tslot_index = GNUNET_TESTBED_get_tslot_ (opc->c, data);
+ data->tstart = GNUNET_TIME_absolute_get ();
+ msg = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage));
+ msg->header.size =
+ htons (sizeof (struct GNUNET_TESTBED_OverlayConnectMessage));
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT);
+ msg->peer1 = htonl (data->p1->unique_id);
+ msg->peer2 = htonl (data->p2->unique_id);
+ msg->operation_id = GNUNET_htonll (opc->id);
+ msg->peer2_host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->p2->host));
+ GNUNET_CONTAINER_DLL_insert_tail (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
+}
+
+
+/**
+ * Callback which will be called when overlay connect operation is released
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_overlay_connect (void *cls)
+{
+ struct OperationContext *opc = cls;
+ struct GNUNET_TIME_Relative duration;
+ struct OverlayConnectData *data;
+
+ data = opc->data;
+ switch (opc->state)
+ {
+ case OPC_STATE_INIT:
+ break;
+ case OPC_STATE_STARTED:
+ (void) GNUNET_TESTBED_release_time_slot_ (opc->c, data->tslot_index, data);
+ GNUNET_CONTAINER_DLL_remove (opc->c->ocq_head, opc->c->ocq_tail, opc);
+ break;
+ case OPC_STATE_FINISHED:
+ duration = GNUNET_TIME_absolute_get_duration (data->tstart);
+ GNUNET_TESTBED_update_time_slot_ (opc->c, data->tslot_index, data, duration,
+ data->failed);
+ }
+ GNUNET_free (data);
+ GNUNET_free (opc);
+}
+
+
+/**
+ * Lookup a peer by ID.
+ *
+ * @param id global peer ID assigned to the peer
+ * @return handle to the host, NULL on error
*/
struct GNUNET_TESTBED_Peer *
-GNUNET_TESTBED_peer_create_with_id_ (uint32_t unique_id,
- struct GNUNET_TESTBED_Controller *controller,
- struct GNUNET_TESTBED_Host *host,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
+GNUNET_TESTBED_peer_lookup_by_id_ (uint32_t id)
{
- // FIXME: create locally or delegate...
GNUNET_break (0);
- return NULL;
+ return NULL;
}
@@ -160,70 +422,164 @@ GNUNET_TESTBED_peer_create_with_id_ (uint32_t unique_id,
* 'GNUNET_TESTBED_peer_get_information'.
*
* @param controller controller process to use
- * @param host host to run the peer on
- * @param cfg configuration to use for the peer
- * @return handle to the peer (actual startup will happen asynchronously)
+ * @param host host to run the peer on; cannot be NULL
+ * @param cfg Template configuration to use for the peer. Should exist until
+ * operation is cancelled or GNUNET_TESTBED_operation_done() is called
+ * @param cb the callback to call when the peer has been created
+ * @param cls the closure to the above callback
+ * @return the operation handle
*/
-struct GNUNET_TESTBED_Peer *
+struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_peer_create (struct GNUNET_TESTBED_Controller *controller,
- struct GNUNET_TESTBED_Host *host,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
+ struct GNUNET_TESTBED_Host *host,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_TESTBED_PeerCreateCallback cb, void *cls)
{
+
+ struct GNUNET_TESTBED_Peer *peer;
+ struct PeerCreateData *data;
+ struct OperationContext *opc;
static uint32_t id_gen;
- return GNUNET_TESTBED_peer_create_with_id_ (++id_gen,
- controller,
- host,
- cfg);
+ peer = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer));
+ peer->controller = controller;
+ peer->host = host;
+ peer->unique_id = id_gen++;
+ peer->state = PS_INVALID;
+ data = GNUNET_malloc (sizeof (struct PeerCreateData));
+ data->host = host;
+ data->cfg = cfg;
+ data->cb = cb;
+ data->cls = cls;
+ data->peer = peer;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->c = controller;
+ opc->data = data;
+ opc->id = GNUNET_TESTBED_get_next_op_id (controller);
+ opc->type = OP_PEER_CREATE;
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_create,
+ &oprelease_peer_create);
+ GNUNET_TESTBED_operation_queue_insert_ (controller->opq_parallel_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
}
/**
* Start the given peer.
*
+ * @param op_cls the closure for this operation; will be set in
+ * event->details.operation_finished.op_cls when this operation fails.
* @param peer peer to start
+ * @param pcc function to call upon completion
+ * @param pcc_cls closure for 'pcc'
* @return handle to the operation
*/
struct GNUNET_TESTBED_Operation *
-GNUNET_TESTBED_peer_start (struct GNUNET_TESTBED_Peer *peer)
+GNUNET_TESTBED_peer_start (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
+ GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
{
- // FIXME: start locally or delegate...
- GNUNET_break (0);
- return NULL;
+ struct OperationContext *opc;
+ struct PeerEventData *data;
+
+ data = GNUNET_malloc (sizeof (struct PeerEventData));
+ data->peer = peer;
+ data->pcc = pcc;
+ data->pcc_cls = pcc_cls;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->c = peer->controller;
+ opc->data = data;
+ opc->op_cls = op_cls;
+ opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
+ opc->type = OP_PEER_START;
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_start,
+ &oprelease_peer_start);
+ GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
}
/**
* Stop the given peer. The handle remains valid (use
- * "GNUNET_TESTBED_peer_destroy" to fully clean up the
+ * "GNUNET_TESTBED_peer_destroy" to fully clean up the
* state of the peer).
*
* @param peer peer to stop
+ * @param pcc function to call upon completion
+ * @param pcc_cls closure for 'pcc'
* @return handle to the operation
*/
struct GNUNET_TESTBED_Operation *
-GNUNET_TESTBED_peer_stop (struct GNUNET_TESTBED_Peer *peer)
+GNUNET_TESTBED_peer_stop (struct GNUNET_TESTBED_Peer *peer,
+ GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
{
- // FIXME: stop locally or delegate...
- GNUNET_break (0);
- return NULL;
+ struct OperationContext *opc;
+ struct PeerEventData *data;
+
+ data = GNUNET_malloc (sizeof (struct PeerEventData));
+ data->peer = peer;
+ data->pcc = pcc;
+ data->pcc_cls = pcc_cls;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->c = peer->controller;
+ opc->data = data;
+ opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
+ opc->type = OP_PEER_STOP;
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_stop,
+ &oprelease_peer_stop);
+ GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
}
/**
- * Request information about a peer.
+ * Request information about a peer. The controller callback will not be called
+ * with event type GNUNET_TESTBED_ET_OPERATION_FINISHED when result for this
+ * operation is available. Instead, the GNUNET_TESTBED_PeerInfoCallback() will
+ * be called.
*
* @param peer peer to request information about
* @param pit desired information
+ * @param cb the convenience callback to be called when results for this
+ * operation are available
+ * @param cb_cls the closure for the above callback
* @return handle to the operation
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer,
- enum GNUNET_TESTBED_PeerInformationType pit)
+ enum GNUNET_TESTBED_PeerInformationType
+ pit, GNUNET_TESTBED_PeerInfoCallback cb,
+ void *cb_cls)
{
- // FIXME: handle locally or delegate...
- GNUNET_break (0);
- return NULL;
+ struct OperationContext *opc;
+ struct PeerInfoData *data;
+
+ GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC != pit);
+ data = GNUNET_malloc (sizeof (struct PeerInfoData));
+ data->peer = peer;
+ data->pit = pit;
+ data->cb = cb;
+ data->cb_cls = cb_cls;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->c = peer->controller;
+ opc->data = data;
+ opc->type = OP_PEER_INFO;
+ opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_getinfo,
+ &oprelease_peer_getinfo);
+ GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
}
@@ -239,7 +595,8 @@ GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer,
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
+ const struct
+ GNUNET_CONFIGURATION_Handle *cfg)
{
// FIXME: handle locally or delegate...
GNUNET_break (0);
@@ -248,8 +605,35 @@ GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer,
/**
+ * Destroy the given peer; the peer should have been
+ * stopped first (if it was started).
+ *
+ * @param peer peer to stop
+ * @return handle to the operation
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_peer_destroy (struct GNUNET_TESTBED_Peer *peer)
+{
+ struct OperationContext *opc;
+
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->data = peer;
+ opc->c = peer->controller;
+ opc->id = GNUNET_TESTBED_get_next_op_id (peer->controller);
+ opc->type = OP_PEER_DESTROY;
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_destroy,
+ &oprelease_peer_destroy);
+ GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
+}
+
+
+/**
* Manipulate the P2P underlay topology by configuring a link
- * between two peers.
+ * between two peers.
*
* @param op_cls closure argument to give with the operation event
* @param p1 first peer
@@ -261,22 +645,24 @@ GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer,
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_underlay_configure_link (void *op_cls,
- struct GNUNET_TESTBED_Peer *p1,
- struct GNUNET_TESTBED_Peer *p2,
- enum GNUNET_TESTBED_ConnectOption co, ...)
+ struct GNUNET_TESTBED_Peer *p1,
+ struct GNUNET_TESTBED_Peer *p2,
+ enum GNUNET_TESTBED_ConnectOption co,
+ ...)
{
GNUNET_break (0);
return NULL;
}
-
/**
* Both peers must have been started before calling this function.
* This function then obtains a HELLO from 'p1', gives it to 'p2'
* and asks 'p2' to connect to 'p1'.
*
* @param op_cls closure argument to give with the operation event
+ * @param cb the callback to call when this operation has finished
+ * @param cb_cls the closure for the above callback
* @param p1 first peer
* @param p2 second peer
* @return handle to the operation, NULL if connecting these two
@@ -285,11 +671,33 @@ GNUNET_TESTBED_underlay_configure_link (void *op_cls,
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_overlay_connect (void *op_cls,
- struct GNUNET_TESTBED_Peer *p1,
- struct GNUNET_TESTBED_Peer *p2)
+ GNUNET_TESTBED_OperationCompletionCallback cb,
+ void *cb_cls, struct GNUNET_TESTBED_Peer *p1,
+ struct GNUNET_TESTBED_Peer *p2)
{
- GNUNET_break (0);
- return NULL;
+ struct OperationContext *opc;
+ struct OverlayConnectData *data;
+
+ GNUNET_assert ((PS_STARTED == p1->state) && (PS_STARTED == p2->state));
+ data = GNUNET_malloc (sizeof (struct OverlayConnectData));
+ data->p1 = p1;
+ data->p2 = p2;
+ data->cb = cb;
+ data->cb_cls = cb_cls;
+ opc = GNUNET_malloc (sizeof (struct OperationContext));
+ opc->data = data;
+ opc->c = p1->controller;
+ opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
+ opc->type = OP_OVERLAY_CONNECT;
+ opc->op_cls = op_cls;
+ opc->op =
+ GNUNET_TESTBED_operation_create_ (opc, &opstart_overlay_connect,
+ &oprelease_overlay_connect);
+ GNUNET_TESTBED_operation_queue_insert_ (opc->
+ c->opq_parallel_overlay_connect_operations,
+ opc->op);
+ GNUNET_TESTBED_operation_begin_wait_ (opc->op);
+ return opc->op;
}
diff --git a/src/testbed/testbed_api_peers.h b/src/testbed/testbed_api_peers.h
index ea42c98..8598cc1 100644
--- a/src/testbed/testbed_api_peers.h
+++ b/src/testbed/testbed_api_peers.h
@@ -22,7 +22,9 @@
* @file testbed/testbed_api_peers.h
* @brief internal API to access the 'peers' subsystem
* @author Christian Grothoff
+ * @author Sree Harsha Totakura
*/
+
#ifndef NEW_TESTING_API_PEERS_H
#define NEW_TESTING_API_PEERS_H
@@ -31,41 +33,220 @@
/**
- * Create the given peer at the specified host using the given
- * controller. If the given controller is not running on the target
- * host, it should find or create a controller at the target host and
- * delegate creating the peer. Explicit delegation paths can be setup
- * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation
- * path exists, a direct link with a subordinate controller is setup
- * for the first delegated peer to a particular host; the subordinate
- * controller is then destroyed once the last peer that was delegated
- * to the remote host is stopped. This function is used in particular
- * if some other controller has already assigned a unique ID to the
- * peer.
- *
- * Creating the peer only creates the handle to manipulate and further
- * configure the peer; use "GNUNET_TESTBED_peer_start" and
- * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
- * processes.
- *
- * Note that the given configuration will be adjusted by the
- * controller to avoid port/path conflicts with other peers.
- * The "final" configuration can be obtained using
- * 'GNUNET_TESTBED_peer_get_information'.
- *
- * @param unique_id unique ID for this peer
- * @param controller controller process to use
- * @param host host to run the peer on
- * @param cfg configuration to use for the peer
- * @return handle to the peer (actual startup will happen asynchronously)
+ * Enumeration of possible states a peer could be in
+ */
+enum PeerState
+{
+ /**
+ * State to signify that this peer is invalid
+ */
+ PS_INVALID,
+
+ /**
+ * The peer has been created
+ */
+ PS_CREATED,
+
+ /**
+ * The peer is running
+ */
+ PS_STARTED,
+
+ /**
+ * The peer is stopped
+ */
+ PS_STOPPED,
+};
+
+
+/**
+ * A peer controlled by the testing framework. A peer runs
+ * at a particular host.
+ */
+struct GNUNET_TESTBED_Peer
+{
+ /**
+ * Our controller context (not necessarily the controller
+ * that is responsible for starting/running the peer!).
+ */
+ struct GNUNET_TESTBED_Controller *controller;
+
+ /**
+ * Which host does this peer run on?
+ */
+ struct GNUNET_TESTBED_Host *host;
+
+ /**
+ * Globally unique ID of the peer.
+ */
+ uint32_t unique_id;
+
+ /**
+ * Peer's state
+ */
+ enum PeerState state;
+};
+
+
+/**
+ * Data for the OperationType OP_PEER_CREATE
+ */
+struct PeerCreateData
+{
+ /**
+ * The host where the peer has to be created
+ */
+ struct GNUNET_TESTBED_Host *host;
+
+ /**
+ * The template configuration of the peer
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * The call back to call when we receive peer create success message
+ */
+ GNUNET_TESTBED_PeerCreateCallback cb;
+
+ /**
+ * The closure for the above callback
+ */
+ void *cls;
+
+ /**
+ * The peer structure to return when we get success message
+ */
+ struct GNUNET_TESTBED_Peer *peer;
+
+};
+
+
+/**
+ * Data for OperationType OP_PEER_START and OP_PEER_STOP
+ */
+struct PeerEventData
+{
+ /**
+ * The handle of the peer to start
+ */
+ struct GNUNET_TESTBED_Peer *peer;
+
+ /**
+ * The Peer churn callback to call when this operation is completed
+ */
+ GNUNET_TESTBED_PeerChurnCallback pcc;
+
+ /**
+ * Closure for the above callback
+ */
+ void *pcc_cls;
+
+};
+
+
+/**
+ * Data for the OperationType OP_PEER_DESTROY;
*/
-struct GNUNET_TESTBED_Peer *
-GNUNET_TESTBED_peer_create_with_id_ (uint32_t unique_id,
- struct GNUNET_TESTBED_Controller *controller,
- struct GNUNET_TESTBED_Host *host,
- const struct GNUNET_CONFIGURATION_Handle *cfg);
+struct PeerDestroyData
+{
+ /**
+ * The peer structure
+ */
+ struct GNUNET_TESTBED_Peer *peer;
+
+ //PEERDESTROYDATA
+};
+/**
+ * Data for the OperationType OP_PEER_INFO
+ */
+struct PeerInfoData
+{
+ /**
+ * The peer whose information has been requested
+ */
+ struct GNUNET_TESTBED_Peer *peer;
+
+ /**
+ * The Peer info callback to call when this operation has completed
+ */
+ GNUNET_TESTBED_PeerInfoCallback cb;
+
+ /**
+ * The closure for peer info callback
+ */
+ void *cb_cls;
+
+ /**
+ * The type of peer information requested
+ */
+ enum GNUNET_TESTBED_PeerInformationType pit;
+};
+
+
+/**
+ * Data structure for OperationType OP_OVERLAY_CONNECT
+ */
+struct OverlayConnectData
+{
+
+ /**
+ * Peer A to connect to peer B
+ */
+ struct GNUNET_TESTBED_Peer *p1;
+
+ /**
+ * Peer B
+ */
+ struct GNUNET_TESTBED_Peer *p2;
+
+ /**
+ * The operation completion callback to call once this operation is done
+ */
+ GNUNET_TESTBED_OperationCompletionCallback cb;
+
+ /**
+ * The closure for the above callback
+ */
+ void *cb_cls;
+
+ /**
+ * OperationContext for forwarded operations generated when peer1's controller doesn't have the
+ * configuration of peer2's controller for linking laterally to attemp an
+ * overlay connection between peer 1 and peer 2.
+ */
+ struct OperationContext *sub_opc;
+
+ /**
+ * The starting time of this operation
+ */
+ struct GNUNET_TIME_Absolute tstart;
+
+ /**
+ * Has this operation failed
+ */
+ int failed;
+
+ /**
+ * The timing slot index for this operation
+ */
+ unsigned int tslot_index;
+
+};
+
+
+/**
+ * Generate PeerGetConfigurationMessage
+ *
+ * @param peer_id the id of the peer whose information we have to get
+ * @param operation_id the ip of the operation that should be represented in
+ * the message
+ * @return the PeerGetConfigurationMessage
+ */
+struct GNUNET_TESTBED_PeerGetConfigurationMessage *
+GNUNET_TESTBED_generate_peergetconfig_msg_ (uint32_t peer_id,
+ uint64_t operation_id);
#endif
/* end of testbed_api_peers.h */
diff --git a/src/testbed/testbed_api_services.c b/src/testbed/testbed_api_services.c
index 34de0fd..923caed 100644
--- a/src/testbed/testbed_api_services.c
+++ b/src/testbed/testbed_api_services.c
@@ -24,7 +24,211 @@
* @author Christian Grothoff
*/
#include "platform.h"
+#include "testbed_api.h"
#include "testbed_api_peers.h"
+#include "testbed_api_operations.h"
+
+
+/**
+ * States for Service connect operations
+ */
+enum State
+{
+ /**
+ * Initial state
+ */
+ INIT,
+
+ /**
+ * The configuration request has been sent
+ */
+ CFG_REQUEST_QUEUED,
+
+ /**
+ * connected to service
+ */
+ SERVICE_CONNECTED
+};
+
+
+/**
+ * Data accessed during service connections
+ */
+struct ServiceConnectData
+{
+ /**
+ * helper function callback to establish the connection
+ */
+ GNUNET_TESTBED_ConnectAdapter ca;
+
+ /**
+ * helper function callback to close the connection
+ */
+ GNUNET_TESTBED_DisconnectAdapter da;
+
+ /**
+ * Closure to the above callbacks
+ */
+ void *cada_cls;
+
+ /**
+ * Service name
+ */
+ char *service_name;
+
+ /**
+ * Closure for operation event
+ */
+ void *op_cls;
+
+ /**
+ * The operation which created this structure
+ */
+ struct GNUNET_TESTBED_Operation *operation;
+
+ /**
+ * The operation context from GNUNET_TESTBED_forward_operation_msg_()
+ */
+ struct OperationContext *opc;
+
+ /**
+ * The peer handle
+ */
+ struct GNUNET_TESTBED_Peer *peer;
+
+ /**
+ * The acquired configuration of the peer
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * The op_result pointer from ConnectAdapter
+ */
+ void *op_result;
+
+ /**
+ * The operation completion callback
+ */
+ GNUNET_TESTBED_ServiceConnectCompletionCallback cb;
+
+ /**
+ * The closure for operation completion callback
+ */
+ void *cb_cls;
+
+ /**
+ * State information
+ */
+ enum State state;
+
+};
+
+
+/**
+ * Type of a function to call when we receive a message
+ * from the service.
+ *
+ * @param cls ServiceConnectData
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+configuration_receiver (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct ServiceConnectData *data = cls;
+ struct GNUNET_TESTBED_Controller *c;
+ const char *emsg;
+ struct GNUNET_TESTBED_EventInformation info;
+ uint16_t mtype;
+
+ c = data->peer->controller;
+ mtype = ntohs (msg->type);
+ emsg = NULL;
+ info.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
+ info.details.operation_finished.operation = data->operation;
+ info.details.operation_finished.op_cls = data->op_cls;
+ if (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT == mtype)
+ {
+ emsg =
+ GNUNET_TESTBED_parse_error_string_ ((const struct
+ GNUNET_TESTBED_OperationFailureEventMessage
+ *) msg);
+ if (NULL == emsg)
+ emsg = "Unknown error";
+ info.details.operation_finished.emsg = emsg;
+ info.details.operation_finished.generic = NULL;
+ goto call_cb;
+ }
+ data->cfg = GNUNET_TESTBED_extract_config_ (msg);
+ GNUNET_assert (NULL == data->op_result);
+ data->op_result = data->ca (data->cada_cls, data->cfg);
+ info.details.operation_finished.emsg = NULL;
+ info.details.operation_finished.generic = data->op_result;
+ data->state = SERVICE_CONNECTED;
+
+call_cb:
+ if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
+ (NULL != c->cc))
+ c->cc (c->cc_cls, &info);
+ if (NULL != data->cb)
+ data->cb (data->cb_cls, data->operation, data->op_result, emsg);
+}
+
+
+/**
+ * Function called when a service connect operation is ready
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+opstart_service_connect (void *cls)
+{
+ struct ServiceConnectData *data = cls;
+ struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
+ struct GNUNET_TESTBED_Controller *c;
+ uint64_t op_id;
+
+ GNUNET_assert (NULL != data);
+ GNUNET_assert (NULL != data->peer);
+ c = data->peer->controller;
+ op_id = GNUNET_TESTBED_get_next_op_id (c);
+ msg =
+ GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id, op_id);
+ data->opc =
+ GNUNET_TESTBED_forward_operation_msg_ (c, op_id, &msg->header,
+ &configuration_receiver, data);
+ GNUNET_free (msg);
+ data->state = CFG_REQUEST_QUEUED;
+}
+
+
+/**
+ * Callback which will be called when service connect type operation is
+ * released
+ *
+ * @param cls the closure from GNUNET_TESTBED_operation_create_()
+ */
+static void
+oprelease_service_connect (void *cls)
+{
+ struct ServiceConnectData *data = cls;
+
+ switch (data->state)
+ {
+ case INIT:
+ break;
+ case CFG_REQUEST_QUEUED:
+ GNUNET_assert (NULL != data->opc);
+ GNUNET_TESTBED_forward_operation_msg_cancel_ (data->opc);
+ break;
+ case SERVICE_CONNECTED:
+ GNUNET_assert (NULL != data->cfg);
+ GNUNET_CONFIGURATION_destroy (data->cfg);
+ if (NULL != data->da)
+ data->da (data->cada_cls, data->op_result);
+ break;
+ }
+ GNUNET_free (data);
+}
/**
@@ -33,7 +237,7 @@
* maintain connections with other systems. The actual service
* handle is then returned via the 'op_result' member in the event
* callback. The 'ca' callback is used to create the connection
- * when the time is right; the 'da' callback will be used to
+ * when the time is right; the 'da' callback will be used to
* destroy the connection (upon 'GNUNET_TESTBED_operation_done').
* 'GNUNET_TESTBED_operation_cancel' can be used to abort this
* operation until the event callback has been called.
@@ -41,21 +245,44 @@
* @param op_cls closure to pass in operation event
* @param peer peer that runs the service
* @param service_name name of the service to connect to
+ * @param cb the callback to call when this operation finishes
+ * @param cb_cls closure for the above callback
* @param ca helper function to establish the connection
* @param da helper function to close the connection
* @param cada_cls closure for ca and da
* @return handle for the operation
*/
struct GNUNET_TESTBED_Operation *
-GNUNET_TESTBED_service_connect (void *op_cls,
- struct GNUNET_TESTBED_Peer *peer,
- const char *service_name,
- GNUNET_TESTBED_ConnectAdapter ca,
- GNUNET_TESTBED_DisconnectAdapter da,
- void *cada_cls)
+GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
+ const char *service_name,
+ GNUNET_TESTBED_ServiceConnectCompletionCallback
+ cb, void *cb_cls,
+ GNUNET_TESTBED_ConnectAdapter ca,
+ GNUNET_TESTBED_DisconnectAdapter da,
+ void *cada_cls)
{
- GNUNET_break (0);
- return NULL;
+ struct ServiceConnectData *data;
+
+ data = GNUNET_malloc (sizeof (struct ServiceConnectData));
+ data->ca = ca;
+ data->da = da;
+ data->cada_cls = cada_cls;
+ data->op_cls = op_cls;
+ data->peer = peer;
+ data->state = INIT;
+ data->cb = cb;
+ data->cb_cls = cb_cls;
+ data->operation =
+ GNUNET_TESTBED_operation_create_ (data, &opstart_service_connect,
+ &oprelease_service_connect);
+ GNUNET_TESTBED_operation_queue_insert_ (peer->
+ controller->opq_parallel_service_connections,
+ data->operation);
+ GNUNET_TESTBED_operation_queue_insert_ (peer->
+ controller->opq_parallel_operations,
+ data->operation);
+ GNUNET_TESTBED_operation_begin_wait_ (data->operation);
+ return data->operation;
}
/* end of testbed_api_services.c */
diff --git a/src/testbed/testbed_api_statistics.c b/src/testbed/testbed_api_statistics.c
new file mode 100644
index 0000000..f013c03
--- /dev/null
+++ b/src/testbed/testbed_api_statistics.c
@@ -0,0 +1,56 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/testbed_api_statistics.c
+ * @brief high-level statistics function
+ * @author Christian Grothoff
+ * @author Sree Harsha Totakura
+ */
+#include "platform.h"
+#include "gnunet_testbed_service.h"
+
+
+/**
+ * Convenience method that iterates over all (running) peers
+ * and retrieves all statistics from each peer.
+ *
+ * @param num_peers number of peers to iterate over
+ * @param peers array of peers to iterate over
+ * @param proc processing function for each statistic retrieved
+ * @param cont continuation to call once call is completed(?)
+ * @param cls closure to pass to proc and cont
+ * @return operation handle to cancel the operation
+ */
+struct GNUNET_TESTBED_Operation *
+GNUNET_TESTBED_get_statistics (unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers,
+ GNUNET_TESTBED_StatisticsIterator proc,
+ GNUNET_TESTBED_OperationCompletionCallback cont,
+ void *cls)
+{
+ // FIXME: not implemented, but clients will kind-of work if we do this:
+ GNUNET_break (0);
+ cont (cls, NULL, "not implemented");
+ return NULL;
+}
+
+
+/* end of testbed_api_statistics.c */
diff --git a/src/testbed/testbed_api_test.c b/src/testbed/testbed_api_test.c
index 38e189b..af91cec 100644
--- a/src/testbed/testbed_api_test.c
+++ b/src/testbed/testbed_api_test.c
@@ -22,11 +22,66 @@
* @file testbed/testbed_api_test.c
* @brief high-level test function
* @author Christian Grothoff
+ * @author Sree Harsha Totakura
*/
#include "platform.h"
#include "gnunet_testbed_service.h"
+/**
+ * Context information for test run
+ */
+struct TestRunContext
+{
+ /**
+ * Test master callback
+ */
+ GNUNET_TESTBED_TestMaster test_master;
+
+ /**
+ * Closure for test master
+ */
+ void *test_master_cls;
+
+ /**
+ * The controller event callback
+ */
+ GNUNET_TESTBED_ControllerCallback cc;
+
+ /**
+ * Closure for the above callback
+ */
+ void *cc_cls;
+
+ /**
+ * event mask for the controller callback
+ */
+ uint64_t event_mask;
+
+ /**
+ * Number of peers to start
+ */
+ unsigned int num_peers;
+};
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param config the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ struct TestRunContext *rc = cls;
+
+ GNUNET_TESTBED_run (NULL, config, rc->num_peers, rc->event_mask, rc->cc,
+ rc->cc_cls, rc->test_master, rc->test_master_cls);
+}
/**
@@ -49,19 +104,57 @@
* @param cfg_filename configuration filename to use
* (for testbed, controller and peers)
* @param num_peers number of peers to start
+ * @param event_mask bit mask with set of events to call 'cc' for;
+ * or-ed values of "1LL" shifted by the
+ * respective 'enum GNUNET_TESTBED_EventType'
+ * (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
+ * @param cc controller callback to invoke on events; This callback is called
+ * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
+ * set in the event_mask as this is the only way get access to the
+ * handle of each peer
+ * @param cc_cls closure for cc
* @param test_master task to run once the test is ready
* @param test_master_cls closure for 'task'.
+ * @return GNUNET_SYSERR on error, GNUNET_OK on success
*/
-void
-GNUNET_TESTBED_test_run (const char *testname,
- const char *cfg_filename,
- unsigned int num_peers,
- GNUNET_TESTBED_TestMaster test_master,
- void *test_master_cls)
+int
+GNUNET_TESTBED_test_run (const char *testname, const char *cfg_filename,
+ unsigned int num_peers, uint64_t event_mask,
+ GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
+ GNUNET_TESTBED_TestMaster test_master,
+ void *test_master_cls)
{
- GNUNET_break (0);
-}
-
+ char *argv2[] = {
+ NULL,
+ "-c",
+ NULL,
+ NULL
+ };
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ struct TestRunContext *rc;
+ int ret;
+ argv2[0] = GNUNET_strdup (testname);
+ argv2[2] = GNUNET_strdup (cfg_filename);
+ GNUNET_assert (NULL != test_master);
+ GNUNET_assert (num_peers > 0);
+ rc = GNUNET_malloc (sizeof (struct TestRunContext) +
+ (num_peers * sizeof (struct GNUNET_TESTBED_Peer *)));
+ rc->test_master = test_master;
+ rc->test_master_cls = test_master_cls;
+ rc->num_peers = num_peers;
+ rc->event_mask = event_mask;
+ rc->cc = cc;
+ rc->cc_cls = cc_cls;
+ ret =
+ GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
+ testname, "nohelp", options, &run, rc);
+ GNUNET_free (rc);
+ GNUNET_free (argv2[0]);
+ GNUNET_free (argv2[2]);
+ return ret;
+}
/* end of testbed_api_test.c */
diff --git a/src/testbed/testbed_api_testbed.c b/src/testbed/testbed_api_testbed.c
index 6311806..1c9363c 100644
--- a/src/testbed/testbed_api_testbed.c
+++ b/src/testbed/testbed_api_testbed.c
@@ -1,115 +1,1016 @@
/*
- This file is part of GNUnet
- (C) 2008--2012 Christian Grothoff (and other contributing authors)
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, or (at your
- option) any later version.
+ 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 3, 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.
+ 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.
- */
+ 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 testbed/testbed_api_testbed.c
* @brief high-level testbed management
* @author Christian Grothoff
+ * @author Sree Harsha Totakura
*/
+
#include "platform.h"
+#include "gnunet_util_lib.h"
#include "gnunet_testbed_service.h"
+#include "testbed_api_peers.h"
+#include "testbed_api_hosts.h"
+#include "testbed_api_topology.h"
+
+/**
+ * Generic loggins shorthand
+ */
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
+
+/**
+ * Debug logging shortcut
+ */
+#define DEBUG(...) \
+ LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
+
+/**
+ * DLL of operations
+ */
+struct DLLOperation
+{
+ /**
+ * The testbed operation handle
+ */
+ struct GNUNET_TESTBED_Operation *op;
+
+ /**
+ * Context information for GNUNET_TESTBED_run()
+ */
+ struct RunContext *rc;
+
+ /**
+ * Closure
+ */
+ void *cls;
+
+ /**
+ * The next pointer for DLL
+ */
+ struct DLLOperation *next;
+
+ /**
+ * The prev pointer for DLL
+ */
+ struct DLLOperation *prev;
+};
/**
- * Opaque handle to an abstract operation to be executed by the testing framework.
+ * States of RunContext
*/
-struct GNUNET_TESTBED_Testbed
+enum State
{
- // FIXME!
+ /**
+ * Initial state
+ */
+ RC_INIT = 0,
+
+ /**
+ * Controllers on given hosts started and linked
+ */
+ RC_LINKED,
+
+ /**
+ * Peers are created
+ */
+ RC_PEERS_CREATED,
+
+ /**
+ * The testbed run is ready and the master callback can be called now. At this
+ * time the peers are all started and if a topology is provided in the
+ * configuration the topology would have been attempted
+ */
+ RC_READY,
+
+ /**
+ * Peers are stopped
+ */
+ RC_PEERS_STOPPED,
+
+ /**
+ * Peers are destroyed
+ */
+ RC_PEERS_DESTROYED
};
/**
- * Configure and run a testbed using the given
- * master controller on 'num_hosts' starting
- * 'num_peers' using the given peer configuration.
- *
- * @param controller master controller for the testbed
- * (must not be destroyed until after the
- * testbed is destroyed).
- * @param num_hosts number of hosts in 'hosts', 0 to only
- * use 'localhost'
- * @param hosts list of hosts to use for the testbed
- * @param num_peers number of peers to start
- * @param peer_cfg peer configuration template to use
- * @param underlay_topology underlay topology to create
- * @param va topology-specific options
- * @return handle to the testbed
- */
-struct GNUNET_TESTBED_Testbed *
-GNUNET_TESTBED_create_va (struct GNUNET_TESTBED_Controller *controller,
- unsigned int num_hosts,
- struct GNUNET_TESTBED_Host **hosts,
- unsigned int num_peers,
- const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
- enum GNUNET_TESTBED_TopologyOption underlay_topology,
- va_list va)
-{
- GNUNET_break (0);
- return NULL;
+ * Testbed Run Handle
+ */
+struct RunContext
+{
+ /**
+ * The controller handle
+ */
+ struct GNUNET_TESTBED_Controller *c;
+
+ /**
+ * The configuration of the controller. This is based on the cfg given to the
+ * function GNUNET_TESTBED_run(). We also use this config as a template while
+ * for peers
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Handle to the host on which the controller runs
+ */
+ struct GNUNET_TESTBED_Host *h;
+
+ /**
+ * The handle to the controller process
+ */
+ struct GNUNET_TESTBED_ControllerProc *cproc;
+
+ /**
+ * The callback to use as controller callback
+ */
+ GNUNET_TESTBED_ControllerCallback cc;
+
+ /**
+ * The pointer to the controller callback
+ */
+ void *cc_cls;
+
+ /**
+ * The trusted IP string
+ */
+ char *trusted_ip;
+
+ /**
+ * TestMaster callback to call when testbed initialization is done
+ */
+ GNUNET_TESTBED_TestMaster test_master;
+
+ /**
+ * The closure for the TestMaster callback
+ */
+ void *test_master_cls;
+
+ /**
+ * The head element of DLL operations
+ */
+ struct DLLOperation *dll_op_head;
+
+ /**
+ * The tail element of DLL operations
+ */
+ struct DLLOperation *dll_op_tail;
+
+ /**
+ * An array of hosts loaded from the hostkeys file
+ */
+ struct GNUNET_TESTBED_Host **hosts;
+
+ /**
+ * The handle for whether a host is habitable or not
+ */
+ struct GNUNET_TESTBED_HostHabitableCheckHandle **hc_handles;
+
+ /**
+ * Array of peers which we create
+ */
+ struct GNUNET_TESTBED_Peer **peers;
+
+ /**
+ * The topology generation operation. Will be null if no topology is set in
+ * the configuration
+ */
+ struct GNUNET_TESTBED_Operation *topology_operation;
+
+ /**
+ * The file containing topology data. Only used if the topology is set to 'FROM_FILE'
+ */
+ char *topo_file;
+
+ /**
+ * Host registration handle
+ */
+ struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
+
+ /**
+ * Profiling start time
+ */
+ struct GNUNET_TIME_Absolute pstart_time;
+
+ /**
+ * Host registration task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier register_hosts_task;
+
+ /**
+ * Task to be run while shutting down
+ */
+ GNUNET_SCHEDULER_TaskIdentifier shutdown_run_task;
+
+ /**
+ * The event mask for the controller
+ */
+ uint64_t event_mask;
+
+ /**
+ * State of this context
+ */
+ enum State state;
+
+ /**
+ * The topology which has to be achieved with the peers started in this context
+ */
+ enum GNUNET_TESTBED_TopologyOption topology;
+
+ /**
+ * Have we already shutdown
+ */
+ int shutdown;
+
+ /**
+ * Number of hosts in the given host file
+ */
+ unsigned int num_hosts;
+
+ /**
+ * Number of registered hosts. Also used as a counter while checking
+ * habitabillity of hosts
+ */
+ unsigned int reg_hosts;
+
+ /**
+ * Current peer count for an operation; Set this to 0 and increment for each
+ * successful operation on a peer
+ */
+ unsigned int peer_count;
+
+ /**
+ * number of peers to start
+ */
+ unsigned int num_peers;
+
+ /**
+ * counter to count overlay connect attempts. This counter includes both
+ * successful and failed overlay connects
+ */
+ unsigned int oc_count;
+
+ /**
+ * Expected overlay connects. Should be zero if no topology is relavant
+ */
+ unsigned int num_oc;
+
+ /**
+ * Number of random links to established
+ */
+ unsigned int random_links;
+
+};
+
+
+/**
+ * Function to return the string representation of the duration between current
+ * time and `pstart_time' in `RunContext'
+ *
+ * @param rc the RunContext
+ * @return the representation string; this is NOT reentrant
+ */
+static const char *
+prof_time (struct RunContext *rc)
+{
+ struct GNUNET_TIME_Relative ptime;
+
+ ptime = GNUNET_TIME_absolute_get_duration (rc->pstart_time);
+ return GNUNET_STRINGS_relative_time_to_string (ptime, GNUNET_YES);
+}
+
+
+/**
+ * Task for starting peers
+ *
+ * @param cls the RunHandle
+ * @param tc the task context from scheduler
+ */
+static void
+start_peers_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RunContext *rc = cls;
+ struct DLLOperation *dll_op;
+ unsigned int peer;
+
+ DEBUG ("Starting Peers\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ for (peer = 0; peer < rc->num_peers; peer++)
+ {
+ dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+ dll_op->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
+ dll_op->cls = rc->peers[peer];
+ GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
+ }
+ rc->peer_count = 0;
}
/**
- * Configure and run a testbed using the given
- * master controller on 'num_hosts' starting
- * 'num_peers' using the given peer configuration.
- *
- * @param controller master controller for the testbed
- * (must not be destroyed until after the
- * testbed is destroyed).
- * @param num_hosts number of hosts in 'hosts', 0 to only
- * use 'localhost'
- * @param hosts list of hosts to use for the testbed
- * @param num_peers number of peers to start
- * @param peer_cfg peer configuration template to use
- * @param underlay_topology underlay topology to create
- * @param ... topology-specific options
- */
-struct GNUNET_TESTBED_Testbed *
-GNUNET_TESTBED_create (struct GNUNET_TESTBED_Controller *controller,
- unsigned int num_hosts,
- struct GNUNET_TESTBED_Host **hosts,
- unsigned int num_peers,
- const struct GNUNET_CONFIGURATION_Handle *peer_cfg,
- enum GNUNET_TESTBED_TopologyOption underlay_topology,
- ...)
-{
- GNUNET_break (0);
- return NULL;
+ * Functions of this signature are called when a peer has been successfully
+ * created
+ *
+ * @param cls the closure from GNUNET_TESTBED_peer_create()
+ * @param peer the handle for the created peer; NULL on any error during
+ * creation
+ * @param emsg NULL if peer is not NULL; else MAY contain the error description
+ */
+static void
+peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
+{
+ struct DLLOperation *dll_op = cls;
+ struct RunContext *rc;
+
+ GNUNET_assert (NULL != dll_op);
+ rc = dll_op->rc;
+ GNUNET_assert (NULL != rc);
+ GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
+ GNUNET_TESTBED_operation_done (dll_op->op);
+ GNUNET_free (dll_op);
+ if (NULL == peer)
+ {
+ if (NULL != emsg)
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Error while creating a peer: %s\n",
+ emsg);
+ /* FIXME: GNUNET_TESTBED_shutdown_run()? */
+ return;
+ }
+ rc->peers[rc->peer_count] = peer;
+ rc->peer_count++;
+ if (rc->peer_count < rc->num_peers)
+ return;
+ DEBUG ("%u peers created in %s\n", rc->num_peers, prof_time (rc));
+ rc->state = RC_PEERS_CREATED;
+ GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
}
/**
- * Destroy a testbed. Stops all running peers and then
- * destroys all peers. Does NOT destroy the master controller.
+ * Assuming all peers have been destroyed cleanup run handle
*
- * @param testbed testbed to destroy
+ * @param cls the run handle
+ * @param tc the task context from scheduler
*/
-void
-GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
+static void
+cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RunContext *rc = cls;
+ struct DLLOperation *dll_op;
+ unsigned int hid;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rc->register_hosts_task);
+ GNUNET_assert (NULL == rc->reg_handle);
+ GNUNET_assert (NULL == rc->peers);
+ GNUNET_assert (NULL == rc->hc_handles);
+ GNUNET_assert (RC_PEERS_DESTROYED == rc->state);
+ if (NULL != rc->dll_op_head)
+ { /* cancel our pending operations */
+ while (NULL != (dll_op = rc->dll_op_head))
+ {
+ GNUNET_TESTBED_operation_done (dll_op->op);
+ GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
+ GNUNET_free (dll_op);
+ }
+ }
+ if (NULL != rc->c)
+ GNUNET_TESTBED_controller_disconnect (rc->c);
+ if (NULL != rc->cproc)
+ GNUNET_TESTBED_controller_stop (rc->cproc);
+ if (NULL != rc->h)
+ GNUNET_TESTBED_host_destroy (rc->h);
+ for (hid = 0; hid < rc->num_hosts; hid++)
+ GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
+ GNUNET_free_non_null (rc->hosts);
+ if (NULL != rc->cfg)
+ GNUNET_CONFIGURATION_destroy (rc->cfg);
+ GNUNET_free_non_null (rc->topo_file);
+ GNUNET_free_non_null (rc->trusted_ip);
+ GNUNET_free (rc);
+}
+
+
+/**
+ * Stops the testbed run and releases any used resources
+ *
+ * @param cls the tesbed run handle
+ * @param tc the task context from scheduler
+ */
+static void
+shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Function to shutdown now
+ *
+ * @param rc the RunContext
+ */
+static void
+shutdown_now (struct RunContext *rc)
+{
+ if (GNUNET_YES == rc->shutdown)
+ return;
+ if (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task)
+ GNUNET_SCHEDULER_cancel (rc->shutdown_run_task);
+ rc->shutdown_run_task = GNUNET_SCHEDULER_add_now (&shutdown_run, rc);
+}
+
+
+/**
+ * Stops the testbed run and releases any used resources
+ *
+ * @param cls the tesbed run handle
+ * @param tc the task context from scheduler
+ */
+static void
+shutdown_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- GNUNET_break (0);
+ struct RunContext *rc = cls;
+ struct DLLOperation *dll_op;
+ int all_peers_destroyed;
+ unsigned int peer;
+ unsigned int nhost;
+
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != rc->shutdown_run_task);
+ rc->shutdown_run_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_assert (GNUNET_NO == rc->shutdown);
+ rc->shutdown = GNUNET_YES;
+ if (NULL != rc->hc_handles)
+ {
+ for (nhost = 0; nhost < rc->num_hosts; nhost++)
+ if (NULL != rc->hc_handles[nhost])
+ GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
+ GNUNET_free (rc->hc_handles);
+ rc->hc_handles = NULL;
+ }
+ /* Stop register hosts task if it is running */
+ if (GNUNET_SCHEDULER_NO_TASK != rc->register_hosts_task)
+ {
+ GNUNET_SCHEDULER_cancel (rc->register_hosts_task);
+ rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != rc->reg_handle)
+ {
+ GNUNET_TESTBED_cancel_registration (rc->reg_handle);
+ rc->reg_handle = NULL;
+ }
+ if (NULL != rc->c)
+ {
+ if (NULL != rc->peers)
+ {
+ if (NULL != rc->topology_operation)
+ {
+ GNUNET_TESTBED_operation_done (rc->topology_operation);
+ rc->topology_operation = NULL;
+ }
+ if (RC_INIT == rc->state)
+ rc->state = RC_READY; /* Even though we haven't called the master callback */
+ rc->peer_count = 0;
+ /* Check if some peers are stopped */
+ for (peer = 0; peer < rc->num_peers; peer++)
+ {
+ if (NULL == rc->peers[peer])
+ continue;
+ if (PS_STOPPED != rc->peers[peer]->state)
+ break;
+ }
+ if (peer == rc->num_peers)
+ {
+ /* All peers are stopped */
+ rc->state = RC_PEERS_STOPPED;
+ all_peers_destroyed = GNUNET_YES;
+ for (peer = 0; peer < rc->num_peers; peer++)
+ {
+ if (NULL == rc->peers[peer])
+ continue;
+ all_peers_destroyed = GNUNET_NO;
+ dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+ dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer]);
+ GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
+ dll_op);
+ }
+ if (all_peers_destroyed == GNUNET_NO)
+ {
+ DEBUG ("Destroying peers\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ return;
+ }
+ }
+ /* Some peers are stopped */
+ DEBUG ("Stopping peers\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ for (peer = 0; peer < rc->num_peers; peer++)
+ {
+ if ((NULL == rc->peers[peer]) || (PS_STARTED != rc->peers[peer]->state))
+ {
+ rc->peer_count++;
+ continue;
+ }
+ dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+ dll_op->op = GNUNET_TESTBED_peer_stop (rc->peers[peer], NULL, NULL);
+ dll_op->cls = rc->peers[peer];
+ GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
+ dll_op);
+ }
+ if (rc->peer_count != rc->num_peers)
+ return;
+ GNUNET_free (rc->peers);
+ rc->peers = NULL;
+ }
+ }
+ rc->state = RC_PEERS_DESTROYED; /* No peers are present so we consider the
+ * state where all peers are destroyed */
+ GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
}
+/**
+ * Task to call master task
+ *
+ * @param cls the run context
+ * @param tc the task context
+ */
+static void
+call_master (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RunContext *rc = cls;
+
+ if (NULL != rc->topology_operation)
+ {
+ DEBUG ("Overlay topology generated in %s\n", prof_time (rc));
+ GNUNET_TESTBED_operation_done (rc->topology_operation);
+ rc->topology_operation = NULL;
+ }
+ if (NULL != rc->test_master)
+ rc->test_master (rc->test_master_cls, rc->num_peers, rc->peers);
+}
+
+
+/**
+ * Function to create peers
+ *
+ * @param rc the RunContext
+ */
+static void
+create_peers (struct RunContext *rc)
+{
+ struct DLLOperation *dll_op;
+ unsigned int peer;
+
+ DEBUG ("Creating peers\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ rc->peers =
+ GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Peer *) * rc->num_peers);
+ GNUNET_assert (NULL != rc->c);
+ rc->peer_count = 0;
+ for (peer = 0; peer < rc->num_peers; peer++)
+ {
+ dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+ dll_op->rc = rc;
+ dll_op->op =
+ GNUNET_TESTBED_peer_create (rc->c,
+ (0 ==
+ rc->num_hosts) ? rc->h : rc->hosts[peer %
+ rc->num_hosts],
+ rc->cfg, peer_create_cb, dll_op);
+ GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail, dll_op);
+ }
+}
+
+
+/**
+ * Signature of the event handler function called by the
+ * respective event controller.
+ *
+ * @param cls closure
+ * @param event information about the event
+ */
+static void
+event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
+{
+ struct RunContext *rc = cls;
+ struct DLLOperation *dll_op;
+ unsigned int peer_id;
+
+ if (RC_INIT == rc->state)
+ {
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+ dll_op = event->details.operation_finished.op_cls;
+ if (NULL != event->details.operation_finished.emsg)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Linking controllers failed. Exiting"));
+ shutdown_now (rc);
+ }
+ else
+ rc->reg_hosts++;
+ GNUNET_assert (event->details.operation_finished.operation == dll_op->op);
+ GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
+ GNUNET_TESTBED_operation_done (dll_op->op);
+ GNUNET_free (dll_op);
+ if (rc->reg_hosts == rc->num_hosts)
+ {
+ rc->state = RC_LINKED;
+ create_peers (rc);
+ }
+ return;
+ default:
+ GNUNET_break (0);
+ shutdown_now (rc);
+ return;
+ }
+ }
+ if (NULL != rc->topology_operation)
+ {
+ switch (event->type)
+ {
+ case GNUNET_TESTBED_ET_OPERATION_FINISHED:
+ case GNUNET_TESTBED_ET_CONNECT:
+ rc->oc_count++;
+ break;
+ default:
+ GNUNET_break (0);
+ shutdown_now (rc);
+ return;
+ }
+ if (rc->oc_count == rc->num_oc)
+ {
+ rc->state = RC_READY;
+ GNUNET_SCHEDULER_add_continuation (&call_master, rc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+ }
+ goto call_cc;
+ }
+ for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
+ {
+ if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
+ (event->details.operation_finished.operation == dll_op->op))
+ break;
+ if ((GNUNET_TESTBED_ET_PEER_STOP == event->type) &&
+ (event->details.peer_stop.peer == dll_op->cls))
+ break;
+ }
+ if (NULL == dll_op)
+ goto call_cc;
+ GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
+ GNUNET_TESTBED_operation_done (dll_op->op);
+ GNUNET_free (dll_op);
+ rc->peer_count++;
+ if (rc->peer_count < rc->num_peers)
+ return;
+ switch (rc->state)
+ {
+ case RC_PEERS_CREATED:
+ case RC_READY:
+ rc->state = RC_PEERS_STOPPED;
+ DEBUG ("Peers stopped in %s\n", prof_time (rc));
+ DEBUG ("Destroying peers\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ rc->peer_count = 0;
+ for (peer_id = 0; peer_id < rc->num_peers; peer_id++)
+ {
+ dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+ dll_op->op = GNUNET_TESTBED_peer_destroy (rc->peers[peer_id]);
+ GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
+ dll_op);
+ }
+ break;
+ case RC_PEERS_STOPPED:
+ rc->state = RC_PEERS_DESTROYED;
+ GNUNET_free (rc->peers);
+ rc->peers = NULL;
+ DEBUG ("Peers destroyed in %s\n", prof_time (rc));
+ GNUNET_SCHEDULER_add_now (&cleanup_task, rc);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ return;
+
+call_cc:
+ if ((0 != (rc->event_mask & (1LL << event->type))) && (NULL != rc->cc))
+ rc->cc (rc->cc_cls, event);
+ if (GNUNET_TESTBED_ET_PEER_START != event->type)
+ return;
+ for (dll_op = rc->dll_op_head; NULL != dll_op; dll_op = dll_op->next)
+ if ((NULL != dll_op->cls) &&
+ (event->details.peer_start.peer == dll_op->cls))
+ break;
+ if (NULL == dll_op) /* Not our operation */
+ return;
+ GNUNET_CONTAINER_DLL_remove (rc->dll_op_head, rc->dll_op_tail, dll_op);
+ GNUNET_TESTBED_operation_done (dll_op->op);
+ GNUNET_free (dll_op);
+ rc->peer_count++;
+ if (rc->peer_count < rc->num_peers)
+ return;
+ DEBUG ("%u peers started in %s\n", rc->num_peers, prof_time (rc));
+ if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
+ {
+ if ((GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI == rc->topology) ||
+ (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING == rc->topology) ||
+ (GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD == rc->topology))
+ {
+ rc->topology_operation =
+ GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
+ rc->peers, &rc->num_oc,
+ NULL,
+ NULL,
+ rc->topology,
+ rc->random_links,
+ GNUNET_TESTBED_TOPOLOGY_OPTION_END);
+ }
+ else if (GNUNET_TESTBED_TOPOLOGY_FROM_FILE == rc->topology)
+ {
+ GNUNET_assert (NULL != rc->topo_file);
+ rc->topology_operation =
+ GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
+ rc->peers, &rc->num_oc,
+ NULL,
+ NULL,
+ rc->topology,
+ rc->topo_file,
+ GNUNET_TESTBED_TOPOLOGY_OPTION_END);
+ }
+ else
+ rc->topology_operation =
+ GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
+ rc->peers, &rc->num_oc,
+ NULL,
+ NULL,
+ rc->topology,
+ GNUNET_TESTBED_TOPOLOGY_OPTION_END);
+ if (NULL == rc->topology_operation)
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Not generating topology. Check number of peers\n");
+ else
+ {
+ DEBUG ("Creating overlay topology\n");
+ rc->pstart_time = GNUNET_TIME_absolute_get ();
+ return;
+ }
+ }
+ rc->state = RC_READY;
+ GNUNET_SCHEDULER_add_continuation (&call_master, rc,
+ GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+}
+
+
+/**
+ * Task to register all hosts available in the global host list
+ *
+ * @param cls the RunContext
+ * @param tc the scheduler task context
+ */
+static void
+register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Callback which will be called to after a host registration succeeded or failed
+ *
+ * @param cls the closure
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+host_registration_completion (void *cls, const char *emsg)
+{
+ struct RunContext *rc = cls;
+
+ rc->reg_handle = NULL;
+ if (NULL != emsg)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Host registration failed for a host. Error: %s\n"), emsg);
+ shutdown_now (rc);
+ return;
+ }
+ rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
+}
+
+
+/**
+ * Task to register all hosts available in the global host list
+ *
+ * @param cls RunContext
+ * @param tc the scheduler task context
+ */
+static void
+register_hosts (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct RunContext *rc = cls;
+ struct DLLOperation *dll_op;
+ unsigned int slave;
+
+ rc->register_hosts_task = GNUNET_SCHEDULER_NO_TASK;
+ if (rc->reg_hosts == rc->num_hosts)
+ {
+ DEBUG ("All hosts successfully registered\n");
+ /* Start slaves */
+ for (slave = 0; slave < rc->num_hosts; slave++)
+ {
+ dll_op = GNUNET_malloc (sizeof (struct DLLOperation));
+ dll_op->rc = rc;
+ dll_op->op =
+ GNUNET_TESTBED_controller_link (dll_op, rc->c, rc->hosts[slave],
+ rc->h, rc->cfg, GNUNET_YES);
+ GNUNET_CONTAINER_DLL_insert_tail (rc->dll_op_head, rc->dll_op_tail,
+ dll_op);
+ }
+ rc->reg_hosts = 0;
+ return;
+ }
+ rc->reg_handle =
+ GNUNET_TESTBED_register_host (rc->c, rc->hosts[rc->reg_hosts],
+ host_registration_completion, rc);
+ rc->reg_hosts++;
+}
+
+
+/**
+ * Callback to signal successfull startup of the controller process
+ *
+ * @param cls the closure from GNUNET_TESTBED_controller_start()
+ * @param cfg the configuration with which the controller has been started;
+ * NULL if status is not GNUNET_OK
+ * @param status GNUNET_OK if the startup is successfull; GNUNET_SYSERR if not,
+ * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
+ */
+static void
+controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
+ int status)
+{
+ struct RunContext *rc = cls;
+ uint64_t event_mask;
+
+ if (status != GNUNET_OK)
+ {
+ switch (rc->state)
+ {
+ case RC_INIT:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Testbed startup failed\n");
+ return;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Controller crash detected. Shutting down.\n");
+ rc->cproc = NULL;
+ shutdown_now (rc);
+ return;
+ }
+ }
+ GNUNET_CONFIGURATION_destroy (rc->cfg);
+ rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ event_mask = rc->event_mask;
+ event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
+ event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
+ event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
+ if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
+ event_mask |= GNUNET_TESTBED_ET_CONNECT;
+ rc->c =
+ GNUNET_TESTBED_controller_connect (rc->cfg, rc->h, event_mask, &event_cb,
+ rc);
+ if (0 < rc->num_hosts)
+ {
+ rc->reg_hosts = 0;
+ rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
+ return;
+ }
+ rc->state = RC_LINKED;
+ create_peers (rc);
+}
+
+
+/**
+ * Callback function invoked for each interface found.
+ *
+ * @param cls closure
+ * @param name name of the interface (can be NULL for unknown)
+ * @param isDefault is this presumably the default interface
+ * @param addr address of this interface (can be NULL for unknown or unassigned)
+ * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
+ * @param netmask the network mask (can be NULL for unknown or unassigned))
+ * @param addrlen length of the address
+ * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
+ */
+static int
+netint_proc (void *cls, const char *name, int isDefault,
+ const struct sockaddr *addr, const struct sockaddr *broadcast_addr,
+ const struct sockaddr *netmask, socklen_t addrlen)
+{
+ struct RunContext *rc = cls;
+ char hostip[NI_MAXHOST];
+ char *buf;
+
+ if (sizeof (struct sockaddr_in) != addrlen)
+ return GNUNET_OK; /* Only consider IPv4 for now */
+ if (0 !=
+ getnameinfo (addr, addrlen, hostip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
+ if (NULL == rc->trusted_ip)
+ {
+ rc->trusted_ip = GNUNET_strdup (hostip);
+ return GNUNET_YES;
+ }
+ (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
+ GNUNET_free (rc->trusted_ip);
+ rc->trusted_ip = buf;
+ return GNUNET_YES;
+}
+
+
+/**
+ * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
+ * inform whether the given host is habitable or not. The Handle returned by
+ * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
+ *
+ * @param cls NULL
+ * @param host the host whose status is being reported; will be NULL if the host
+ * given to GNUNET_TESTBED_is_host_habitable() is NULL
+ * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
+ */
+static void
+host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
+ int status)
+{
+ struct RunContext *rc = cls;
+ struct GNUNET_TESTBED_Host **old_hosts;
+ unsigned int nhost;
+
+ for (nhost = 0; nhost < rc->num_hosts; nhost++)
+ {
+ if (host == rc->hosts[nhost])
+ break;
+ }
+ GNUNET_assert (nhost != rc->num_hosts);
+ rc->hc_handles[nhost] = NULL;
+ if (GNUNET_NO == status)
+ {
+ if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Host %s cannot start testbed\n"),
+ GNUNET_TESTBED_host_get_hostname (host));
+ else
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Testbed cannot be started on localhost\n"));
+ shutdown_now (rc);
+ return;
+ }
+ rc->reg_hosts++;
+ if (rc->reg_hosts < rc->num_hosts)
+ return;
+ GNUNET_free (rc->hc_handles);
+ rc->hc_handles = NULL;
+ rc->h = rc->hosts[0];
+ rc->num_hosts--;
+ if (0 < rc->num_hosts)
+ {
+ old_hosts = rc->hosts;
+ rc->hosts =
+ GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts);
+ memcpy (rc->hosts, &old_hosts[1],
+ (sizeof (struct GNUNET_TESTBED_Host *) * rc->num_hosts));
+ GNUNET_free (old_hosts);
+ }
+ else
+ {
+ GNUNET_free (rc->hosts);
+ rc->hosts = NULL;
+ }
+ GNUNET_OS_network_interfaces_list (netint_proc, rc);
+ if (NULL == rc->trusted_ip)
+ rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
+ rc->cproc =
+ GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h, rc->cfg,
+ &controller_status_cb, rc);
+ GNUNET_free (rc->trusted_ip);
+ rc->trusted_ip = NULL;
+ if (NULL == rc->cproc)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot start the master controller"));
+ shutdown_now (rc);
+ }
+}
+
/**
* Convenience method for running a testbed with
@@ -130,24 +1031,150 @@ GNUNET_TESTBED_destroy (struct GNUNET_TESTBED_Testbed *testbed)
* or-ed values of "1LL" shifted by the
* respective 'enum GNUNET_TESTBED_EventType'
* (i.e. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
- * @param cc controller callback to invoke on events
+ * @param cc controller callback to invoke on events; This callback is called
+ * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
+ * set in the event_mask as this is the only way get access to the
+ * handle of each peer
* @param cc_cls closure for cc
- * @param master task to run once the testbed is ready
- * @param master_cls closure for 'task'.
+ * @param test_master this callback will be called once the test is ready
+ * @param test_master_cls closure for 'test_master'.
*/
void
GNUNET_TESTBED_run (const char *host_filename,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- unsigned int num_peers,
- uint64_t event_mask,
- GNUNET_TESTBED_ControllerCallback cc,
- void *cc_cls,
- GNUNET_SCHEDULER_Task master,
- void *master_cls)
-{
- GNUNET_break (0);
-}
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ unsigned int num_peers, uint64_t event_mask,
+ GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
+ GNUNET_TESTBED_TestMaster test_master,
+ void *test_master_cls)
+{
+ struct RunContext *rc;
+ char *topology;
+ unsigned long long random_links;
+ unsigned int hid;
+ unsigned int nhost;
+ GNUNET_assert (num_peers > 0);
+ rc = GNUNET_malloc (sizeof (struct RunContext));
+ if (NULL != host_filename)
+ {
+ rc->num_hosts =
+ GNUNET_TESTBED_hosts_load_from_file (host_filename, &rc->hosts);
+ if (0 == rc->num_hosts)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("No hosts loaded. Need at least one host\n"));
+ goto error_cleanup;
+ }
+ }
+ else
+ rc->h = GNUNET_TESTBED_host_create (NULL, NULL, 0);
+ rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
+ rc->num_peers = num_peers;
+ rc->event_mask = event_mask;
+ rc->cc = cc;
+ rc->cc_cls = cc_cls;
+ rc->test_master = test_master;
+ rc->test_master_cls = test_master_cls;
+ rc->state = RC_INIT;
+ rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
+ "OVERLAY_TOPOLOGY", &topology))
+ {
+ if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology, topology))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "testbed",
+ "OVERLAY_TOPLOGY",
+ _
+ ("Specified topology must be supported by testbed"));
+ }
+ GNUNET_free (topology);
+ }
+ switch (rc->topology)
+ {
+ case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
+ case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
+ case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (rc->cfg, "testbed",
+ "OVERLAY_RANDOM_LINKS",
+ &random_links))
+ {
+ /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
+ * option to be set to the number of random links to be established */
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
+ "OVERLAY_RANDOM_LINKS");
+ goto error_cleanup;
+ }
+ if (random_links > UINT32_MAX)
+ {
+ GNUNET_break (0); /* Too big number */
+ goto error_cleanup;
+ }
+ rc->random_links = (unsigned int) random_links;
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (rc->cfg, "testbed",
+ "OVERLAY_TOPOLOGY_FILE",
+ &rc->topo_file))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "testbed",
+ "OVERLAY_TOPOLOGY_FILE");
+ goto error_cleanup;
+ }
+ default:
+ /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (rc->cfg, "testbed",
+ "OVERLAY_RANDOM_LINKS"))
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
+ break;
+ }
+ if (NULL != host_filename)
+ {
+ rc->hc_handles =
+ GNUNET_malloc (sizeof (struct GNUNET_TESTBED_HostHabitableCheckHandle *)
+ * rc->num_hosts);
+ for (nhost = 0; nhost < rc->num_hosts; nhost++)
+ {
+ if (NULL ==
+ (rc->hc_handles[nhost] =
+ GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
+ &host_habitable_cb, rc)))
+ {
+ GNUNET_break (0);
+ for (nhost = 0; nhost < rc->num_hosts; nhost++)
+ if (NULL != rc->hc_handles[nhost])
+ GNUNET_TESTBED_is_host_habitable_cancel (rc->hc_handles[nhost]);
+ GNUNET_free (rc->hc_handles);
+ rc->hc_handles = NULL;
+ goto error_cleanup;
+ }
+ }
+ }
+ else
+ rc->cproc =
+ GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h, rc->cfg,
+ &controller_status_cb, rc);
+ rc->shutdown_run_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_run,
+ rc);
+ return;
+
+error_cleanup:
+ if (NULL != rc->h)
+ GNUNET_TESTBED_host_destroy (rc->h);
+ if (NULL != rc->hosts)
+ {
+ for (hid = 0; hid < rc->num_hosts; hid++)
+ if (NULL != rc->hosts[hid])
+ GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
+ GNUNET_free (rc->hosts);
+ }
+ GNUNET_free (rc);
+}
/* end of testbed_api_testbed.c */
diff --git a/src/testbed/testbed_api_topology.c b/src/testbed/testbed_api_topology.c
index c0e9f72..9618f98 100644
--- a/src/testbed/testbed_api_topology.c
+++ b/src/testbed/testbed_api_topology.c
@@ -25,6 +25,768 @@
*/
#include "platform.h"
#include "gnunet_testbed_service.h"
+#include "testbed_api.h"
+#include "testbed_api_peers.h"
+#include "testbed_api_operations.h"
+#include "testbed_api_topology.h"
+
+/**
+ * Generic loggins shorthand
+ */
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "testbed-api-topology", __VA_ARGS__)
+
+
+/**
+ * Default number of retires
+ */
+#define DEFAULT_RETRY_CNT 3
+
+
+/**
+ * Context information for topology operations
+ */
+struct TopologyContext;
+
+
+/**
+ * Representation of an overlay link
+ */
+struct OverlayLink
+{
+
+ /**
+ * An operation corresponding to this link
+ */
+ struct GNUNET_TESTBED_Operation *op;
+
+ /**
+ * The topology context this link is a part of
+ */
+ struct TopologyContext *tc;
+
+ /**
+ * position of peer A's handle in peers array
+ */
+ uint32_t A;
+
+ /**
+ * position of peer B's handle in peers array
+ */
+ uint32_t B;
+
+};
+
+
+struct RetryListEntry
+{
+ /**
+ * the next pointer for the DLL
+ */
+ struct RetryListEntry *next;
+
+ /**
+ * the prev pointer for the DLL
+ */
+ struct RetryListEntry *prev;
+
+ /**
+ * The link to be retired
+ */
+ struct OverlayLink *link;
+};
+
+
+/**
+ * Context information for topology operations
+ */
+struct TopologyContext
+{
+ /**
+ * The array of peers
+ */
+ struct GNUNET_TESTBED_Peer **peers;
+
+ /**
+ * An array of links; this array is of size link_array_size
+ */
+ struct OverlayLink *link_array;
+
+ /**
+ * The operation closure
+ */
+ void *op_cls;
+
+ /**
+ * topology generation completion callback
+ */
+ GNUNET_TESTBED_TopologyCompletionCallback comp_cb;
+
+ /**
+ * The closure for the above callback
+ */
+ void *comp_cb_cls;
+
+ /**
+ * DLL head for retry list
+ */
+ struct RetryListEntry *rl_head;
+
+ /**
+ * DLL tail for retry list
+ */
+ struct RetryListEntry *rl_tail;
+
+ /**
+ * The number of peers
+ */
+ unsigned int num_peers;
+
+ /**
+ * The size of the link array
+ */
+ unsigned int link_array_size;
+
+ /**
+ * How many retries to do before we give up
+ */
+ unsigned int retry_cnt;
+
+ /**
+ * Number of links to try
+ */
+ unsigned int nlinks;
+
+ /**
+ * How many links have been completed
+ */
+ unsigned int ncompleted;
+
+ /**
+ * Total successfully established overlay connections
+ */
+ unsigned int nsuccess;
+
+ /**
+ * Total failed overlay connections
+ */
+ unsigned int nfailures;
+};
+
+
+/**
+ * A array of names representing topologies. Should be in sync with enum
+ * GNUNET_TESTBED_TopologyOption
+ */
+const char *topology_strings[] = {
+
+ /**
+ * A clique (everyone connected to everyone else). No options. If there are N
+ * peers this topology results in (N * (N -1)) connections.
+ */
+ "CLIQUE",
+
+ /**
+ * Small-world network (2d torus plus random links). Followed
+ * by the number of random links to add (unsigned int).
+ */
+ "SMALL_WORLD",
+
+ /**
+ * Small-world network (ring plus random links). Followed
+ * by the number of random links to add (unsigned int).
+ */
+ "SMALL_WORLD_RING",
+
+ /**
+ * Ring topology. No options.
+ */
+ "RING",
+
+ /**
+ * 2-d torus. No options.
+ */
+ "2D_TORUS",
+
+ /**
+ * Random graph. Followed by the number of random links to be established
+ * (unsigned int)
+ */
+ "RANDOM", // GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
+
+ /**
+ * Certain percentage of peers are unable to communicate directly
+ * replicating NAT conditions. Followed by the fraction of
+ * NAT'ed peers (float).
+ */
+ "INTERNAT",
+
+ /**
+ * Scale free topology. No options.
+ */
+ "SCALE_FREE",
+
+ /**
+ * Straight line topology. No options.
+ */
+ "LINE",
+
+ /**
+ * Read a topology from a given file. Followed by the name of the file (const char *).
+ */
+ "FROM_FILE",
+
+ /**
+ * All peers are disconnected. No options.
+ */
+ "NONE",
+
+ /**
+ * End of strings
+ */
+ NULL
+};
+
+
+/**
+ * Callback to be called when an overlay_link operation complete
+ *
+ * @param cls element of the link_op array which points to the corresponding operation
+ * @param op the operation that has been finished
+ * @param emsg error message in case the operation has failed; will be NULL if
+ * operation has executed successfully.
+ */
+static void
+overlay_link_completed (void *cls, struct GNUNET_TESTBED_Operation *op,
+ const char *emsg)
+{
+ struct OverlayLink *link = cls;
+ struct TopologyContext *tc;
+ struct RetryListEntry *retry_entry;
+
+ GNUNET_assert (op == link->op);
+ GNUNET_TESTBED_operation_done (op);
+ link->op = NULL;
+ tc = link->tc;
+ if (NULL != emsg)
+ {
+ tc->nfailures++;
+ if (0 != tc->retry_cnt)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Error while establishing a link: %s -- Retrying\n", emsg);
+ retry_entry = GNUNET_malloc (sizeof (struct RetryListEntry));
+ retry_entry->link = link;
+ GNUNET_CONTAINER_DLL_insert_tail (tc->rl_head, tc->rl_tail, retry_entry);
+ }
+ }
+ else
+ tc->nsuccess++;
+ tc->ncompleted++;
+ if (tc->ncompleted < tc->nlinks)
+ return;
+ if ((0 != tc->retry_cnt) && (NULL != tc->rl_head))
+ {
+ tc->retry_cnt--;
+ tc->ncompleted = 0;
+ tc->nlinks = 0;
+ while (NULL != (retry_entry = tc->rl_head))
+ {
+ link = retry_entry->link;
+ link->op =
+ GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed,
+ link, tc->peers[link->A],
+ tc->peers[link->B]);
+ tc->nlinks++;
+ GNUNET_CONTAINER_DLL_remove (tc->rl_head, tc->rl_tail, retry_entry);
+ GNUNET_free (retry_entry);
+ }
+ return;
+ }
+ if (NULL != tc->comp_cb)
+ {
+ tc->comp_cb (tc->comp_cb_cls, tc->nsuccess, tc->nfailures);
+ }
+}
+
+
+
+/**
+ * Function called when a overlay connect operation is ready
+ *
+ * @param cls the Topology context
+ */
+static void
+opstart_overlay_configure_topology (void *cls)
+{
+ struct TopologyContext *tc = cls;
+ unsigned int p;
+
+ tc->nlinks = tc->link_array_size;
+ for (p = 0; p < tc->link_array_size; p++)
+ {
+ tc->link_array[p].op =
+ GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed,
+ &tc->link_array[p],
+ tc->peers[tc->link_array[p].A],
+ tc->peers[tc->link_array[p].B]);
+ }
+}
+
+
+/**
+ * Callback which will be called when overlay connect operation is released
+ *
+ * @param cls the Topology context
+ */
+static void
+oprelease_overlay_configure_topology (void *cls)
+{
+ struct TopologyContext *tc = cls;
+ struct RetryListEntry *retry_entry;
+ unsigned int p;
+
+ while (NULL != (retry_entry = tc->rl_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (tc->rl_head, tc->rl_tail, retry_entry);
+ GNUNET_free (retry_entry);
+ }
+ if (NULL != tc->link_array)
+ {
+ for (p = 0; p < tc->link_array_size; p++)
+ if (NULL != tc->link_array[p].op)
+ GNUNET_TESTBED_operation_done (tc->link_array[p].op);
+ GNUNET_free (tc->link_array);
+ }
+ GNUNET_free (tc);
+}
+
+
+/**
+ * Populates the OverlayLink structure.
+ *
+ * @param link the OverlayLink
+ * @param A the peer A. Should be different from B
+ * @param B the peer B. Should be different from A
+ * @param tc the TopologyContext
+ * @return
+ */
+static void
+make_link (struct OverlayLink *link, uint32_t A, uint32_t B,
+ struct TopologyContext *tc)
+{
+ GNUNET_assert (A != B);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %u to %u\n", B, A);
+ link->A = A;
+ link->B = B;
+ link->op = NULL;
+ link->tc = tc;
+}
+
+
+/**
+ * Generates line topology
+ *
+ * @param tc the topology context
+ */
+static void
+gen_topo_line (struct TopologyContext *tc)
+{
+ unsigned int cnt;
+
+ tc->link_array_size = tc->num_peers - 1;
+ tc->link_array =
+ GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
+ for (cnt = 0; cnt < (tc->num_peers - 1); cnt++)
+ make_link (&tc->link_array[cnt], cnt, cnt + 1, tc);
+}
+
+
+/**
+ * Generates ring topology
+ *
+ * @param tc the topology context
+ */
+static void
+gen_topo_ring (struct TopologyContext *tc)
+{
+ gen_topo_line (tc);
+ tc->link_array_size++;
+ tc->link_array =
+ GNUNET_realloc (tc->link_array,
+ sizeof (struct OverlayLink) * tc->link_array_size);
+ make_link (&tc->link_array[tc->link_array_size - 1], tc->num_peers - 1, 0,
+ tc);
+}
+
+
+/**
+ * Returns the number of links that are required to generate a 2d torus for the
+ * given number of peers. Also returns the arrangment (number of rows and the
+ * length of each row)
+ *
+ * @param num_peers number of peers
+ * @param rows number of rows in the 2d torus. Can be NULL
+ * @param rows_len the length of each row. This array will be allocated
+ * fresh. The caller should free it. Can be NULL
+ */
+unsigned int
+GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
+ unsigned int **rows_len)
+{
+ double sq;
+ unsigned int sq_floor;
+ unsigned int _rows;
+ unsigned int *_rows_len;
+ unsigned int x;
+ unsigned int y;
+ unsigned int _num_peers;
+ unsigned int cnt;
+
+ sq = sqrt (num_peers);
+ sq = floor (sq);
+ sq_floor = (unsigned int) sq;
+ _rows = (sq_floor + 1);
+ _rows_len = GNUNET_malloc (sizeof (unsigned int) * _rows);
+ for (y = 0; y < _rows - 1; y++)
+ _rows_len[y] = sq_floor;
+ _num_peers = sq_floor * sq_floor;
+ cnt = 2 * _num_peers;
+ x = 0;
+ y = 0;
+ while (_num_peers < num_peers)
+ {
+ if (x < y)
+ _rows_len[_rows - 1] = ++x;
+ else
+ _rows_len[y++]++;
+ _num_peers++;
+ }
+ cnt += (x < 2) ? x : 2 * x;
+ cnt += (y < 2) ? y : 2 * y;
+ if (0 == _rows_len[_rows - 1])
+ _rows--;
+ if (NULL != rows)
+ *rows = _rows;
+ if (NULL != rows_len)
+ *rows_len = _rows_len;
+ else
+ GNUNET_free (_rows_len);
+ return cnt;
+}
+
+
+/**
+ * Generates ring topology
+ *
+ * @param tc the topology context
+ */
+static void
+gen_topo_2dtorus (struct TopologyContext *tc)
+{
+ unsigned int rows;
+ unsigned int *rows_len;
+ unsigned int x;
+ unsigned int y;
+ unsigned int cnt;
+ unsigned int offset;
+
+ tc->link_array_size =
+ GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows, &rows_len);
+ tc->link_array =
+ GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
+ cnt = 0;
+ offset = 0;
+ for (y = 0; y < rows; y++)
+ {
+ for (x = 0; x < rows_len[y] - 1; x++)
+ {
+ make_link (&tc->link_array[cnt], offset + x, offset + x + 1, tc);
+ cnt++;
+ }
+ if (0 == x)
+ break;
+ make_link (&tc->link_array[cnt], offset + x, offset, tc);
+ cnt++;
+ offset += rows_len[y];
+ }
+ for (x = 0; x < rows_len[0]; x++)
+ {
+ offset = 0;
+ for (y = 0; y < rows - 1; y++)
+ {
+ if (x >= rows_len[y + 1])
+ break;
+ GNUNET_assert (x < rows_len[y + 1]);
+ make_link (&tc->link_array[cnt], offset + x, offset + rows_len[y] + x,
+ tc);
+ offset += rows_len[y];
+ cnt++;
+ }
+ if (0 == offset)
+ break;
+ make_link (&tc->link_array[cnt], offset + x, x, tc);
+ cnt++;
+ }
+ GNUNET_assert (cnt == tc->link_array_size);
+ GNUNET_free (rows_len);
+}
+
+
+/**
+ * Generates ring topology
+ *
+ * @param tc the topology context
+ * @param links the number of random links to establish
+ * @param append GNUNET_YES to add links to existing link array; GNUNET_NO to
+ * create a new link array
+ */
+static void
+gen_topo_random (struct TopologyContext *tc, unsigned int links, int append)
+{
+ unsigned int cnt;
+ unsigned int index;
+ uint32_t A_rand;
+ uint32_t B_rand;
+
+ if (GNUNET_YES == append)
+ {
+ GNUNET_assert ((0 < tc->link_array_size) && (NULL != tc->link_array));
+ index = tc->link_array_size;
+ tc->link_array_size += links;
+ tc->link_array =
+ GNUNET_realloc (tc->link_array,
+ sizeof (struct OverlayLink) * tc->link_array_size);
+ }
+ else
+ {
+ GNUNET_assert ((0 == tc->link_array_size) && (NULL == tc->link_array));
+ index = 0;
+ tc->link_array_size = links;
+ tc->link_array =
+ GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
+ }
+ for (cnt = 0; cnt < links; cnt++)
+ {
+ do
+ {
+ A_rand =
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
+ B_rand =
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
+ }
+ while (A_rand == B_rand);
+ make_link (&tc->link_array[index + cnt], A_rand, B_rand, tc);
+ }
+}
+
+
+/**
+ * Generates scale free network. Its construction is described in:
+ *
+ * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
+ *
+ * @param tc the topology context
+ */
+static void
+gen_scale_free (struct TopologyContext *tc)
+{
+ double random;
+ double probability;
+ unsigned int cnt;
+ unsigned int previous_connections;
+ unsigned int i;
+ uint16_t *popularity;
+
+ popularity = GNUNET_malloc (sizeof (uint16_t) * tc->num_peers);
+ /* Initially connect peer 1 to peer 0 */
+ tc->link_array_size = 1;
+ tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink));
+ make_link (&tc->link_array[0], 0, 1, tc);
+ popularity[0]++; /* increase popularity of 0 as 1 connected to it */
+ for (cnt = 1; cnt < tc->num_peers; cnt++)
+ {
+ previous_connections = tc->link_array_size;
+ for (i = 0; i < cnt; i++)
+ {
+ probability = ((double) popularity[i]) / ((double) previous_connections);
+ random =
+ ((double)
+ GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT64_MAX)) / ((double) UINT64_MAX);
+ if (random < probability)
+ {
+ tc->link_array_size++;
+ tc->link_array =
+ GNUNET_realloc (tc->link_array,
+ (sizeof (struct OverlayLink) *
+ tc->link_array_size));
+ make_link (&tc->link_array[tc->link_array_size - 1], cnt, i, tc);
+ popularity[cnt]++;
+ }
+ }
+ }
+ GNUNET_free (popularity);
+}
+
+
+/**
+ * Generates topology from the given file
+ *
+ * @param tc the topology context
+ * @param filename the filename of the file containing topology data
+ */
+static void
+gen_topo_from_file (struct TopologyContext *tc, const char *filename)
+{
+ char *data;
+ char *end;
+ char *buf;
+ uint64_t fs;
+ uint64_t offset;
+ unsigned long int peer_id;
+ unsigned long int other_peer_id;
+ enum ParseState
+ {
+
+ /**
+ * We read the peer index
+ */
+ PEER_INDEX,
+
+ /**
+ * We read the other peer indices
+ */
+ OTHER_PEER_INDEX,
+
+ } state;
+ int status;
+
+ status = GNUNET_SYSERR;
+ if (GNUNET_YES != GNUNET_DISK_file_test (filename))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s not found\n"), filename);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s has no data\n"),
+ filename);
+ return;
+ }
+ data = GNUNET_malloc (fs);
+ if (fs != GNUNET_DISK_fn_read (filename, data, fs))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Topology file %s cannot be read\n"),
+ filename);
+ goto _exit;
+ }
+
+ offset = 0;
+ peer_id = 0;
+ state = PEER_INDEX;
+ buf = data;
+ while (offset < fs)
+ {
+ if (0 != isspace (data[offset]))
+ {
+ offset++;
+ continue;
+ }
+ switch (state)
+ {
+ case PEER_INDEX:
+ buf = strchr (&data[offset], ':');
+ if (NULL == buf)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to read peer index from toology file: %s"), filename);
+ goto _exit;
+ }
+ *buf = '\0';
+ errno = 0;
+ peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
+ if (0 != errno)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Value in given topology file: %s out of range\n"), filename);
+ goto _exit;
+ }
+ if (&data[offset] == end)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to read peer index from topology file: %s"), filename);
+ goto _exit;
+ }
+ if (tc->num_peers <= peer_id)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Topology file needs more peers than given ones\n"), filename);
+ goto _exit;
+ }
+ state = OTHER_PEER_INDEX;
+ offset += ((unsigned int) (buf - &data[offset])) + 1;
+ break;
+ case OTHER_PEER_INDEX:
+ errno = 0;
+ other_peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
+ if (0 != errno)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Value in given topology file: %s out of range\n"), filename);
+ goto _exit;
+ }
+ if (&data[offset] == end)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to read peer index from topology file: %s"), filename);
+ goto _exit;
+ }
+ if (tc->num_peers <= other_peer_id)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Topology file needs more peers than given ones\n"), filename);
+ goto _exit;
+ }
+ if (peer_id != other_peer_id)
+ {
+ tc->link_array_size++;
+ tc->link_array =
+ GNUNET_realloc (tc->link_array,
+ sizeof (struct OverlayLink) * tc->link_array_size);
+ offset += end - &data[offset];
+ make_link (&tc->link_array[tc->link_array_size - 1], peer_id,
+ other_peer_id, tc);
+ }
+ else
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Ignoring to connect peer %u to peer %u\n"), peer_id,
+ other_peer_id);
+ while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
+ offset++;
+ if ('\n' == data[offset])
+ state = PEER_INDEX;
+ else if ('|' == data[offset])
+ {
+ state = OTHER_PEER_INDEX;
+ offset++;
+ }
+ break;
+ }
+ }
+ status = GNUNET_OK;
+
+_exit:
+ GNUNET_free (data);
+ if (GNUNET_OK != status)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING, "Removing link data read from the file\n");
+ tc->link_array_size = 0;
+ GNUNET_free_non_null (tc->link_array);
+ tc->link_array = NULL;
+ }
+}
/**
@@ -40,10 +802,12 @@
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer **peers,
- enum GNUNET_TESTBED_TopologyOption topo,
- va_list ap)
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer
+ **peers,
+ enum
+ GNUNET_TESTBED_TopologyOption
+ topo, va_list ap)
{
GNUNET_break (0);
return NULL;
@@ -63,10 +827,10 @@ GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer **peers,
- enum GNUNET_TESTBED_TopologyOption topo,
- ...)
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers,
+ enum GNUNET_TESTBED_TopologyOption
+ topo, ...)
{
GNUNET_break (0);
return NULL;
@@ -78,24 +842,144 @@ GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
* This function then connects the given peers in the P2P overlay
* using the given topology.
*
- * @param op_cls closure argument to give with the operation event
+ * @param op_cls closure argument to give with the peer connect operation events
+ * generated through this function
* @param num_peers number of peers in 'peers'
* @param peers array of 'num_peers' with the peers to configure
+ * @param max_connections the maximums number of overlay connections that will
+ * be made to achieve the given topology
+ * @param comp_cb the completion callback to call when the topology generation
+ * is completed
+ * @param comp_cb_cls closure for the above completion callback
* @param topo desired underlay topology to use
* @param va topology-specific options
- * @return handle to the operation, NULL if connecting these
+ * @return handle to the operation, NULL if connecting these
* peers is fundamentally not possible at this time (peers
- * not running or underlay disallows)
+ * not running or underlay disallows) or if num_peers is less than 2
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer *peers,
- enum GNUNET_TESTBED_TopologyOption topo,
- va_list va)
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers,
+ unsigned int *max_connections,
+ GNUNET_TESTBED_TopologyCompletionCallback
+ comp_cb,
+ void *comp_cb_cls,
+ enum GNUNET_TESTBED_TopologyOption topo,
+ va_list va)
{
- GNUNET_break (0);
- return NULL;
+ struct TopologyContext *tc;
+ struct GNUNET_TESTBED_Operation *op;
+ struct GNUNET_TESTBED_Controller *c;
+ enum GNUNET_TESTBED_TopologyOption secondary_option;
+ unsigned int cnt;
+
+ if (num_peers < 2)
+ return NULL;
+ c = peers[0]->controller;
+ tc = GNUNET_malloc (sizeof (struct TopologyContext));
+ tc->peers = peers;
+ tc->num_peers = num_peers;
+ tc->op_cls = op_cls;
+ tc->retry_cnt = DEFAULT_RETRY_CNT;
+ switch (topo)
+ {
+ case GNUNET_TESTBED_TOPOLOGY_LINE:
+ gen_topo_line (tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_RING:
+ gen_topo_ring (tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
+ gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_NO);
+
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
+ gen_topo_ring (tc);
+ gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
+
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
+ tc->link_array_size = num_peers * (num_peers - 1);
+ tc->link_array =
+ GNUNET_malloc (sizeof (struct OverlayLink) * tc->link_array_size);
+ {
+ unsigned int offset;
+
+ offset = 0;
+ for (cnt = 0; cnt < num_peers; cnt++)
+ {
+ unsigned int neighbour;
+
+ for (neighbour = 0; neighbour < num_peers; neighbour++)
+ {
+ if (neighbour == cnt)
+ continue;
+ tc->link_array[offset].A = cnt;
+ tc->link_array[offset].B = neighbour;
+ tc->link_array[offset].tc = tc;
+ offset++;
+ }
+ }
+ }
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
+ gen_topo_2dtorus (tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
+ gen_topo_2dtorus (tc);
+ gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
+
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
+ gen_scale_free (tc);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
+ {
+ const char *filename;
+
+ filename = va_arg (va, const char *);
+
+ GNUNET_assert (NULL != filename);
+ gen_topo_from_file (tc, filename);
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ GNUNET_free (tc);
+ return NULL;
+ }
+ do
+ {
+ secondary_option = va_arg (va, enum GNUNET_TESTBED_TopologyOption);
+
+ switch (secondary_option)
+ {
+ case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT:
+ tc->retry_cnt = va_arg (va, unsigned int);
+ break;
+ case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
+ break;
+ default:
+ GNUNET_break (0); /* Should not use any other option apart from
+ * the ones handled here */
+ GNUNET_free_non_null (tc->link_array);
+ GNUNET_free (tc);
+ return NULL;
+ }
+ }
+ while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
+ op = GNUNET_TESTBED_operation_create_ (tc,
+ &opstart_overlay_configure_topology,
+ &oprelease_overlay_configure_topology);
+ GNUNET_TESTBED_operation_queue_insert_
+ (c->opq_parallel_topology_config_operations, op);
+ GNUNET_TESTBED_operation_begin_wait_ (op);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Generated %u connections\n",
+ tc->link_array_size);
+ if (NULL != max_connections)
+ *max_connections = tc->link_array_size;
+ return op;
}
@@ -104,24 +988,88 @@ GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
* This function then connects the given peers in the P2P overlay
* using the given topology.
*
- * @param op_cls closure argument to give with the operation event
+ * @param op_cls closure argument to give with the peer connect operation events
+ * generated through this function
* @param num_peers number of peers in 'peers'
* @param peers array of 'num_peers' with the peers to configure
+ * @param max_connections the maximums number of overlay connections that will
+ * be made to achieve the given topology
+ * @param comp_cb the completion callback to call when the topology generation
+ * is completed
+ * @param comp_cb_cls closure for the above completion callback
* @param topo desired underlay topology to use
* @param ... topology-specific options
- * @return handle to the operation, NULL if connecting these
+ * @return handle to the operation, NULL if connecting these
* peers is fundamentally not possible at this time (peers
- * not running or underlay disallows)
+ * not running or underlay disallows) or if num_peers is less than 2
*/
struct GNUNET_TESTBED_Operation *
GNUNET_TESTBED_overlay_configure_topology (void *op_cls,
- unsigned int num_peers,
- struct GNUNET_TESTBED_Peer *peers,
- enum GNUNET_TESTBED_TopologyOption topo,
- ...)
+ unsigned int num_peers,
+ struct GNUNET_TESTBED_Peer **peers,
+ unsigned int *max_connections,
+ GNUNET_TESTBED_TopologyCompletionCallback
+ comp_cb,
+ void *comp_cb_cls,
+ enum GNUNET_TESTBED_TopologyOption topo,
+ ...)
{
- GNUNET_break (0);
- return NULL;
+ struct GNUNET_TESTBED_Operation *op;
+ va_list vargs;
+
+ GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
+ va_start (vargs, topo);
+ op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
+ max_connections,
+ comp_cb, comp_cb_cls,
+ topo,
+ vargs);
+ va_end (vargs);
+ return op;
+}
+
+
+/**
+ * Get a topology from a string input.
+ *
+ * @param topology where to write the retrieved topology
+ * @param topology_string The string to attempt to
+ * get a configuration value from
+ * @return GNUNET_YES if topology string matched a
+ * known topology, GNUNET_NO if not
+ */
+int
+GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
+ const char *topology_string)
+{
+ unsigned int cnt;
+
+ for (cnt = 0; NULL != topology_strings[cnt]; cnt++)
+ {
+ if (0 == strcasecmp (topology_string, topology_strings[cnt]))
+ {
+ if (NULL != topology)
+ *topology = (enum GNUNET_TESTBED_TopologyOption) cnt;
+ return GNUNET_YES;
+ }
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Returns the string corresponding to the given topology
+ *
+ * @param topology the topology
+ * @return the string (freshly allocated) of given topology; NULL if topology cannot be
+ * expressed as a string
+ */
+char *
+GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology)
+{
+ if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology)
+ return NULL;
+ return GNUNET_strdup (topology_strings[topology]);
}
/* end of testbed_api_topology.c */
diff --git a/src/testbed/testbed_api_topology.h b/src/testbed/testbed_api_topology.h
new file mode 100644
index 0000000..b5f3685
--- /dev/null
+++ b/src/testbed/testbed_api_topology.h
@@ -0,0 +1,70 @@
+/*
+ This file is part of GNUnet
+ (C) 2008--2012 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 3, 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 testbed/testbed_api_topology.h
+ * @brief header for intra library exported functions
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#ifndef TESTBED_API_TOPOLOGY_H
+#define TESTBED_API_TOPOLOGY_H
+
+/**
+ * Returns the number of links that are required to generate a 2d torus for the
+ * given number of peers. Also returns the arrangment (number of rows and the
+ * length of each row)
+ *
+ * @param num_peers number of peers
+ * @param rows number of rows in the 2d torus. Can be NULL.
+ * @param rows_len the length of each row. This array will be allocated
+ * fresh. The caller should free it. Can be NULL.
+ */
+unsigned int
+GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
+ unsigned int **rows_len);
+
+
+/**
+ * Get a topology from a string input.
+ *
+ * @param topology where to write the retrieved topology
+ * @param topology_string The string to attempt to
+ * get a configuration value from
+ * @return GNUNET_YES if topology string matched a
+ * known topology, GNUNET_NO if not
+ */
+int
+GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
+ const char *topology_string);
+
+
+/**
+ * Returns the string corresponding to the given topology
+ *
+ * @param topology the topology
+ * @return the string (freshly allocated) of given topology; NULL if topology cannot be
+ * expressed as a string
+ */
+char *
+GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology);
+
+#endif
+/* end of testbed_api_topology.h */
diff --git a/src/testbed/testbed_helper.h b/src/testbed/testbed_helper.h
new file mode 100644
index 0000000..6b476cd
--- /dev/null
+++ b/src/testbed/testbed_helper.h
@@ -0,0 +1,89 @@
+/*
+ This file is part of GNUnet
+ (C) 2012 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 3, 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 testbed/testbed_helper.h
+ * @brief Message formats for communication between testbed api and
+ * gnunet-helper-testbed process
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+
+#ifndef TESTBED_HELPER_H
+#define TESTBED_HELPER_H
+
+GNUNET_NETWORK_STRUCT_BEGIN
+/**
+ * Initialization message for gnunet-helper-testbed to start testbed service
+ */
+ struct GNUNET_TESTBED_HelperInit
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * The controller hostname size excluding the NULL termination character -
+ * strlen (hostname); cannot be zero
+ */
+ uint16_t trusted_ip_size GNUNET_PACKED;
+
+ /**
+ * The hostname size excluding the NULL termination character - strlen
+ * (hostname); cannot be zero
+ */
+ uint16_t hostname_size GNUNET_PACKED;
+
+ /**
+ * The size of the uncompressed configuration
+ */
+ uint16_t config_size GNUNET_PACKED;
+
+ /* Followed by NULL terminated trusted ip */
+
+ /* Followed by hostname of the machine on which helper runs. This is not NULL
+ * terminated */
+
+ /* Followed by serialized and compressed configuration which should be
+ * config_size long when un-compressed */
+};
+
+/**
+ * Reply message from helper process
+ */
+struct GNUNET_TESTBED_HelperReply
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Size of the uncompressed configuration
+ */
+ uint16_t config_size GNUNET_PACKED;
+
+ /* Followed by compressed configuration which should be config_size long when
+ * un-compressed */
+};
+
+GNUNET_NETWORK_STRUCT_END
+#endif
+/* end of testbed_helper.h */