From e0033c1da56e1889775d7dccf92ea78ee52e4d5c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 9 Jun 2012 15:35:06 +0000 Subject: -moving old testing code to legacy location --- src/Makefile.am | 3 +- src/dht/Makefile.am | 16 +- src/fs/Makefile.am | 16 +- src/mesh/Makefile.am | 10 +- src/nse/Makefile.am | 4 +- src/testing/Makefile.am | 267 +- src/testing/gnunet-testing-remote-peer-start.pl | 92 - src/testing/gnunet-testing.c | 291 - src/testing/helper.c | 75 - src/testing/test_testing.c | 126 - src/testing/test_testing_2dtorus.c | 372 -- src/testing/test_testing_2dtorus.conf | 81 - src/testing/test_testing_connect.c | 197 - src/testing/test_testing_connect_peer1.conf | 37 - src/testing/test_testing_connect_peer2.conf | 37 - src/testing/test_testing_data.conf | 7 - src/testing/test_testing_data_remote.conf | 12 - .../test_testing_data_topology_2d_torus.conf | 7 - .../test_testing_data_topology_blacklist.conf | 13 - src/testing/test_testing_data_topology_churn.conf | 10 - src/testing/test_testing_data_topology_clique.conf | 10 - .../test_testing_data_topology_clique_dfs.conf | 13 - .../test_testing_data_topology_clique_minimum.conf | 10 - .../test_testing_data_topology_clique_random.conf | 16 - .../test_testing_data_topology_erdos_renyi.conf | 7 - .../test_testing_data_topology_internat.conf | 7 - src/testing/test_testing_data_topology_none.conf | 37 - src/testing/test_testing_data_topology_ring.conf | 7 - .../test_testing_data_topology_scale_free.conf | 11 - ...est_testing_data_topology_small_world_ring.conf | 8 - ...st_testing_data_topology_small_world_torus.conf | 7 - .../test_testing_data_topology_stability.conf | 9 - src/testing/test_testing_defaults.conf | 78 - src/testing/test_testing_group.c | 166 - src/testing/test_testing_group_remote.c | 263 - src/testing/test_testing_large_topology.c | 1197 ---- src/testing/test_testing_peergroup.c | 157 - src/testing/test_testing_peergroup_data.conf | 22 - src/testing/test_testing_reconnect.c | 249 - src/testing/test_testing_topology.c | 1220 ---- src/testing/test_testing_topology_blacklist.c | 595 -- src/testing/test_testing_topology_churn.c | 322 - src/testing/testing.c | 2204 ------ src/testing/testing_group.c | 7038 -------------------- src/testing/testing_peergroup.c | 1017 --- src/testing_old/Makefile.am | 283 + .../gnunet-testing-remote-peer-start.pl | 92 + src/testing_old/gnunet-testing.c | 291 + src/testing_old/helper.c | 75 + src/testing_old/test_testing.c | 126 + src/testing_old/test_testing_2dtorus.c | 372 ++ src/testing_old/test_testing_2dtorus.conf | 81 + src/testing_old/test_testing_connect.c | 197 + src/testing_old/test_testing_connect_peer1.conf | 37 + src/testing_old/test_testing_connect_peer2.conf | 37 + src/testing_old/test_testing_data.conf | 7 + src/testing_old/test_testing_data_remote.conf | 12 + .../test_testing_data_topology_2d_torus.conf | 7 + .../test_testing_data_topology_blacklist.conf | 13 + .../test_testing_data_topology_churn.conf | 10 + .../test_testing_data_topology_clique.conf | 10 + .../test_testing_data_topology_clique_dfs.conf | 13 + .../test_testing_data_topology_clique_minimum.conf | 10 + .../test_testing_data_topology_clique_random.conf | 16 + .../test_testing_data_topology_erdos_renyi.conf | 7 + .../test_testing_data_topology_internat.conf | 7 + .../test_testing_data_topology_none.conf | 37 + .../test_testing_data_topology_ring.conf | 7 + .../test_testing_data_topology_scale_free.conf | 11 + ...est_testing_data_topology_small_world_ring.conf | 8 + ...st_testing_data_topology_small_world_torus.conf | 7 + .../test_testing_data_topology_stability.conf | 9 + src/testing_old/test_testing_defaults.conf | 78 + src/testing_old/test_testing_group.c | 166 + src/testing_old/test_testing_group_remote.c | 263 + src/testing_old/test_testing_large_topology.c | 1197 ++++ src/testing_old/test_testing_peergroup.c | 157 + src/testing_old/test_testing_peergroup_data.conf | 22 + src/testing_old/test_testing_reconnect.c | 249 + src/testing_old/test_testing_topology.c | 1220 ++++ src/testing_old/test_testing_topology_blacklist.c | 595 ++ src/testing_old/test_testing_topology_churn.c | 322 + src/testing_old/testing.c | 2204 ++++++ src/testing_old/testing.conf | 11 + src/testing_old/testing_group.c | 7038 ++++++++++++++++++++ src/testing_old/testing_peergroup.c | 1017 +++ src/topology/Makefile.am | 2 +- 87 files changed, 16353 insertions(+), 16313 deletions(-) delete mode 100755 src/testing/gnunet-testing-remote-peer-start.pl delete mode 100644 src/testing/gnunet-testing.c delete mode 100644 src/testing/helper.c delete mode 100644 src/testing/test_testing.c delete mode 100644 src/testing/test_testing_2dtorus.c delete mode 100644 src/testing/test_testing_2dtorus.conf delete mode 100644 src/testing/test_testing_connect.c delete mode 100644 src/testing/test_testing_connect_peer1.conf delete mode 100644 src/testing/test_testing_connect_peer2.conf delete mode 100644 src/testing/test_testing_data.conf delete mode 100644 src/testing/test_testing_data_remote.conf delete mode 100644 src/testing/test_testing_data_topology_2d_torus.conf delete mode 100644 src/testing/test_testing_data_topology_blacklist.conf delete mode 100644 src/testing/test_testing_data_topology_churn.conf delete mode 100644 src/testing/test_testing_data_topology_clique.conf delete mode 100644 src/testing/test_testing_data_topology_clique_dfs.conf delete mode 100644 src/testing/test_testing_data_topology_clique_minimum.conf delete mode 100644 src/testing/test_testing_data_topology_clique_random.conf delete mode 100644 src/testing/test_testing_data_topology_erdos_renyi.conf delete mode 100644 src/testing/test_testing_data_topology_internat.conf delete mode 100644 src/testing/test_testing_data_topology_none.conf delete mode 100644 src/testing/test_testing_data_topology_ring.conf delete mode 100644 src/testing/test_testing_data_topology_scale_free.conf delete mode 100644 src/testing/test_testing_data_topology_small_world_ring.conf delete mode 100644 src/testing/test_testing_data_topology_small_world_torus.conf delete mode 100644 src/testing/test_testing_data_topology_stability.conf delete mode 100644 src/testing/test_testing_defaults.conf delete mode 100644 src/testing/test_testing_group.c delete mode 100644 src/testing/test_testing_group_remote.c delete mode 100644 src/testing/test_testing_large_topology.c delete mode 100644 src/testing/test_testing_peergroup.c delete mode 100644 src/testing/test_testing_peergroup_data.conf delete mode 100644 src/testing/test_testing_reconnect.c delete mode 100644 src/testing/test_testing_topology.c delete mode 100644 src/testing/test_testing_topology_blacklist.c delete mode 100644 src/testing/test_testing_topology_churn.c delete mode 100644 src/testing/testing.c delete mode 100644 src/testing/testing_group.c delete mode 100644 src/testing/testing_peergroup.c create mode 100644 src/testing_old/Makefile.am create mode 100755 src/testing_old/gnunet-testing-remote-peer-start.pl create mode 100644 src/testing_old/gnunet-testing.c create mode 100644 src/testing_old/helper.c create mode 100644 src/testing_old/test_testing.c create mode 100644 src/testing_old/test_testing_2dtorus.c create mode 100644 src/testing_old/test_testing_2dtorus.conf create mode 100644 src/testing_old/test_testing_connect.c create mode 100644 src/testing_old/test_testing_connect_peer1.conf create mode 100644 src/testing_old/test_testing_connect_peer2.conf create mode 100644 src/testing_old/test_testing_data.conf create mode 100644 src/testing_old/test_testing_data_remote.conf create mode 100644 src/testing_old/test_testing_data_topology_2d_torus.conf create mode 100644 src/testing_old/test_testing_data_topology_blacklist.conf create mode 100644 src/testing_old/test_testing_data_topology_churn.conf create mode 100644 src/testing_old/test_testing_data_topology_clique.conf create mode 100644 src/testing_old/test_testing_data_topology_clique_dfs.conf create mode 100644 src/testing_old/test_testing_data_topology_clique_minimum.conf create mode 100644 src/testing_old/test_testing_data_topology_clique_random.conf create mode 100644 src/testing_old/test_testing_data_topology_erdos_renyi.conf create mode 100644 src/testing_old/test_testing_data_topology_internat.conf create mode 100644 src/testing_old/test_testing_data_topology_none.conf create mode 100644 src/testing_old/test_testing_data_topology_ring.conf create mode 100644 src/testing_old/test_testing_data_topology_scale_free.conf create mode 100644 src/testing_old/test_testing_data_topology_small_world_ring.conf create mode 100644 src/testing_old/test_testing_data_topology_small_world_torus.conf create mode 100644 src/testing_old/test_testing_data_topology_stability.conf create mode 100644 src/testing_old/test_testing_defaults.conf create mode 100644 src/testing_old/test_testing_group.c create mode 100644 src/testing_old/test_testing_group_remote.c create mode 100644 src/testing_old/test_testing_large_topology.c create mode 100644 src/testing_old/test_testing_peergroup.c create mode 100644 src/testing_old/test_testing_peergroup_data.conf create mode 100644 src/testing_old/test_testing_reconnect.c create mode 100644 src/testing_old/test_testing_topology.c create mode 100644 src/testing_old/test_testing_topology_blacklist.c create mode 100644 src/testing_old/test_testing_topology_churn.c create mode 100644 src/testing_old/testing.c create mode 100644 src/testing_old/testing.conf create mode 100644 src/testing_old/testing_group.c create mode 100644 src/testing_old/testing_peergroup.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 37bcbf676..0afd18063 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,6 +28,7 @@ SUBDIRS = \ block \ statistics \ arm \ + testing \ peerinfo \ $(MYSQL_DIR) \ $(POSTGRES_DIR) \ @@ -41,7 +42,7 @@ SUBDIRS = \ transport \ peerinfo-tool \ core \ - testing \ + testing_old \ testbed \ nse \ dht \ diff --git a/src/dht/Makefile.am b/src/dht/Makefile.am index 0ea452db1..0b840dc9a 100644 --- a/src/dht/Makefile.am +++ b/src/dht/Makefile.am @@ -141,7 +141,7 @@ test_dht_twopeer_SOURCES = \ test_dht_twopeer.c test_dht_twopeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_DEPENDENCIES = \ libgnunetdht.la @@ -150,21 +150,21 @@ test_dht_twopeer_put_get_SOURCES = \ test_dht_twopeer_put_get.c test_dht_twopeer_put_get_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_get_put_SOURCES = \ test_dht_twopeer_get_put.c test_dht_twopeer_get_put_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_twopeer_path_tracking_SOURCES = \ test_dht_twopeer_path_tracking.c test_dht_twopeer_path_tracking_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_multipeer_SOURCES = \ @@ -172,7 +172,7 @@ test_dht_multipeer_SOURCES = \ test_dht_multipeer_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_multipeer_DEPENDENCIES = \ libgnunetdht.la @@ -181,7 +181,7 @@ test_dht_2dtorus_SOURCES = \ test_dht_topo.c test_dht_2dtorus_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_2dtorus_DEPENDENCIES = \ libgnunetdht.la @@ -190,7 +190,7 @@ test_dht_line_SOURCES = \ test_dht_topo.c test_dht_line_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_line_DEPENDENCIES = \ libgnunetdht.la @@ -198,7 +198,7 @@ test_dht_line_DEPENDENCIES = \ test_dht_monitor_SOURCES = test_dht_monitor.c test_dht_monitor_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/dht/libgnunetdht.la test_dht_monitor_DEPENDENCIES = \ libgnunetdht.la diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am index f68cad75b..c88427d83 100644 --- a/src/fs/Makefile.am +++ b/src/fs/Makefile.am @@ -57,7 +57,7 @@ libgnunetfstest_a_SOURCES = \ fs_test_lib.c fs_test_lib.h libgnunetfstest_a_LIBADD = \ - $(top_builddir)/src/testing/libgnunettesting.la + $(top_builddir)/src/testing_old/libgnunettesting_old.la bin_PROGRAMS = \ gnunet-directory \ @@ -375,7 +375,7 @@ test_fs_test_lib_SOURCES = \ test_fs_test_lib.c test_fs_test_lib_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la @@ -383,7 +383,7 @@ test_gnunet_service_fs_p2p_SOURCES = \ test_gnunet_service_fs_p2p.c test_gnunet_service_fs_p2p_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la @@ -391,7 +391,7 @@ test_gnunet_service_fs_migration_SOURCES = \ test_gnunet_service_fs_migration.c test_gnunet_service_fs_migration_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la @@ -400,7 +400,7 @@ perf_gnunet_service_fs_p2p_SOURCES = \ perf_gnunet_service_fs_p2p_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la @@ -409,7 +409,7 @@ perf_gnunet_service_fs_p2p_index_SOURCES = \ perf_gnunet_service_fs_p2p_index_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la @@ -418,7 +418,7 @@ perf_gnunet_service_fs_p2p_dht_SOURCES = \ perf_gnunet_service_fs_p2p_dht_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la @@ -427,7 +427,7 @@ perf_gnunet_service_fs_p2p_trust_SOURCES = \ perf_gnunet_service_fs_p2p_trust_LDADD = \ $(top_builddir)/src/fs/libgnunetfstest.a \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/fs/libgnunetfs.la \ $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/mesh/Makefile.am b/src/mesh/Makefile.am index 4c5dbb5d9..e116b889a 100644 --- a/src/mesh/Makefile.am +++ b/src/mesh/Makefile.am @@ -105,14 +105,14 @@ test_mesh_2dtorus_SOURCES = \ test_mesh_2dtorus.c test_mesh_2dtorus_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la + $(top_builddir)/src/testing_old/libgnunettesting_old.la test_mesh_small_unicast_SOURCES = \ test_mesh_small.c test_mesh_small_unicast_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la + $(top_builddir)/src/testing_old/libgnunettesting_old.la test_mesh_small_unicast_DEPENDENCIES = \ libgnunetmesh.la @@ -121,7 +121,7 @@ test_mesh_small_multicast_SOURCES = \ test_mesh_small_multicast_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la + $(top_builddir)/src/testing_old/libgnunettesting_old.la test_mesh_small_multicast_DEPENDENCIES = \ libgnunetmesh.la @@ -130,7 +130,7 @@ test_mesh_small_speed_SOURCES = \ test_mesh_small_speed_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la + $(top_builddir)/src/testing_old/libgnunettesting_old.la test_mesh_small_speed_DEPENDENCIES = \ libgnunetmesh.la @@ -139,7 +139,7 @@ test_mesh_small_speed_ack_SOURCES = \ test_mesh_small_speed_ack_LDADD = \ $(top_builddir)/src/mesh/libgnunetmesh.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la + $(top_builddir)/src/testing_old/libgnunettesting_old.la test_mesh_small_speed_ack_DEPENDENCIES = \ libgnunetmesh.la diff --git a/src/nse/Makefile.am b/src/nse/Makefile.am index 054a77663..2011661cf 100644 --- a/src/nse/Makefile.am +++ b/src/nse/Makefile.am @@ -39,7 +39,7 @@ gnunet_nse_profiler_LDADD = -lm \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(GN_LIBINTL) gnunet_nse_profiler_DEPENDENCIES = \ libgnunetnse.la @@ -80,7 +80,7 @@ test_nse_multipeer_SOURCES = \ test_nse_multipeer_LDADD = \ $(top_builddir)/src/nse/libgnunetnse.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ -lm EXTRA_DIST = \ diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 455df6989..dcefc34d1 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -14,301 +14,46 @@ pkgcfgdir= $(pkgdatadir)/config.d/ dist_pkgcfg_DATA = \ testing.conf -if HAVE_EXPENSIVE_TESTS - EXPENSIVE_TESTS = \ - test_testing_topology_stability \ - test_testing_topology_clique_random \ - test_testing_topology_clique_minimum \ - test_testing_topology_clique_dfs \ - test_testing_topology_churn \ - test_testing_topology_line \ - test_testing_topology_blacklist \ - test_testing_group_remote \ - test_testing_topology_ring \ - test_testing_topology_2d_torus \ - test_testing_topology_small_world_ring \ - test_testing_topology_small_world_torus \ - test_testing_topology_erdos_renyi \ - test_testing_topology_internat \ - test_testing_topology_scale_free -endif - lib_LTLIBRARIES = \ - libgnunettesting.la \ - libgnunettesting_new.la + libgnunettesting.la libgnunettesting_la_SOURCES = \ - helper.c \ - testing.c \ - testing_group.c \ - testing_peergroup.c -libgnunettesting_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 \ - $(LTLIBINTL) -libgnunettesting_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) \ - -version-info 0:1:0 - - -libgnunettesting_new_la_SOURCES = \ testing_new.c -libgnunettesting_new_la_LIBADD = \ +libgnunettesting_la_LIBADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(LTLIBINTL) -libgnunettesting_new_la_LDFLAGS = \ +libgnunettesting_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 0:1:0 -bin_PROGRAMS = \ - gnunet-testing - check_PROGRAMS = \ - test_testing \ - test_testing_connect \ - test_testing_reconnect \ - test_testing_group \ - test_testing_peergroup \ - test_testing_topology_stability \ - test_testing_topology_clique \ - test_testing_topology_clique_random \ - test_testing_topology_clique_minimum \ - test_testing_topology_clique_dfs \ - test_testing_topology_churn \ - test_testing_topology_line \ - test_testing_topology_blacklist \ - test_testing_group_remote \ - test_testing_2dtorus \ - test_testing_topology_ring \ - test_testing_topology_2d_torus \ - test_testing_topology_small_world_ring \ - test_testing_topology_small_world_torus \ - test_testing_topology_erdos_renyi \ - test_testing_topology_internat \ - test_testing_topology_none \ - test_testing_topology_scale_free \ test_testing_new_portreservation \ test_testing_new_peerstartup \ test_testing_new_servicestartup if ENABLE_TEST_RUN TESTS = \ - test_testing \ - test_testing_connect \ - test_testing_reconnect \ - test_testing_group \ - test_testing_peergroup \ test_testing_new_portreservation \ test_testing_new_peerstartup \ test_testing_new_servicestartup endif -gnunet_testing_SOURCES = \ - gnunet-testing.c -gnunet_testing_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) -gnunet_testing_DEPENDENCIES = \ - libgnunettesting.la - - -test_testing_SOURCES = \ - test_testing.c -test_testing_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_connect_SOURCES = \ - test_testing_connect.c -test_testing_connect_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_reconnect_SOURCES = \ - test_testing_reconnect.c -test_testing_reconnect_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_group_SOURCES = \ - test_testing_group.c -test_testing_group_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_peergroup_SOURCES = \ - test_testing_peergroup.c -test_testing_peergroup_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_clique_SOURCES = \ - test_testing_topology.c -test_testing_topology_clique_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_stability_SOURCES = \ - test_testing_topology.c -test_testing_topology_stability_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_blacklist_SOURCES = \ - test_testing_topology_blacklist.c -test_testing_topology_blacklist_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_churn_SOURCES = \ - test_testing_topology_churn.c -test_testing_topology_churn_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_clique_random_SOURCES = \ - test_testing_topology.c -test_testing_topology_clique_random_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_clique_minimum_SOURCES = \ - test_testing_topology.c -test_testing_topology_clique_minimum_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_clique_dfs_SOURCES = \ - test_testing_topology.c -test_testing_topology_clique_dfs_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_line_SOURCES = \ - test_testing_topology.c -test_testing_topology_line_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - - -test_testing_group_remote_SOURCES = \ - test_testing_group_remote.c -test_testing_group_remote_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_2dtorus_SOURCES = \ - test_testing_2dtorus.c -test_testing_2dtorus_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_ring_SOURCES = \ - test_testing_topology.c -test_testing_topology_ring_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_2d_torus_SOURCES = \ - test_testing_topology.c -test_testing_topology_2d_torus_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_small_world_ring_SOURCES = \ - test_testing_topology.c -test_testing_topology_small_world_ring_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_small_world_torus_SOURCES = \ - test_testing_topology.c -test_testing_topology_small_world_torus_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_internat_SOURCES = \ - test_testing_topology.c -test_testing_topology_internat_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_erdos_renyi_SOURCES = \ - test_testing_topology.c -test_testing_topology_erdos_renyi_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_scale_free_SOURCES = \ - test_testing_topology.c -test_testing_topology_scale_free_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_testing_topology_none_SOURCES = \ - test_testing_topology.c -test_testing_topology_none_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la - test_testing_new_portreservation_SOURCES = \ test_testing_new_portreservation.c test_testing_new_portreservation_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting_new.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_peerstartup_SOURCES = \ test_testing_new_peerstartup.c test_testing_new_peerstartup_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting_new.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la test_testing_new_servicestartup_SOURCES = \ test_testing_new_servicestartup.c test_testing_new_servicestartup_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting_new.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/util/libgnunetutil.la -EXTRA_DIST = \ - test_testing_defaults.conf \ - test_testing_data.conf \ - test_testing_connect_peer1.conf \ - test_testing_connect_peer2.conf \ - test_testing_2dtorus.conf \ - test_testing_data_topology_clique.conf \ - test_testing_data_topology_clique_random.conf \ - test_testing_data_topology_clique_minimum.conf \ - test_testing_data_topology_clique_dfs.conf \ - test_testing_data_topology_ring.conf \ - test_testing_data_topology_2d_torus.conf \ - test_testing_data_topology_small_world_ring.conf \ - test_testing_data_topology_small_world_torus.conf \ - test_testing_data_topology_erdos_renyi.conf \ - test_testing_data_topology_internat.conf \ - test_testing_data_topology_scale_free.conf \ - test_testing_data_topology_blacklist.conf \ - test_testing_data_topology_churn.conf \ - test_testing_data_topology_none.conf \ - test_testing_data_remote.conf \ - test_testing_data_topology_stability.conf \ - test_testing_peergroup_data.conf diff --git a/src/testing/gnunet-testing-remote-peer-start.pl b/src/testing/gnunet-testing-remote-peer-start.pl deleted file mode 100755 index e4f72e9d0..000000000 --- a/src/testing/gnunet-testing-remote-peer-start.pl +++ /dev/null @@ -1,92 +0,0 @@ -# -# This file is part of GNUnet -# (C) 2008, 2009 Christian Grothoff (and other contributing authors) -# -# GNUnet is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; either version 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 contrib/peerStartHelper.pl -# @brief Helper process for starting gnunet-testing peers. -# @author Nathan Evans -# -# Finds configuration files (or any files) of the format -# /path/*/gnunet-testing-config* and runs gnunet-arm with -# each as the given configuration. -# -# usage: peerStartHelper.pl /path/to/testing_dir/ -#!/usr/bin/perl -use strict; - -my $max_outstanding = 300; - -$ARGV[0] || die "No directory provided for peer information, exiting!\n"; - -my $directory = $ARGV[0]; -my @config_files = `find $directory -iname gnunet-testing-config*`; -my @child_arr = {}; -my $count = 0; -my $outstanding = 0; -foreach my $file (@config_files) -{ - chomp($file); - #print "Starting GNUnet peer with config file $file\n"; - my $pid = fork(); - if ($pid == -1) - { - die; - } - elsif ($pid == 0) - { - exec "gnunet-arm -q -c $file -s" or die; - } - - if ($pid != 0) - { - push @child_arr, $pid; - $count++; - $outstanding++; - if ($outstanding > $max_outstanding) - { - for (my $i = 0; $i < $max_outstanding / 5; $i++) - { - #print "Too many outstanding peers, waiting!\n"; - waitpid($child_arr[0], 0); - shift(@child_arr); - $outstanding--; - } - } - } -} - -print "All $count peers started (waiting for them to finish!\n"; - -while ($outstanding > 0) -{ - waitpid($child_arr[0], 0); - shift(@child_arr); - $outstanding--; - if ($outstanding % 50 == 0) - { - print "All $count peers started (waiting for $outstanding to finish!\n"; - } -} - -while (wait() != -1) {sleep 1} - -print "All $count peers started!\n"; - - diff --git a/src/testing/gnunet-testing.c b/src/testing/gnunet-testing.c deleted file mode 100644 index bdbb5e8c5..000000000 --- a/src/testing/gnunet-testing.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/gnunet-testing.c - * @brief tool to use testing functionality from cmd line - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_getopt_lib.h" -#include "gnunet_program_lib.h" -#include "gnunet_testing_lib.h" - -#define HOSTKEYFILESIZE 914 - -/** - * Final status code. - */ -static int ret; - -static unsigned int create_hostkey; - -static unsigned int create_cfg; - -static int create_no; - -static char * create_cfg_template; - -static char * create_hostkey_file; - -static int -create_unique_cfgs (const char * template, const unsigned int no) -{ - int fail = GNUNET_NO; - - uint16_t port = 20000; - uint32_t upnum = 1; - uint32_t fdnum = 1; - - if (GNUNET_NO == GNUNET_DISK_file_test(template)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Configuration template `%s': file not found\n", create_cfg_template); - return 1; - } - - int cur = 0; - char * cur_file; - char *service_home = NULL; - char *cur_service_home = NULL; - - struct GNUNET_CONFIGURATION_Handle *cfg_new = NULL; - struct GNUNET_CONFIGURATION_Handle *cfg_tmpl = GNUNET_CONFIGURATION_create(); - - /* load template */ - if ((create_cfg_template != NULL) && (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, create_cfg_template))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load template `%s'\n", create_cfg_template); - GNUNET_CONFIGURATION_destroy(cfg_tmpl); - - return 1; - } - /* load defaults */ - else if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, NULL)) - { - GNUNET_break (0); - return 1; - } - - if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg_tmpl, "PATHS", "SERVICEHOME", &service_home)) - { - GNUNET_asprintf(&service_home, "%s", "/tmp/testing"); - } - else - { - int s = strlen (service_home); - if (service_home[s-1] == DIR_SEPARATOR) - service_home[s-1] = '\0'; - } - - while (cur < no) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating configuration no. %u \n", cur); - if (create_cfg_template != NULL) - GNUNET_asprintf (&cur_file,"%04u-%s",cur, create_cfg_template); - else - GNUNET_asprintf (&cur_file,"%04u%s",cur, ".conf"); - - - GNUNET_asprintf (&cur_service_home, "%s-%04u%c",service_home, cur, DIR_SEPARATOR); - GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","SERVICEHOME", cur_service_home); - GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","DEFAULTCONFIG", cur_file); - GNUNET_free (cur_service_home); - - cfg_new = GNUNET_TESTING_create_cfg(cfg_tmpl, cur, &port, &upnum, NULL, &fdnum); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing configuration no. %u to file `%s' \n", cur, cur_file); - if (GNUNET_OK != GNUNET_CONFIGURATION_write(cfg_new, cur_file)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write configuration no. %u \n", cur); - fail = GNUNET_YES; - } - - GNUNET_CONFIGURATION_destroy (cfg_new); - GNUNET_free (cur_file); - if (fail == GNUNET_YES) - break; - cur ++; - } - - GNUNET_CONFIGURATION_destroy(cfg_tmpl); - GNUNET_free (service_home); - if (fail == GNUNET_NO) - return 0; - else - return 1; -} - -static int -create_hostkeys (const unsigned int no) -{ - struct GNUNET_DISK_FileHandle *fd; - int cur = 0; - uint64_t fs; - uint64_t total_hostkeys; - char *hostkey_data; - char *hostkey_src_file; - char *hostkey_dest_file; - - /* prepare hostkeys */ - if (create_hostkey_file == NULL) - hostkey_src_file = "../../contrib/testing_hostkeys.dat"; - else - { - hostkey_src_file = create_hostkey_file; - } - - if (GNUNET_YES != GNUNET_DISK_file_test (hostkey_src_file)) - { - if (create_hostkey_file == NULL) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file, specify hostkey file with -H!\n")); - else - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Specified hostkey file `%s' not found!\n"), create_hostkey_file); - return 1; - } - else - { - /* Check hostkey file size, read entire thing into memory */ - fd = GNUNET_DISK_file_open (hostkey_src_file, GNUNET_DISK_OPEN_READ, - GNUNET_DISK_PERM_NONE); - if (NULL == fd) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkey_src_file); - return 1; - } - - if (GNUNET_OK != GNUNET_DISK_file_size (hostkey_src_file, &fs, GNUNET_YES, GNUNET_YES)) - fs = 0; - - if (0 != (fs % HOSTKEYFILESIZE)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "File size %llu seems incorrect for hostkeys...\n", fs); - } - else - { - total_hostkeys = fs / HOSTKEYFILESIZE; - hostkey_data = GNUNET_malloc_large (fs); - GNUNET_assert (fs == GNUNET_DISK_file_read (fd, hostkey_data, fs)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Read %llu hostkeys from file\n", total_hostkeys); - } - GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); - } - - while (cur < no) - { - GNUNET_asprintf (&hostkey_dest_file, "%04u-hostkey",cur); - GNUNET_assert (GNUNET_OK == - GNUNET_DISK_directory_create_for_file (hostkey_dest_file)); - fd = GNUNET_DISK_file_open (hostkey_dest_file, - GNUNET_DISK_OPEN_READWRITE | - GNUNET_DISK_OPEN_CREATE, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - GNUNET_assert (fd != NULL); - GNUNET_assert (HOSTKEYFILESIZE == - GNUNET_DISK_file_write (fd, &hostkey_data[cur * HOSTKEYFILESIZE], HOSTKEYFILESIZE)); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", - "Wrote hostkey to file: `%s' \n", hostkey_dest_file); - GNUNET_free (hostkey_dest_file); - cur ++; - } - - GNUNET_free (hostkey_data); - - return 0; -} - -/** - * 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 cfg configuration - */ -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - /* main code here */ - if (create_cfg == GNUNET_YES) - { - if (create_no > 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u configuration files based on template `%s'\n", create_no, create_cfg_template); - ret = create_unique_cfgs (create_cfg_template, create_no); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); - ret = 1; - } - } - - if (create_hostkey == GNUNET_YES) - { - if (create_no > 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u hostkeys \n", create_no); - ret = create_hostkeys (create_no); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); - ret = 1; - } - } - - GNUNET_free_non_null (create_cfg_template); -} - - -/** - * The main function. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'C', "cfg", NULL, gettext_noop ("create unique configuration files"), - GNUNET_NO, &GNUNET_GETOPT_set_one, &create_cfg}, - {'k', "key", NULL, gettext_noop ("create hostkey files from pre-computed hostkey list"), - GNUNET_NO, &GNUNET_GETOPT_set_one, &create_hostkey}, - {'H', "hostkeys", NULL, gettext_noop ("host key file"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &create_hostkey_file}, - {'n', "number", NULL, gettext_noop ("number of unique configuration files or hostkeys to create"), - GNUNET_YES, &GNUNET_GETOPT_set_uint, &create_no}, - {'t', "template", NULL, gettext_noop ("configuration template"), - GNUNET_YES, &GNUNET_GETOPT_set_string, &create_cfg_template}, - GNUNET_GETOPT_OPTION_END - }; - return (GNUNET_OK == - GNUNET_PROGRAM_run (argc, argv, "gnunet-testing", - gettext_noop ("Command line tool to access the testing library"), options, &run, - NULL)) ? ret : 1; -} - -/* end of gnunet-testing.c */ diff --git a/src/testing/helper.c b/src/testing/helper.c deleted file mode 100644 index ebb37ebe5..000000000 --- a/src/testing/helper.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - 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 testing/helper.c - * @brief helper functions for testing - * @author Christian Grothoff - * - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - - - - -/** - * Obtain the peer identity of the peer with the given configuration - * handle. This function reads the private key of the peer, obtains - * the public key and hashes it. - * - * @param cfg configuration of the peer - * @param pid where to store the peer identity - * @return GNUNET_OK on success, GNUNET_SYSERR on failure - */ -int -GNUNET_TESTING_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_PeerIdentity *pid) -{ - char *keyfile; - struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", - &keyfile)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ - ("Peer is lacking HOSTKEY configuration setting.\n")); - return GNUNET_SYSERR; - } - my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); - GNUNET_free (keyfile); - if (my_private_key == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not access hostkey.\n")); - return GNUNET_SYSERR; - } - GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); - GNUNET_CRYPTO_rsa_key_free (my_private_key); - GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), - &pid->hashPubKey); - return GNUNET_OK; -} - - -/* end of helper.c */ diff --git a/src/testing/test_testing.c b/src/testing/test_testing.c deleted file mode 100644 index 3e2cd65ee..000000000 --- a/src/testing/test_testing.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing.c - * @brief testcase for testing.c - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - -#define VERBOSE GNUNET_YES - -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -static int ok; - -static void -end_cb (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); - ok = 1; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon terminated, will now exit.\n"); -#endif - ok = 0; - } -} - - - -void -do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TESTING_Daemon *d = cls; - - GNUNET_TESTING_daemon_stop (d, TIMEOUT, &end_cb, NULL, GNUNET_YES, GNUNET_NO); -} - - -static void -my_cb (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - GNUNET_assert (id != NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Daemon `%s' started, will now stop it.\n", GNUNET_i2s (id)); -#endif - GNUNET_SCHEDULER_add_now (&do_shutdown, d); -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_TESTING_Daemon *d; - - ok = 1; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); -#endif - d = GNUNET_TESTING_daemon_start (cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, - NULL, NULL, &my_cb, NULL); - GNUNET_assert (d != NULL); -} - -static int -check () -{ - char *const argv[] = { "test-testing", - "-c", - "test_testing_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing", "nohelp", options, &run, &ok); - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test-testing", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - - return ret; -} - -/* end of test_testing.c */ diff --git a/src/testing/test_testing_2dtorus.c b/src/testing/test_testing_2dtorus.c deleted file mode 100644 index 00a66d65c..000000000 --- a/src/testing/test_testing_2dtorus.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2011 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 testing/test_testing_2dtorus.c - * - * @brief Test for creating a 2dtorus. - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - -#define VERBOSE GNUNET_YES -#define REMOVE_DIR GNUNET_YES - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) - -/** - * Time to wait for stuff that should be rather fast - */ -#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - - -/** - * How many events have happened - */ -static int ok; - -/** - * Be verbose - */ -static int verbose; - -/** - * Total number of peers in the test. - */ -static unsigned long long num_peers; - -/** - * Global configuration file - */ -static struct GNUNET_CONFIGURATION_Handle *testing_cfg; - -/** - * Total number of currently running peers. - */ -static unsigned long long peers_running; - -/** - * Total number of successful connections in the whole network. - */ -static unsigned int total_connections; - -/** - * Total number of counted topo connections - */ -static unsigned int topo_connections; - -/** - * Total number of failed connections in the whole network. - */ -static unsigned int failed_connections; - -/** - * The currently running peer group. - */ -static struct GNUNET_TESTING_PeerGroup *pg; - -/** - * Task called to disconnect peers - */ -static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; - -/** - * Task called to shutdown test. - */ -static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; - - -/** - * Check whether peers successfully shut down. - */ -static void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n"); -#endif - ok--; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "test: All peers successfully shut down!\n"); -#endif - } -} - - -static void -shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); -#endif - - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - GNUNET_CONFIGURATION_destroy (testing_cfg); -} - - -static void -disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); - - if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) - { - GNUNET_SCHEDULER_cancel (shutdown_handle); - shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); - } -} - - -/** - * Prototype of a callback function indicating that two peers - * are currently connected. - * - * @param cls closure - * @param first peer id for first daemon - * @param second peer id for the second daemon - * @param distance distance between the connected peers - * @param emsg error message (NULL on success) - */ -void -topo_cb (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, const char *emsg) -{ - topo_connections++; - if (NULL != emsg) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error by topo %u: %s\n", - topo_connections, emsg); - } - else - { - if (first == NULL || second == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u NULL\n", - topo_connections); - if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (disconnect_task); - GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); - } - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u ok\n", - topo_connections); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (first)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (second)); - } -} - - -/** - * peergroup_ready: start test when all peers are connected - * @param cls closure - * @param emsg error message - */ -static void -peergroup_ready (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "test: Peergroup callback called with error, aborting test!\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", - emsg); - ok--; - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - return; - } -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "************************************************************\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "test: Peer Group started successfully!\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", - total_connections); -#endif - - peers_running = GNUNET_TESTING_daemons_running (pg); - if (0 < failed_connections) - { - ok = GNUNET_SYSERR; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n", - failed_connections); - disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); - - } - else - { - GNUNET_TESTING_get_topology (pg, &topo_cb, NULL); - disconnect_task = - GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL); - ok = GNUNET_OK; - } - -} - - -/** - * Function that will be called whenever two daemons are connected by - * the testing library. - * - * @param cls closure - * @param first peer id for first daemon - * @param second peer id for the second daemon - * @param distance distance between the connected peers - * @param first_cfg config for the first daemon - * @param second_cfg config for the second daemon - * @param first_daemon handle for the first daemon - * @param second_daemon handle for the second daemon - * @param emsg error message (NULL on success) - */ -static void -connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, uint32_t distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) -{ - if (emsg == NULL) - { - total_connections++; - } - else - { - failed_connections++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "test: Problem with new connection (%s)\n", emsg); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (first)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (second)); - } - -} - - -/** - * run: load configuration options and schedule test to run (start peergroup) - * @param cls closure - * @param args argv - * @param cfgfile configuration file name (can be NULL) - * @param cfg configuration handle - */ -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_TESTING_Host *hosts; - - ok = GNUNET_NO; - total_connections = 0; - failed_connections = 0; - testing_cfg = GNUNET_CONFIGURATION_dup (cfg); - - GNUNET_log_setup ("test_testing_2dtorus", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); - GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", - "use_progressbars", "YES"); -#endif - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", - "num_peers", &num_peers)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Option TESTING:NUM_PEERS is required!\n"); - return; - } - - hosts = GNUNET_TESTING_hosts_load (testing_cfg); - - pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, - &connect_cb, &peergroup_ready, NULL, - hosts); - GNUNET_assert (pg != NULL); - shutdown_handle = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, - &shutdown_task, NULL); -} - - -/** - * test_testing_2dtorus command line options - */ -static struct GNUNET_GETOPT_CommandLineOption options[] = { - {'V', "verbose", NULL, - gettext_noop ("be verbose (print progress information)"), - 0, &GNUNET_GETOPT_set_one, &verbose}, - GNUNET_GETOPT_OPTION_END -}; - - -/** - * Main: start test - */ -int -main (int argc, char *argv[]) -{ - char *const argv2[] = { - argv[0], - "-c", - "test_testing_2dtorus.conf", -#if VERBOSE - "-L", - "DEBUG", -#endif - NULL - }; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n"); - - - GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, - "test_testing_2dtorus", - gettext_noop ("Test testing 2d torus."), options, &run, - NULL); -#if REMOVE_DIR - GNUNET_DISK_directory_remove ("/tmp/test_testing_2dtorus"); -#endif - if (GNUNET_OK != ok) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); - return 1; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n"); - return 0; -} - -/* end of test_testing_2dtorus.c */ diff --git a/src/testing/test_testing_2dtorus.conf b/src/testing/test_testing_2dtorus.conf deleted file mode 100644 index 54bb7c5a7..000000000 --- a/src/testing/test_testing_2dtorus.conf +++ /dev/null @@ -1,81 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -SERVICEHOME = /tmp/test_testing_2dtorus/ -DEFAULTCONFIG = test_testing_2dtorus.conf - -[arm] -PORT = 10010 -DEFAULTSERVICES = core -#DEBUG = YES - -[statistics] -AUTOSTART = YES -PORT = 10000 - -[dht] -DEBUG = NO -AUTOSTART = YES -ACCEPT_FROM6 = ::1; -ACCEPT_FROM = 127.0.0.1; -HOSTNAME = localhost -PORT = 10001 - -[nse] -WORKBITS = 0 - -[dns] -AUTOSTART = NO -PORT = 10011 - -[transport] -PORT = 10002 -AUTOSTART = YES -PLUGINS = tcp - -[nat] -DISABLEV6 = YES -BINDTO = 127.0.0.1 -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 - -[ats] -WAN_QUOTA_IN = 1 GB -WAN_QUOTA_OUT = 1 GB - -[core] -AUTOSTART = YES -PORT = 10003 - -[peerinfo] -AUTOSTART = YES -PORT = 10004 - -[testing] -NUM_PEERS = 16 -WEAKRANDOM = YES -TOPOLOGY = 2D_TORUS -CONNECT_TOPOLOGY = 2D_TORUS -#TOPOLOGY_FILE = small.dat -CONNECT_TOPOLOGY = 2D_TORUS -#CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM -#CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 -#PERCENTAGE = 3 -#PROBABILITY = .1 -F2F = NO -CONNECT_TIMEOUT = 600 s -CONNECT_ATTEMPTS = 2 -DEBUG = YES -HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat -MAX_CONCURRENT_SSH = 10 -USE_PROGRESSBARS = YES -PEERGROUP_TIMEOUT = 2400 s -TOPOLOGY_OUTPUT_FILE = testing_topo_initial -MAX_OUTSTANDING_CONNECTIONS = 75 -#SINGLE_PEERINFO_PER_HOST = YES -#NUM_PEERINFO_PER_HOST = 10 -#SINGLE_STATISTICS_PER_HOST = YES -#NUM_STATISTICS_PER_HOST = 10 -DELETE_FILES = YES diff --git a/src/testing/test_testing_connect.c b/src/testing/test_testing_connect.c deleted file mode 100644 index c69c20326..000000000 --- a/src/testing/test_testing_connect.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_connect.c - * @brief testcase for functions to connect two peers in testing.c - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - -#define VERBOSE GNUNET_NO - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -#define CONNECT_ATTEMPTS 3 - -static int ok; - -static struct GNUNET_TESTING_Daemon *d1; - -static struct GNUNET_TESTING_Daemon *d2; - -static struct GNUNET_CONFIGURATION_Handle *c1; - -static struct GNUNET_CONFIGURATION_Handle *c2; - -static struct GNUNET_TESTING_ConnectContext *cc; - -static void -end2_cb (void *cls, const char *emsg) -{ - - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); - ok = 1; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Both daemons terminated, will now exit.\n"); -#endif - ok = 0; - } -} - -static void -end1_cb (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", - emsg); - ok = 1; - } - else - { - ok = 0; - } - - GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, GNUNET_YES, - GNUNET_NO); - d2 = NULL; -} - -static void -finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, GNUNET_YES, - GNUNET_NO); - d1 = NULL; -} - -static void -my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, - unsigned int distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - cc = NULL; - GNUNET_SCHEDULER_add_now (&finish_testing, NULL); -} - - -static void -my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - GNUNET_assert (id != NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", - GNUNET_i2s (id)); -#endif - cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, - GNUNET_YES, &my_connect_complete, NULL); -} - - -static void -my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - GNUNET_assert (id != NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", - GNUNET_i2s (id)); -#endif - d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, - NULL, NULL, &my_cb2, NULL); - GNUNET_assert (d2 != NULL); - -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - ok = 1; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); -#endif - c1 = GNUNET_CONFIGURATION_create (); - GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_load (c1, - "test_testing_connect_peer1.conf")); - c2 = GNUNET_CONFIGURATION_create (); - GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_load (c2, - "test_testing_connect_peer2.conf")); - d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, - NULL, NULL, &my_cb1, NULL); - GNUNET_assert (d1 != NULL); -} - -static int -check () -{ - char *const argv[] = { "test-testing", - "-c", - "test_testing_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing-connect", "nohelp", options, &run, &ok); - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test-testing-connect", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - return ret; -} - -/* end of test_testing_connect.c */ diff --git a/src/testing/test_testing_connect_peer1.conf b/src/testing/test_testing_connect_peer1.conf deleted file mode 100644 index cccda5e2a..000000000 --- a/src/testing/test_testing_connect_peer1.conf +++ /dev/null @@ -1,37 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -SERVICEHOME = /tmp/test-gnunet-testing-connect-peer1/ -DEFAULTCONFIG = test_testing_connect_peer1.conf - -[transport-tcp] -PORT = 12568 - -[arm] -PORT = 12566 -DEFAULTSERVICES = core -UNIXPATH = /tmp/gnunet-p1-service-arm.sock - -[statistics] -PORT = 12567 -UNIXPATH = /tmp/gnunet-p1-service-statistics.sock - -[resolver] -PORT = 12564 -UNIXPATH = /tmp/gnunet-p1-service-resolver.sock - -[peerinfo] -PORT = 12569 -UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock - -[transport] -PORT = 12565 -UNIXPATH = /tmp/gnunet-p1-service-transport.sock - -[core] -PORT = 12570 -UNIXPATH = /tmp/gnunet-p1-service-core.sock - -[ats] -PORT = 12571 -UNIXPATH = /tmp/gnunet-p1-service-ats.sock - diff --git a/src/testing/test_testing_connect_peer2.conf b/src/testing/test_testing_connect_peer2.conf deleted file mode 100644 index 08ec55113..000000000 --- a/src/testing/test_testing_connect_peer2.conf +++ /dev/null @@ -1,37 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -SERVICEHOME = /tmp/test-gnunet-testing-connect-peer2/ -DEFAULTCONFIG = test_testing_connect_peer2.conf - -[transport-tcp] -PORT = 22568 - -[arm] -PORT = 22566 -DEFAULTSERVICES = core -UNIXPATH = /tmp/gnunet-p2-service-arm.sock - -[statistics] -PORT = 22567 -UNIXPATH = /tmp/gnunet-p2-service-statistics.sock - -[resolver] -PORT = 22564 -UNIXPATH = /tmp/gnunet-p2-service-resolver.sock - -[peerinfo] -PORT = 22569 -UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock - -[transport] -PORT = 22565 -UNIXPATH = /tmp/gnunet-p2-service-transport.sock - -[core] -PORT = 22570 -UNIXPATH = /tmp/gnunet-p2-service-core.sock - -[ats] -PORT = 22571 -UNIXPATH = /tmp/gnunet-p2-service-ats.sock - diff --git a/src/testing/test_testing_data.conf b/src/testing/test_testing_data.conf deleted file mode 100644 index c46cb0d42..000000000 --- a/src/testing/test_testing_data.conf +++ /dev/null @@ -1,7 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data.conf - -[arm] -DEFAULTSERVICES = core - diff --git a/src/testing/test_testing_data_remote.conf b/src/testing/test_testing_data_remote.conf deleted file mode 100644 index d58666f31..000000000 --- a/src/testing/test_testing_data_remote.conf +++ /dev/null @@ -1,12 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_remote.conf - -[TESTING] -CONTROL_HOST = 127.0.0.1 -HOSTFILE = remote_hosts.txt -MAX_OUTSTANDING_SSH = 5 - -[statistics] -AUTOSTART = NO - diff --git a/src/testing/test_testing_data_topology_2d_torus.conf b/src/testing/test_testing_data_topology_2d_torus.conf deleted file mode 100644 index cbdaceb5a..000000000 --- a/src/testing/test_testing_data_topology_2d_torus.conf +++ /dev/null @@ -1,7 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_2d_torus.conf - -[TESTING] -NUM_PEERS = 13 -TOPOLOGY = 2D_TORUS diff --git a/src/testing/test_testing_data_topology_blacklist.conf b/src/testing/test_testing_data_topology_blacklist.conf deleted file mode 100644 index 36e378d42..000000000 --- a/src/testing/test_testing_data_topology_blacklist.conf +++ /dev/null @@ -1,13 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_blacklist.conf - -[TESTING] -NUM_PEERS = 4 -TOPOLOGY = CLIQUE -BLACKLIST_TOPOLOGY = RING -BLACKLIST_TRANSPORTS = tcp udp http - -[transport-udp] -PORT = 2568 - diff --git a/src/testing/test_testing_data_topology_churn.conf b/src/testing/test_testing_data_topology_churn.conf deleted file mode 100644 index b3371658d..000000000 --- a/src/testing/test_testing_data_topology_churn.conf +++ /dev/null @@ -1,10 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_churn.conf - -[TESTING] -NUM_PEERS = 12 - -[arm] -DEFAULTSERVICES = peerinfo transport core - diff --git a/src/testing/test_testing_data_topology_clique.conf b/src/testing/test_testing_data_topology_clique.conf deleted file mode 100644 index 69cecb7e9..000000000 --- a/src/testing/test_testing_data_topology_clique.conf +++ /dev/null @@ -1,10 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -CONNECT_TIMEOUT = 180 s -CONNECT_ATTEMPTS = 14 -NUM_PEERS = 4 -TOPOLOGY = CLIQUE -SETTLE_TIME = 0 diff --git a/src/testing/test_testing_data_topology_clique_dfs.conf b/src/testing/test_testing_data_topology_clique_dfs.conf deleted file mode 100644 index c7abeae5e..000000000 --- a/src/testing/test_testing_data_topology_clique_dfs.conf +++ /dev/null @@ -1,13 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -NUM_PEERS = 7 -TOPOLOGY = CLIQUE -CONNECT_TOPOLOGY_OPTION = CONNECT_DFS -CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 - -[arm] -DEFAULTSERVICES = peerinfo transport core - diff --git a/src/testing/test_testing_data_topology_clique_minimum.conf b/src/testing/test_testing_data_topology_clique_minimum.conf deleted file mode 100644 index ef95cb1fd..000000000 --- a/src/testing/test_testing_data_topology_clique_minimum.conf +++ /dev/null @@ -1,10 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -NUM_PEERS = 20 -TOPOLOGY = CLIQUE -CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM -CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 - diff --git a/src/testing/test_testing_data_topology_clique_random.conf b/src/testing/test_testing_data_topology_clique_random.conf deleted file mode 100644 index cd44b65f0..000000000 --- a/src/testing/test_testing_data_topology_clique_random.conf +++ /dev/null @@ -1,16 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -NUM_PEERS = 20 -TOPOLOGY = CLIQUE -CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET -CONNECT_TOPOLOGY_OPTION_MODIFIER = .15 - -[statistics] -AUTOSTART = NO - -[resolver] -AUTOSTART = NO - diff --git a/src/testing/test_testing_data_topology_erdos_renyi.conf b/src/testing/test_testing_data_topology_erdos_renyi.conf deleted file mode 100644 index 8e1741352..000000000 --- a/src/testing/test_testing_data_topology_erdos_renyi.conf +++ /dev/null @@ -1,7 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -TOPOLOGY = ERDOS_RENYI - diff --git a/src/testing/test_testing_data_topology_internat.conf b/src/testing/test_testing_data_topology_internat.conf deleted file mode 100644 index af3f62f39..000000000 --- a/src/testing/test_testing_data_topology_internat.conf +++ /dev/null @@ -1,7 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -TOPOLOGY = INTERNAT - diff --git a/src/testing/test_testing_data_topology_none.conf b/src/testing/test_testing_data_topology_none.conf deleted file mode 100644 index dbee5d0b9..000000000 --- a/src/testing/test_testing_data_topology_none.conf +++ /dev/null @@ -1,37 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -NUM_PEERS = 1000 -TOPOLOGY = NONE -F2F = NO -BLACKLIST_TOPOLOGY = NONE -CONNECT_TOPOLOGY = RING - -[arm] -PORT = 0 - -[statistics] -AUTOSTART = NO -PORT = 0 - -[resolver] -AUTOSTART = NO -PORT = 0 - -[peerinfo] -PORT = 0 - -[transport] -PORT = 0 - -[core] -PORT = 0 - -[topology] -PORT = 0 - -[hostlist] -PORT = 0 - diff --git a/src/testing/test_testing_data_topology_ring.conf b/src/testing/test_testing_data_topology_ring.conf deleted file mode 100644 index 6159030f4..000000000 --- a/src/testing/test_testing_data_topology_ring.conf +++ /dev/null @@ -1,7 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -TOPOLOGY = RING - diff --git a/src/testing/test_testing_data_topology_scale_free.conf b/src/testing/test_testing_data_topology_scale_free.conf deleted file mode 100644 index 7690eac29..000000000 --- a/src/testing/test_testing_data_topology_scale_free.conf +++ /dev/null @@ -1,11 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_scale_free.conf - -[TESTING] -NUM_PEERS = 50 -TOPOLOGY = SCALE_FREE - -[arm] -DEFAULTSERVICES = peerinfo transport core - diff --git a/src/testing/test_testing_data_topology_small_world_ring.conf b/src/testing/test_testing_data_topology_small_world_ring.conf deleted file mode 100644 index 01931df6d..000000000 --- a/src/testing/test_testing_data_topology_small_world_ring.conf +++ /dev/null @@ -1,8 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -NUM_PEERS = 25 -TOPOLOGY = SMALL_WORLD_RING - diff --git a/src/testing/test_testing_data_topology_small_world_torus.conf b/src/testing/test_testing_data_topology_small_world_torus.conf deleted file mode 100644 index 7c35454de..000000000 --- a/src/testing/test_testing_data_topology_small_world_torus.conf +++ /dev/null @@ -1,7 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -TOPOLOGY = SMALL_WORLD - diff --git a/src/testing/test_testing_data_topology_stability.conf b/src/testing/test_testing_data_topology_stability.conf deleted file mode 100644 index 1bfcd1bde..000000000 --- a/src/testing/test_testing_data_topology_stability.conf +++ /dev/null @@ -1,9 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_data_topology_clique.conf - -[TESTING] -SETTLE_TIME = 600 s -NUM_PEERS = 2 -TOPOLOGY = CLIQUE - diff --git a/src/testing/test_testing_defaults.conf b/src/testing/test_testing_defaults.conf deleted file mode 100644 index ba7e269a6..000000000 --- a/src/testing/test_testing_defaults.conf +++ /dev/null @@ -1,78 +0,0 @@ -[PATHS] -SERVICEHOME = /tmp/test-gnunet-testing/ -DEFAULTCONFIG = test_testing_defaults.conf - -[resolver] -PORT = 2564 - -[transport] -PORT = 2565 -PLUGINS = tcp - -[arm] -PORT = 2566 -DEFAULTSERVICES = - -[statistics] -PORT = 2567 - -[transport-tcp] -PORT = 2568 -BINDTO = 127.0.0.1 - -[peerinfo] -PORT = 2569 - -[core] -PORT = 2570 - -[testing] -NUM_PEERS = 5 -WEAKRANDOM = YES -F2F = YES -HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat - -[dht] -AUTOSTART = NO - -[nat] -DISABLEV6 = YES -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 -USE_LOCALADDR = NO - -[dns] -AUTOSTART = NO - -[nse] -AUTOSTART = NO - -[mesh] -AUTOSTART = NO - -[datastore] -AUTOSTART = NO - -[fs] -AUTOSTART = NO - -[dv] -AUTOSTART = NO - -[chat] -AUTOSTART = NO - -[vpn] -AUTOSTART = NO - -[gns] -AUTOSTART = NO - -[namestore] -AUTOSTART = NO - -[lockmanager] -AUTOSTART = NO diff --git a/src/testing/test_testing_group.c b/src/testing/test_testing_group.c deleted file mode 100644 index f5df45b19..000000000 --- a/src/testing/test_testing_group.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_group.c - * @brief testcase for functions to connect peers in testing.c - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - -#define VERBOSE GNUNET_NO - -#define NUM_PEERS 4 - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -static int ok; - -static int peers_left; - -static int failed_peers; - -static struct GNUNET_TESTING_PeerGroup *pg; - -/** - * Check whether peers successfully shut down. - */ -void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); -#endif - if (ok == 0) - ok = 666; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); -#endif - } -} - - -static void -my_cb (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (id == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Start callback called with error (too long starting peers), aborting test!\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); - failed_peers++; - if (failed_peers == peers_left) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Too many peers failed, ending test!\n"); - ok = 1; - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - } - return; - } - - peers_left--; - if (peers_left == 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All peers started successfully, ending test!\n"); - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - ok = 0; - } - else if (failed_peers == peers_left) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Too many peers failed, ending test!\n"); - ok = 1; - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - } -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - ok = 1; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); -#endif - peers_left = NUM_PEERS; - pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ - peers_left, /* Number of outstanding connections */ - peers_left, /* Number of parallel ssh connections, or peers being started at once */ - TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, - NULL, NULL); - GNUNET_assert (pg != NULL); -} - -static int -check () -{ - char *const argv[] = { "test-testing", - "-c", - "test_testing_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing-group", "nohelp", options, &run, &ok); - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test-testing-group", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - /** - * Still need to remove the base testing directory here, - * because group starts will create subdirectories under this - * main dir. However, we no longer need to sleep, as the - * shutdown sequence won't return until everything is cleaned - * up. - */ - GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); - return ret; -} - -/* end of test_testing_group.c */ diff --git a/src/testing/test_testing_group_remote.c b/src/testing/test_testing_group_remote.c deleted file mode 100644 index b06655ca4..000000000 --- a/src/testing/test_testing_group_remote.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_group_remote.c - * @brief testcase for testing remote and local starting and connecting - * of hosts from the testing library. The test_testing_data_remote.conf - * file should be modified if this testcase is intended to be used. - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - -#define VERBOSE GNUNET_YES - - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -#define DEFAULT_NUM_PEERS 8; - -static int ok; - -static int peers_left; - -static int peers_failed; - -static struct GNUNET_TESTING_PeerGroup *pg; - -static unsigned long long num_peers; - - -/** - * Check whether peers successfully shut down. - */ -void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Shutdown of peers failed (error %s)!\n", emsg); -#endif - if (ok == 0) - ok = 666; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); -#endif - } -} - - -static void -my_cb (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - peers_failed++; - } - - peers_left--; - if (peers_left == 0) - { - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - ok = 0; - } - else if (peers_failed == peers_left) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Too many peers failed, ending test!\n"); - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - } -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_TESTING_Host *hosts; - struct GNUNET_TESTING_Host *hostpos; - struct GNUNET_TESTING_Host *temphost; - char *hostfile; - struct stat frstat; - char *buf; - char *data; - int count; - int ret; - - ok = 1; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); -#endif - - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", - &num_peers)) - num_peers = DEFAULT_NUM_PEERS; - - GNUNET_assert (num_peers > 0 && num_peers < (unsigned long long) -1); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", - &hostfile)) - hostfile = NULL; - - hosts = NULL; - data = NULL; - if (hostfile != NULL) - { - if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) - GNUNET_DISK_fn_write (hostfile, NULL, 0, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not open file specified for host list, ending test!"); - ok = 1119; - GNUNET_free (hostfile); - return; - } - - data = GNUNET_malloc_large (frstat.st_size); - GNUNET_assert (data != NULL); - if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not read file %s specified for host list, ending test!", - hostfile); - GNUNET_free (hostfile); - GNUNET_free (data); - return; - } - - GNUNET_free_non_null (hostfile); - - buf = data; - count = 0; - while (count < frstat.st_size) - { - count++; - if (count >= frstat.st_size) - break; - - /* if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count])) */ - if (((data[count] == '\n')) && (buf != &data[count])) - { - data[count] = '\0'; - temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); - ret = - SSCANF (buf, "%a[a-zA-Z0-9]@%a[a-zA-Z0-9.]:%hd", - &temphost->username, &temphost->hostname, &temphost->port); - if (3 == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Successfully read host %s, port %d and user %s from file\n", - temphost->hostname, temphost->port, temphost->username); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Error reading line `%s' in hostfile\n", buf); - GNUNET_free (temphost); - buf = &data[count + 1]; - continue; - } - /* temphost->hostname = buf; */ - temphost->next = hosts; - hosts = temphost; - buf = &data[count + 1]; - } - else if ((data[count] == '\n') || (data[count] == '\0')) - buf = &data[count + 1]; - } - } - - peers_left = num_peers; - pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ - peers_left, /* Number of outstanding connections */ - peers_left, /* Number of parallel ssh connections, or peers being started at once */ - TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, - NULL, hosts); - hostpos = hosts; - while (hostpos != NULL) - { - temphost = hostpos->next; - GNUNET_free (hostpos->hostname); - GNUNET_free (hostpos->username); - GNUNET_free (hostpos); - hostpos = temphost; - } - GNUNET_free_non_null (data); - GNUNET_assert (pg != NULL); - -} - -static int -check () -{ - char *const argv[] = { "test-testing", - "-c", - "test_testing_data_remote.conf", -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing-group", "nohelp", options, &run, &ok); - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test-testing-group", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - /** - * Still need to remove the base testing directory here, - * because group starts will create subdirectories under this - * main dir. However, we no longer need to sleep, as the - * shutdown sequence won't return until everything is cleaned - * up. - */ - GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); - return ret; -} - -/* end of test_testing_group.c */ diff --git a/src/testing/test_testing_large_topology.c b/src/testing/test_testing_large_topology.c deleted file mode 100644 index cd80db195..000000000 --- a/src/testing/test_testing_large_topology.c +++ /dev/null @@ -1,1197 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_topology.c - * @brief base testcase for testing all the topologies provided - */ -#include "platform.h" -#include "gnunet_testing_lib.h" -#include "gnunet_core_service.h" -#include "gnunet_os_lib.h" - -#define VERBOSE GNUNET_YES - -#define DELAY_FOR_LOGGING GNUNET_NO - -#define SECONDS_PER_PEER_START 120 - -#define DEFAULT_NUM_PEERS 4 - -#define MAX_OUTSTANDING_CONNECTIONS 100 - -static float fail_percentage = 0.05; - -static int ok; - -struct GNUNET_TIME_Relative connect_timeout; - -static unsigned long long connect_attempts; - -static unsigned long long num_peers; - -static unsigned int topology_connections; - -static unsigned int total_connections; - -static unsigned int failed_connections; - -static unsigned int total_server_connections; - -static unsigned int total_messages_received; - -static unsigned int expected_messages; - -static unsigned int expected_connections; - -static unsigned long long peers_left; - -static struct GNUNET_TESTING_PeerGroup *pg; - -const struct GNUNET_CONFIGURATION_Handle *main_cfg; - -GNUNET_SCHEDULER_TaskIdentifier die_task; - -static char *dotOutFileName; - -static struct GNUNET_TIME_Relative settle_time; - -static FILE *dotOutFile; - -static char *topology_string; - -static char *blacklist_transports; - -static int transmit_ready_scheduled; - -static int transmit_ready_failed; - -static int transmit_ready_called; - -struct GNUNET_TIME_Relative test_timeout; - -struct GNUNET_TIME_Relative timeout; - -static unsigned int modnum; - -static unsigned int dotnum; - -static enum GNUNET_TESTING_Topology topology; - -static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ - -static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ - -static enum GNUNET_TESTING_TopologyOption connect_topology_option = - GNUNET_TESTING_TOPOLOGY_OPTION_ALL; - -static double connect_topology_option_modifier = 0.0; - -static char *test_directory; - -#define MTYPE 12345 - -GNUNET_NETWORK_STRUCT_BEGIN - -struct GNUNET_TestMessage -{ - /** - * Header of the message - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this message. - */ - uint32_t uid; -}; -GNUNET_NETWORK_STRUCT_END - -struct TestMessageContext -{ - /* This is a linked list */ - struct TestMessageContext *next; - - /* Handle to the sending peer core */ - struct GNUNET_CORE_Handle *peer1handle; - - /* Handle to the receiving peer core */ - struct GNUNET_CORE_Handle *peer2handle; - - /* Handle to the sending peer daemon */ - struct GNUNET_TESTING_Daemon *peer1; - - /* Handle to the receiving peer daemon */ - struct GNUNET_TESTING_Daemon *peer2; - - /* Identifier for this message, so we don't disconnect other peers! */ - uint32_t uid; - - /* Has peer1 been notified already of a connection to peer2? */ - int peer1notified; - - /* Has the core of peer2 been connected already? */ - int peer2connected; - - /* Task for disconnecting cores, allow task to be cancelled on shutdown */ - GNUNET_SCHEDULER_TaskIdentifier disconnect_task; - -}; - -static struct TestMessageContext *test_messages; - -/** - * Check whether peers successfully shut down. - */ -void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); -#endif - if (ok == 0) - ok = 666; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); -#endif - } -} - -#if DELAY_FOR_LOGGING -static void -gather_log_data () -{ - char *peer_number; - char *connect_number; - struct GNUNET_OS_Process *mem_process; - - GNUNET_asprintf (&peer_number, "%llu", num_peers); - GNUNET_asprintf (&connect_number, "%llu", expected_connections); - mem_process = - GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", - "totals.txt", peer_number, connect_number, NULL); - GNUNET_OS_process_wait (mem_process); - GNUNET_OS_process_destroy (mem_process); - mem_process = NULL; -} - -#endif - -static void -finish_testing () -{ - GNUNET_assert (pg != NULL); - struct TestMessageContext *pos; - struct TestMessageContext *free_pos; - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Called finish testing, stopping daemons.\n"); -#endif - - pos = test_messages; - while (pos != NULL) - { - if (pos->peer1handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer1handle); - pos->peer1handle = NULL; - } - if (pos->peer2handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer2handle); - pos->peer2handle = NULL; - } - free_pos = pos; - pos = pos->next; - if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); - } - GNUNET_free (free_pos); - } -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", - transmit_ready_scheduled, transmit_ready_failed, - transmit_ready_called); -#endif - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); -#endif - GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL); - - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "}"); - FCLOSE (dotOutFile); - } - - ok = 0; -} - - -static void -disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct TestMessageContext *pos = cls; - - /* Disconnect from the respective cores */ -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", - GNUNET_i2s (&pos->peer1->id)); -#endif - if (pos->peer1handle != NULL) - GNUNET_CORE_disconnect (pos->peer1handle); -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", - GNUNET_i2s (&pos->peer2->id)); -#endif - if (pos->peer2handle != NULL) - GNUNET_CORE_disconnect (pos->peer2handle); - /* Set handles to NULL so test case can be ended properly */ - pos->peer1handle = NULL; - pos->peer2handle = NULL; - pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; - /* Decrement total connections so new can be established */ - total_server_connections -= 2; -} - - -static void -topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, const char *emsg) -{ - FILE *outfile = cls; - - if (first != NULL) - { - if (outfile != NULL) - { - FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); - FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); - } - topology_connections++; - } - else - { - FPRINTF (stderr, - "Finished iterating over topology, %d total connections!\n", - topology_connections); - if (outfile != NULL) - { - FPRINTF (outfile, "%s", "}\n"); - FCLOSE (outfile); - GNUNET_SCHEDULER_add_now (&finish_testing, NULL); - } - } -} - -static int -process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message, - const struct GNUNET_ATS_Information *atsi) -{ - char *dotOutFileNameFinished; - FILE *dotOutFileFinished; - struct TestMessageContext *pos = cls; - struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; - - if (pos->uid != ntohl (msg->uid)) - return GNUNET_OK; - -#if VERBOSE - if ((total_messages_received) % modnum == 0) - { - if (total_messages_received == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) total_messages_received / expected_messages) * - 100)); - - } - else if (total_messages_received % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - - total_messages_received++; - -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), - ntohs (message->type)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Total messages received %d, expected %d.\n", - total_messages_received, expected_messages); -#endif - - if (total_messages_received == expected_messages) - { -#if VERBOSE - FPRINTF (stdout, "%s", "100%%]\n"); -#endif - GNUNET_SCHEDULER_cancel (die_task); - GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); - dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); - GNUNET_free (dotOutFileNameFinished); - if (dotOutFileFinished != NULL) - { - FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); - } - topology_connections = 0; - GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); - //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); - } - else - { - pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); - } - - return GNUNET_OK; -} - -static void -end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - char *msg = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "End badly was called (%s)... stopping daemons.\n", msg); - struct TestMessageContext *pos; - struct TestMessageContext *free_pos; - - pos = test_messages; - while (pos != NULL) - { - if (pos->peer1handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer1handle); - pos->peer1handle = NULL; - } - if (pos->peer2handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer2handle); - pos->peer2handle = NULL; - } - free_pos = pos; - pos = pos->next; - GNUNET_free (free_pos); - } - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", - transmit_ready_scheduled, transmit_ready_failed, - transmit_ready_called); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Total messages received %d, expected %d.\n", - total_messages_received, expected_messages); -#endif - - if (pg != NULL) - { - GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL); - ok = 7331; /* Opposite of leet */ - } - else - ok = 401; /* Never got peers started */ - - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "}"); - FCLOSE (dotOutFile); - } -} - -static size_t -transmit_ready (void *cls, size_t size, void *buf) -{ - struct GNUNET_TestMessage *m; - struct TestMessageContext *pos = cls; - - GNUNET_assert (buf != NULL); - m = (struct GNUNET_TestMessage *) buf; - m->header.type = htons (MTYPE); - m->header.size = htons (sizeof (struct GNUNET_TestMessage)); - m->uid = htonl (pos->uid); - transmit_ready_called++; -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", - GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, - transmit_ready_called); -#endif - return sizeof (struct GNUNET_TestMessage); -} - - -static struct GNUNET_CORE_MessageHandler no_handlers[] = { - {NULL, 0, 0} -}; - -static struct GNUNET_CORE_MessageHandler handlers[] = { - {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, - {NULL, 0, 0} -}; - -static void -init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, - const struct GNUNET_PeerIdentity *my_identity) -{ - struct TestMessageContext *pos = cls; - - total_server_connections++; - - pos->peer2connected = GNUNET_YES; - if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ - { -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", - GNUNET_i2s (my_identity), - GNUNET_h2s (&pos->peer1->id.hashPubKey)); -#endif - if (NULL == - GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout, - &pos->peer2->id, - sizeof (struct GNUNET_TestMessage), - &transmit_ready, pos)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", - GNUNET_i2s (&pos->peer2->id)); - transmit_ready_failed++; - } - else - { - transmit_ready_scheduled++; - } - } -} - -/** - * Method called whenever a given peer connects. - * - * @param cls closure - * @param peer peer identity this notification is about - * @param atsi performance data for the connection - */ -static void -connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_ATS_Information *atsi) -{ - struct TestMessageContext *pos = cls; - - if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) - { - pos->peer1notified = GNUNET_YES; -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peer `%s' notified of connection to peer `%s'\n", - GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); -#endif - } - else - return; - - if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ - { -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", - GNUNET_i2s (&pos->peer2->id), - GNUNET_h2s (&pos->peer1->id.hashPubKey)); -#endif - if (NULL == - GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout, - &pos->peer2->id, - sizeof (struct GNUNET_TestMessage), - &transmit_ready, pos)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", - GNUNET_i2s (&pos->peer2->id)); - transmit_ready_failed++; - } - else - { - transmit_ready_scheduled++; - } - } -} - -static void -init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, - const struct GNUNET_PeerIdentity *my_identity) -{ - struct TestMessageContext *pos = cls; - - total_server_connections++; - -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Core connection to `%4s' established, setting up handles\n", - GNUNET_i2s (my_identity)); -#endif - - /* - * Connect to the receiving peer - */ - pos->peer2handle = - GNUNET_CORE_connect (pos->peer2->cfg, pos, &init_notify_peer2, NULL, - NULL, NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, - handlers); - -} - - -static void -send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct TestMessageContext *pos = cls; - - if ((pos == test_messages) && (settle_time.rel_value > 0)) - { - topology_connections = 0; - GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); - } - if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) - return; - - if (die_task == GNUNET_SCHEDULER_NO_TASK) - { - die_task = - GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, - "from send test messages (timeout)"); - } - - if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) - { - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 1), - &send_test_messages, pos); - return; /* Otherwise we'll double schedule messages here! */ - } - - /* - * Connect to the sending peer - */ - pos->peer1handle = - GNUNET_CORE_connect (pos->peer1->cfg, pos, &init_notify_peer1, - &connect_notify_peers, NULL, NULL, NULL, GNUNET_NO, - NULL, GNUNET_NO, no_handlers); - - GNUNET_assert (pos->peer1handle != NULL); - - if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) - { - GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); - } - else - { - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 1), - &send_test_messages, pos->next); - } -} - - -void -topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, uint32_t distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - struct TestMessageContext *temp_context; - - if (emsg == NULL) - { -#if VERBOSE - if ((total_connections) % modnum == 0) - { - if (total_connections == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) total_connections / expected_connections) * - 100)); - - } - else if (total_connections % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - total_connections++; -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", - first_daemon->shortname, second_daemon->shortname); -#endif - temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); - temp_context->peer1 = first_daemon; - temp_context->peer2 = second_daemon; - temp_context->next = test_messages; - temp_context->uid = total_connections; - temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; - test_messages = temp_context; - - expected_messages++; - if (dotOutFile != NULL) - FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, - second_daemon->shortname); - } -#if VERBOSE - else - { - failed_connections++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to connect peer %s to peer %s with error :\n%s\n", - first_daemon->shortname, second_daemon->shortname, emsg); - } -#endif - - if (total_connections == expected_connections) - { -#if VERBOSE - FPRINTF (stdout, "%s", "100%%]\n"); -#endif -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Created %d total connections, which is our target number! Calling send messages.\n", - total_connections); -#endif - modnum = expected_messages / 4; - dotnum = (expected_messages / 50) + 1; - GNUNET_SCHEDULER_cancel (die_task); - die_task = GNUNET_SCHEDULER_NO_TASK; -#if DELAY_FOR_LOGGING - FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 10), - &send_test_messages, test_messages); - gather_log_data (); -#else - if (settle_time.rel_value > 0) - { - GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); - } - GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, - test_messages); -#endif -#if VERBOSE - FPRINTF (stdout, "%s", "Test message progress: ["); -#endif - - } - else if (total_connections + failed_connections == expected_connections) - { - if (failed_connections < - (unsigned int) (fail_percentage * total_connections)) - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); - } - else - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from topology_callback (too many failed connections)"); - } - } - else - { -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Have %d total connections, %d failed connections, Want %d (at least %d)\n", - total_connections, failed_connections, expected_connections, - expected_connections - - (unsigned int) (fail_percentage * expected_connections)); -#endif - } -} - -static void -topology_creation_finished (void *cls, const char *emsg) -{ -#if VERBOSE - if (emsg == NULL) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All topology connections created successfully!\n"); -#endif -} - -static void -connect_topology () -{ - expected_connections = -1; - if ((pg != NULL) && (peers_left == 0)) - { - expected_connections = - GNUNET_TESTING_connect_topology (pg, connection_topology, - connect_topology_option, - connect_topology_option_modifier, - connect_timeout, connect_attempts, - &topology_creation_finished, NULL); -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", - expected_connections); -#endif - } - - GNUNET_SCHEDULER_cancel (die_task); - if (expected_connections == GNUNET_SYSERR) - { - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from connect topology (bad return)"); - } - - die_task = - GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, - "from connect topology (timeout)"); - modnum = expected_connections / 4; - dotnum = (expected_connections / 50) + 1; -#if VERBOSE - FPRINTF (stdout, "%s", "Peer connection progress: ["); -#endif -} - -static void -create_topology () -{ - peers_left = num_peers; /* Reset counter */ - if (GNUNET_TESTING_create_topology - (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Topology set up, now starting peers!\n"); - FPRINTF (stdout, "%s", "Daemon start progress ["); -#endif - GNUNET_TESTING_daemons_continue_startup (pg); - } - else - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from create topology (bad return)"); - } - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, - "from continue startup (timeout)"); -} - - -static void -peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to start daemon with error: `%s'\n", emsg); - return; - } - GNUNET_assert (id != NULL); -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", - (num_peers - peers_left) + 1, num_peers); -#endif -#if VERBOSE - if ((num_peers - peers_left) % modnum == 0) - { - if (num_peers - peers_left == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) (num_peers - peers_left) / num_peers) * 100)); - - } - else if ((num_peers - peers_left) % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - peers_left--; - if (peers_left == 0) - { -#if VERBOSE - FPRINTF (stdout, "%s", "100%%]\n"); -#endif -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d daemons started, now connecting peers!\n", num_peers); -#endif - GNUNET_SCHEDULER_cancel (die_task); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - die_task = - GNUNET_SCHEDULER_add_delayed (timeout, &end_badly, - "from peers_started_callback"); -#if DELAY_FOR_LOGGING - FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); - gather_log_data (); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 10), - &connect_topology, NULL); -#else - connect_topology (); -#endif - ok = 0; - } -} - -/** - * Callback indicating that the hostkey was created for a peer. - * - * @param cls NULL - * @param id the peer identity - * @param d the daemon handle (pretty useless at this point, remove?) - * @param emsg non-null on failure - */ -void -hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Hostkey callback received error: %s\n", emsg); - } - -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, - num_peers, GNUNET_i2s (id)); -#endif - -#if VERBOSE - if ((num_peers - peers_left) % modnum == 0) - { - if (num_peers - peers_left == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) (num_peers - peers_left) / num_peers) * 100)); - - } - else if ((num_peers - peers_left) % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - peers_left--; - if (peers_left == 0) - { -#if VERBOSE - FPRINTF (stdout, "%s", "100%%]\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d hostkeys created, now creating topology!\n", num_peers); -#endif - GNUNET_SCHEDULER_cancel (die_task); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - die_task = - GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, - "from create_topology"); - GNUNET_SCHEDULER_add_now (&create_topology, NULL); - ok = 0; - } -} - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - char *topology_str; - char *connect_topology_str; - char *blacklist_topology_str; - char *connect_topology_option_str; - char *connect_topology_option_modifier_string; - unsigned long long temp_settle; - - ok = 1; - - dotOutFile = FOPEN (dotOutFileName, "w"); - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "strict graph G {\n"); - } - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting daemons based on config file %s\n", cfgfile); -#endif - - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", - &test_directory)) - { - ok = 404; - return; - } - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", - &topology_str)) && - (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid topology `%s' given for section %s option %s\n", - topology_str, "TESTING", "TOPOLOGY"); - topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ - } - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology", - &connect_topology_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_get (&connection_topology, - connect_topology_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid connect topology `%s' given for section %s option %s\n", - connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); - } - GNUNET_free_non_null (connect_topology_str); - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology_option", - &connect_topology_option_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_option_get (&connect_topology_option, - connect_topology_option_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid connect topology option `%s' given for section %s option %s\n", - connect_topology_option_str, "TESTING", - "CONNECT_TOPOLOGY_OPTION"); - connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ - } - GNUNET_free_non_null (connect_topology_option_str); - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology_option_modifier", - &connect_topology_option_modifier_string)) - { - if (SSCANF - (connect_topology_option_modifier_string, "%lf", - &connect_topology_option_modifier) != 1) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - connect_topology_option_modifier_string, - "connect_topology_option_modifier", "TESTING"); - } - GNUNET_free (connect_topology_option_modifier_string); - } - - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "blacklist_transports", - &blacklist_transports)) - blacklist_transports = NULL; - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "blacklist_topology", - &blacklist_topology_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_get (&blacklist_topology, - blacklist_topology_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid topology `%s' given for section %s option %s\n", - topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); - } - GNUNET_free_non_null (topology_str); - GNUNET_free_non_null (blacklist_topology_str); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", - &settle_time)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "SETTLE_TIME"); - return; - } - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", - &num_peers)) - num_peers = DEFAULT_NUM_PEERS; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "CONNECT_TIMEOUT", - &connect_timeout)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "CONNECT_TIMEOUT"); - return; - } - - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", - &connect_attempts)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "connect_attempts"); - return; - } - - main_cfg = cfg; - - peers_left = num_peers; - - /** - * How long until we fail the whole testcase? - */ - test_timeout = - GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - SECONDS_PER_PEER_START), num_peers * 2); - - /** - * How long until we give up on starting the peers? - */ - timeout = - GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - SECONDS_PER_PEER_START), num_peers); - - modnum = num_peers / 4; - dotnum = (num_peers / 50) + 1; -#if VERBOSE - FPRINTF (stdout, "%s", "Hostkey generation progress: ["); -#endif - /* Set up a task to end testing if peer start fails */ - die_task = - GNUNET_SCHEDULER_add_delayed (timeout, &end_badly, - "didn't generate all hostkeys within a reasonable amount of time!!!"); - - GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); - pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left / 2, - peers_left, timeout, &hostkey_callback, - NULL, &peers_started_callback, NULL, - &topology_callback, NULL, NULL); - -} - -static int -check () -{ - char *binary_name; - char *config_file_name; - - GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); - GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", - topology_string); - int ret; - - char *const argv[] = { binary_name, - "-c", - config_file_name, -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - ret = - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - binary_name, "nohelp", options, &run, &ok); - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "`test-testing-topology-%s': Failed with error code %d\n", - topology_string, ret); - } - GNUNET_free (binary_name); - GNUNET_free (config_file_name); - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - char *binary_start_pos; - char *our_binary_name; - - binary_start_pos = rindex (argv[0], '/'); - GNUNET_assert (binary_start_pos != NULL); - topology_string = strstr (binary_start_pos, "_topology"); - GNUNET_assert (topology_string != NULL); - topology_string++; - topology_string = strstr (topology_string, "_"); - GNUNET_assert (topology_string != NULL); - topology_string++; - - GNUNET_asprintf (&our_binary_name, "test-testing-large-topology_%s", - topology_string); - GNUNET_asprintf (&dotOutFileName, "large_topology_%s.dot", topology_string); - - GNUNET_log_setup (our_binary_name, -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - - /** - * Need to remove base directory, subdirectories taken care - * of by the testing framework. - */ - if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to remove testing directory %s\n", test_directory); - } - GNUNET_free (our_binary_name); - return ret; -} - -/* end of test_testing_topology.c */ diff --git a/src/testing/test_testing_peergroup.c b/src/testing/test_testing_peergroup.c deleted file mode 100644 index 061a0ca75..000000000 --- a/src/testing/test_testing_peergroup.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_peergroup.c - * @brief testcase for functions to connect peers in testing_peergroup.c - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - -#define VERBOSE GNUNET_NO - -#define NUM_PEERS 4 - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -static int ok; - -static int peers_left; - -static struct GNUNET_TESTING_PeerGroup *pg; - -/** - * Check whether peers successfully shut down. - */ -void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); -#endif - if (ok == 0) - ok = 666; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); -#endif - ok = 0; - } -} - - -static void -my_cb (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peergroup callback called with error, aborting test!\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); - ok = 1; - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peer Group started successfully, ending test!\n"); - /** - * If something is to actually be DONE with the testcase, it should - * be put in here. Usually there will be a struct declared (or global - * variables can be used) to keep track of the state, statistics, - * handles to peers, etc. The example here is the opaque "TestCaseData" - * struct that could be passed into a function "additional_code_for_testing" - * which can be used to perform actions on the peers in the peergroup. - * Also, the GNUNET_TESTING_daemons_stop call would need to be removed, - * and only called once all of the testing is complete. - */ - - /** - * struct TestcaseData *state_closure; - * GNUNET_SCHEDULER_add_now(&additional_code_for_testing, state_closure); - */ - - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_CONFIGURATION_Handle *testing_cfg; - - ok = 1; - testing_cfg = GNUNET_CONFIGURATION_create (); - GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (testing_cfg, cfgfile)); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); - GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", - "use_progressbars", "YES"); -#endif - peers_left = NUM_PEERS; - pg = GNUNET_TESTING_peergroup_start (testing_cfg, peers_left, TIMEOUT, NULL, - &my_cb, NULL, NULL); - GNUNET_assert (pg != NULL); -} - -static int -check () -{ - char *const argv[] = { "test-testing-peergroup", - "-c", - "test_testing_peergroup_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing-peergroup", "nohelp", options, &run, &ok); - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test-testing-peergroup", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); - return ret; -} - -/* end of test_testing_peergroup.c */ diff --git a/src/testing/test_testing_peergroup_data.conf b/src/testing/test_testing_peergroup_data.conf deleted file mode 100644 index 6eadede95..000000000 --- a/src/testing/test_testing_peergroup_data.conf +++ /dev/null @@ -1,22 +0,0 @@ -@INLINE@ test_testing_defaults.conf -[PATHS] -DEFAULTCONFIG = test_testing_peergroup_data.conf - -[TESTING] -CONNECT_ATTEMPTS = 2 -MAX_OUTSTANDING_CONNECTIONS = 20 -MAX_CONCURRENT_SSH = 1 -PEERGROUP_TIMEOUT = 300 s -TOPOLOGY = CLIQUE -PERCENTAGE = 0.5 -PROBABILITY = 0.5 -CONNECT_TOPOLOGY = CLIQUE -CONNECT_TOPOLOGY_OPTION = CONNECT_NONE -CONNECT_TOPOLOGY_OPTION_MODIFIER = 0.0 -BLACKLIST_TOPOLOGY = NONE -BLACKLIST_TRANSPORTS = tcp udp -USE_PROGRESSBARS = NO - -[arm] -DEFAULTSERVICES = core - diff --git a/src/testing/test_testing_reconnect.c b/src/testing/test_testing_reconnect.c deleted file mode 100644 index bcee38659..000000000 --- a/src/testing/test_testing_reconnect.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2010 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 testing/test_testing_reconnect.c - * @brief testcase for functions to connect two peers in testing.c - */ -#include "platform.h" -#include "gnunet_testing_lib.h" - -#define VERBOSE GNUNET_YES - -/** - * How long until we give up on connecting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -#define CONNECT_ATTEMPTS 3 - -static int ok; - -static struct GNUNET_TESTING_Daemon *d1; - -static struct GNUNET_TESTING_Daemon *d2; - -static struct GNUNET_CONFIGURATION_Handle *c1; - -static struct GNUNET_CONFIGURATION_Handle *c2; - -static struct GNUNET_TESTING_ConnectContext *cc; - -/** - * How many start-connect-stop iterations should we do? - */ -#define NUM_PHASES 2 - -static int phase; - -/** - * Run the next phase of starting daemons, connecting them and - * stopping them again. - */ -static void -run_phase (void); - -static void -end2_cb (void *cls, const char *emsg) -{ - - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); - ok = 1; - } - else - { - if (phase < NUM_PHASES) - { - FPRINTF (stderr, "%s", "."); - run_phase (); - return; - } - FPRINTF (stderr, "%s", ".\n"); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Both daemons terminated, will now exit.\n"); -#endif - ok = 0; - } -} - -static void -end1_cb (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", - emsg); - ok = 1; - } - else - { - ok = 0; - } - if (d2 != NULL) - { - GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, - (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, - GNUNET_NO); - d2 = NULL; - } -} - -static void -finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, - (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, - GNUNET_NO); - d1 = NULL; -} - - -static void -my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, - unsigned int distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - cc = NULL; -#if VERBOSE - FPRINTF (stderr, "Peer %s ", GNUNET_i2s (first)); - FPRINTF (stderr, "connected to %s\n", GNUNET_i2s (second)); -#endif - GNUNET_SCHEDULER_add_now (&finish_testing, NULL); -} - - - - -static void -my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 2 gave: %s\n", - emsg); - GNUNET_assert (0); - return; - } - GNUNET_assert (id != NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", - GNUNET_i2s (id)); -#endif - cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, - GNUNET_YES, &my_connect_complete, NULL); -} - - -static void -my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 1 gave: %s\n", - emsg); - GNUNET_assert (0); - return; - } - GNUNET_assert (id != NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", - GNUNET_i2s (id)); -#endif - d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, - NULL, NULL, &my_cb2, NULL); - GNUNET_assert (d2 != NULL); -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - ok = 1; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); -#endif - c1 = GNUNET_CONFIGURATION_create (); - GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_load (c1, - "test_testing_connect_peer1.conf")); - c2 = GNUNET_CONFIGURATION_create (); - GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_load (c2, - "test_testing_connect_peer2.conf")); - run_phase (); -} - -static void -run_phase () -{ - phase++; - d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, - NULL, NULL, &my_cb1, NULL); - GNUNET_assert (d1 != NULL); -} - -static int -check () -{ - char *const argv[] = { "test-testing-reconnect", - "-c", - "test_testing_data.conf", -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing-reconnect", "nohelp", options, &run, &ok); - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test-testing-reconnect", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - return ret; -} - -/* end of test_testing_reconnect.c */ diff --git a/src/testing/test_testing_topology.c b/src/testing/test_testing_topology.c deleted file mode 100644 index 94cbc0df6..000000000 --- a/src/testing/test_testing_topology.c +++ /dev/null @@ -1,1220 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_topology.c - * @brief base testcase for testing all the topologies provided - */ -#include "platform.h" -#include "gnunet_testing_lib.h" -#include "gnunet_core_service.h" -#include "gnunet_os_lib.h" - - -#define PROGRESS_BARS GNUNET_YES - -#define DELAY_FOR_LOGGING GNUNET_NO - -/** - * How long until we fail the whole testcase? - */ -#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 240) - -/** - * How long until we give up on starting the peers? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500) - -#define SECONDS_PER_PEER_START 120 - -#define DEFAULT_NUM_PEERS 4 - -#define MAX_OUTSTANDING_CONNECTIONS 100 - -static float fail_percentage = 0.05; - -static int ok; - -static unsigned long long num_peers; - -struct GNUNET_TIME_Relative connect_timeout; - -static unsigned long long connect_attempts; - -static unsigned int topology_connections; - -static unsigned int total_connections; - -static unsigned int failed_connections; - -static unsigned int total_server_connections; - -static unsigned int total_messages_received; - -static unsigned int expected_messages; - -static unsigned int expected_connections; - -static unsigned long long peers_left; - -static struct GNUNET_TESTING_PeerGroup *pg; - -const struct GNUNET_CONFIGURATION_Handle *main_cfg; - -GNUNET_SCHEDULER_TaskIdentifier die_task; - -static char *dotOutFileName; - -static struct GNUNET_TIME_Relative settle_time; - -static FILE *dotOutFile; - -static char *topology_string; - -static char *blacklist_transports; - -static int transmit_ready_scheduled; - -static int transmit_ready_failed; - -static int transmit_ready_called; - -static unsigned int modnum; - -static unsigned int dotnum; - -static enum GNUNET_TESTING_Topology topology; - -static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ - -static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ - -static enum GNUNET_TESTING_TopologyOption connect_topology_option = - GNUNET_TESTING_TOPOLOGY_OPTION_ALL; - -static double connect_topology_option_modifier = 0.0; - -static char *test_directory; - -#define MTYPE 12345 - -GNUNET_NETWORK_STRUCT_BEGIN - -struct GNUNET_TestMessage -{ - /** - * Header of the message - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this message. - */ - uint32_t uid; -}; -GNUNET_NETWORK_STRUCT_END - -struct TestMessageContext -{ - /* This is a linked list */ - struct TestMessageContext *next; - - /* Handle to the sending peer core */ - struct GNUNET_CORE_Handle *peer1handle; - - /* Handle to the receiving peer core */ - struct GNUNET_CORE_Handle *peer2handle; - - /* Handle to the sending peer daemon */ - struct GNUNET_TESTING_Daemon *peer1; - - /* Handle to the receiving peer daemon */ - struct GNUNET_TESTING_Daemon *peer2; - - /* Identifier for this message, so we don't disconnect other peers! */ - uint32_t uid; - - /* Has peer1 been notified already of a connection to peer2? */ - int peer1notified; - - /* Has the core of peer2 been connected already? */ - int peer2connected; - - /* Task for disconnecting cores, allow task to be cancelled on shutdown */ - GNUNET_SCHEDULER_TaskIdentifier disconnect_task; - -}; - -static struct TestMessageContext *test_messages; - -/** - * Check whether peers successfully shut down. - */ -static void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown of peers failed: %s!\n", - emsg); - if (ok == 0) - ok = 666; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); - } -} - - -#if DELAY_FOR_LOGGING -static void -gather_log_data () -{ - char *peer_number; - char *connect_number; - struct GNUNET_OS_Process *mem_process; - - GNUNET_asprintf (&peer_number, "%llu", num_peers); - GNUNET_asprintf (&connect_number, "%llu", expected_connections); - mem_process = - GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", - "totals.txt", peer_number, connect_number, NULL); - GNUNET_OS_process_wait (mem_process); - GNUNET_OS_process_destroy (mem_process); - mem_process = NULL; -} -#endif - - -static void -finish_testing () -{ - GNUNET_assert (pg != NULL); - struct TestMessageContext *pos; - struct TestMessageContext *free_pos; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Called finish testing, stopping daemons.\n"); - pos = test_messages; - while (pos != NULL) - { - if (pos->peer1handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer1handle); - pos->peer1handle = NULL; - } - if (pos->peer2handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer2handle); - pos->peer2handle = NULL; - } - free_pos = pos; - pos = pos->next; - if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); - } - GNUNET_free (free_pos); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", - transmit_ready_scheduled, transmit_ready_failed, - transmit_ready_called); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "}"); - FCLOSE (dotOutFile); - } - ok = 0; -} - - -static void -disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct TestMessageContext *pos = cls; - - /* Disconnect from the respective cores */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", - GNUNET_i2s (&pos->peer1->id)); - if (pos->peer1handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer1handle); - pos->peer1handle = NULL; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", - GNUNET_i2s (&pos->peer2->id)); - if (pos->peer2handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer2handle); - pos->peer2handle = NULL; - } - pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; - /* Decrement total connections so new can be established */ - total_server_connections -= 2; -} - -#if DO_STATS -static void -stats_finished (void *cls, int result) -{ - GNUNET_SCHEDULER_add_now (&finish_testing, NULL); -} - -/** - * Callback function to process statistic values. - * - * @param cls closure - * @param peer the peer the statistics belong to - * @param subsystem name of subsystem that created the statistic - * @param name the name of the datum - * @param value the current value - * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration - */ -static int -stats_print (void *cls, const struct GNUNET_PeerIdentity *peer, - const char *subsystem, const char *name, uint64_t value, - int is_persistent) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s:%s -- %llu\n", GNUNET_i2s (peer), - subsystem, name, value); - return GNUNET_OK; -} -#endif - - -static void -topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, const char *emsg) -{ - FILE *outfile = cls; - - if (first != NULL) - { - if (outfile != NULL) - { - FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); - FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); - } - topology_connections++; - } - else - { - FPRINTF (stderr, - "Finished iterating over topology, %d total connections!\n", - topology_connections); - if (outfile != NULL) - { - FPRINTF (outfile, "%s", "}\n"); - FCLOSE (outfile); -#if DO_STATS - GNUNET_TESTING_get_statistics (pg, &stats_finished, &stats_print, NULL); -#endif - GNUNET_SCHEDULER_add_now (&finish_testing, NULL); - } - } -} - - -static int -process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_MessageHeader *message, - const struct GNUNET_ATS_Information *atsi, - unsigned int atsi_count) -{ - char *dotOutFileNameFinished; - FILE *dotOutFileFinished; - struct TestMessageContext *pos = cls; - struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; - - if (pos->uid != ntohl (msg->uid)) - return GNUNET_OK; - -#if PROGRESS_BARS - if ((total_messages_received) % modnum == 0) - { - if (total_messages_received == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) total_messages_received / expected_messages) * - 100)); - - } - else if (total_messages_received % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - - total_messages_received++; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), - ntohs (message->type)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Total messages received %d, expected %d.\n", - total_messages_received, expected_messages); - - if (total_messages_received == expected_messages) - { -#if PROGRESS_BARS - FPRINTF (stdout, "%s", "100%%]\n"); -#endif - GNUNET_SCHEDULER_cancel (die_task); - GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); - dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); - GNUNET_free (dotOutFileNameFinished); - if (dotOutFileFinished != NULL) - { - FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); - } - topology_connections = 0; - GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); - //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); - } - else - { - pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); - } - - return GNUNET_OK; -} - - -static void -end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - char *msg = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Ending with error: %s\n", msg); - struct TestMessageContext *pos; - struct TestMessageContext *free_pos; - - pos = test_messages; - while (pos != NULL) - { - if (pos->peer1handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer1handle); - pos->peer1handle = NULL; - } - if (pos->peer2handle != NULL) - { - GNUNET_CORE_disconnect (pos->peer2handle); - pos->peer2handle = NULL; - } - free_pos = pos; - pos = pos->next; - GNUNET_free (free_pos); - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", - transmit_ready_scheduled, transmit_ready_failed, - transmit_ready_called); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Total messages received %d, expected %d.\n", - total_messages_received, expected_messages); - - if (pg != NULL) - { - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - ok = 7331; /* Opposite of leet */ - } - else - ok = 401; /* Never got peers started */ - - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "}"); - FCLOSE (dotOutFile); - } -} - - -static size_t -transmit_ready (void *cls, size_t size, void *buf) -{ - struct GNUNET_TestMessage *m; - struct TestMessageContext *pos = cls; - - GNUNET_assert (buf != NULL); - m = (struct GNUNET_TestMessage *) buf; - m->header.type = htons (MTYPE); - m->header.size = htons (sizeof (struct GNUNET_TestMessage)); - m->uid = htonl (pos->uid); - transmit_ready_called++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", - GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, - transmit_ready_called); - return sizeof (struct GNUNET_TestMessage); -} - - -static struct GNUNET_CORE_MessageHandler no_handlers[] = { - {NULL, 0, 0} -}; - - -static struct GNUNET_CORE_MessageHandler handlers[] = { - {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, - {NULL, 0, 0} -}; - - -static void -init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, - const struct GNUNET_PeerIdentity *my_identity) -{ - struct TestMessageContext *pos = cls; - - total_server_connections++; - - pos->peer2connected = GNUNET_YES; - if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", - GNUNET_i2s (my_identity), - GNUNET_h2s (&pos->peer1->id.hashPubKey)); - if (NULL == - GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, - TIMEOUT, &pos->peer2->id, - sizeof (struct GNUNET_TestMessage), - &transmit_ready, pos)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", - GNUNET_i2s (&pos->peer2->id)); - transmit_ready_failed++; - } - else - { - transmit_ready_scheduled++; - } - } -} - - -/** - * Method called whenever a given peer connects. - * - * @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 -connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_ATS_Information *atsi, - unsigned int atsi_count) -{ - struct TestMessageContext *pos = cls; - - if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) - { - pos->peer1notified = GNUNET_YES; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peer `%s' notified of connection to peer `%s'\n", - GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); - } - else - return; - - if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", - GNUNET_i2s (&pos->peer2->id), - GNUNET_h2s (&pos->peer1->id.hashPubKey)); - if (NULL == - GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, - TIMEOUT, &pos->peer2->id, - sizeof (struct GNUNET_TestMessage), - &transmit_ready, pos)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", - GNUNET_i2s (&pos->peer2->id)); - transmit_ready_failed++; - } - else - { - transmit_ready_scheduled++; - } - } -} - - -static void -init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, - const struct GNUNET_PeerIdentity *my_identity) -{ - struct TestMessageContext *pos = cls; - - total_server_connections++; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Core connection to `%4s' established, setting up handles\n", - GNUNET_i2s (my_identity)); - /* - * Connect to the receiving peer - */ - pos->peer2handle = - GNUNET_CORE_connect (pos->peer2->cfg, pos, &init_notify_peer2, NULL, - NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, handlers); - -} - - -static void -send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct TestMessageContext *pos = cls; - - if ((pos == test_messages) && (settle_time.rel_value > 0)) - { - topology_connections = 0; - GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); - } - if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) - return; - - if (die_task == GNUNET_SCHEDULER_NO_TASK) - { - die_task = - GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, - "from send test messages (timeout)"); - } - - if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) - { - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 1), - &send_test_messages, pos); - return; /* Otherwise we'll double schedule messages here! */ - } - - /* - * Connect to the sending peer - */ - pos->peer1handle = - GNUNET_CORE_connect (pos->peer1->cfg, pos, &init_notify_peer1, - &connect_notify_peers, NULL, NULL, GNUNET_NO, NULL, - GNUNET_NO, no_handlers); - - GNUNET_assert (pos->peer1handle != NULL); - - if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) - { - GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); - } - else - { - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 1), - &send_test_messages, pos->next); - } -} - - -static void -topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, uint32_t distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - struct TestMessageContext *temp_context; - - if (emsg == NULL) - { -#if PROGRESS_BARS - if ((total_connections) % modnum == 0) - { - if (total_connections == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) total_connections / expected_connections) * - 100)); - - } - else if (total_connections % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - total_connections++; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", - first_daemon->shortname, second_daemon->shortname); - temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); - temp_context->peer1 = first_daemon; - temp_context->peer2 = second_daemon; - temp_context->next = test_messages; - temp_context->uid = total_connections; - temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; - test_messages = temp_context; - - expected_messages++; - if (dotOutFile != NULL) - FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, - second_daemon->shortname); - } - else - { - failed_connections++; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to connect peer %s to peer %s with error :\n%s\n", - first_daemon->shortname, second_daemon->shortname, emsg); - } - - if (total_connections == expected_connections) - { -#if PROGRESS_BARS - FPRINTF (stdout, "%s", "100%%]\n"); -#endif - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Created %d total connections, which is our target number! Calling send messages.\n", - total_connections); - modnum = expected_messages / 4; - dotnum = (expected_messages / 50) + 1; - if (modnum == 0) - modnum = 1; - if (dotnum == 0) - dotnum = 1; - GNUNET_SCHEDULER_cancel (die_task); - die_task = GNUNET_SCHEDULER_NO_TASK; -#if DELAY_FOR_LOGGING - FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 10), - &send_test_messages, test_messages); - gather_log_data (); -#else - if (settle_time.rel_value > 0) - { - GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); - } - GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, - test_messages); -#endif -#if PROGRESS_BARS - FPRINTF (stdout, "%s", "Test message progress: ["); -#endif - - } - else if (total_connections + failed_connections == expected_connections) - { - if (failed_connections < - (unsigned int) (fail_percentage * total_connections)) - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); - } - else - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from topology_callback (too many failed connections)"); - } - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Have %d total connections, %d failed connections, Want %d (at least %d)\n", - total_connections, failed_connections, expected_connections, - expected_connections - - (unsigned int) (fail_percentage * expected_connections)); - } -} - - -static void -topology_creation_finished (void *cls, const char *emsg) -{ - if (emsg == NULL) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All topology connections created successfully!\n"); -} - - -static void -connect_topology () -{ - expected_connections = -1; - if ((pg != NULL) && (peers_left == 0)) - { - expected_connections = - GNUNET_TESTING_connect_topology (pg, connection_topology, - connect_topology_option, - connect_topology_option_modifier, - connect_timeout, connect_attempts, - &topology_creation_finished, NULL); -#if PROGRESS_BARS - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", - expected_connections); -#endif - } - - GNUNET_SCHEDULER_cancel (die_task); - if (expected_connections < 1) - { - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from connect topology (bad return)"); - return; - } - - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - SECONDS_PER_PEER_START * num_peers), - &end_badly, - "from connect topology (timeout)"); - modnum = expected_connections / 4; - dotnum = (expected_connections / 50) + 1; - if (modnum == 0) - modnum = 1; - if (dotnum == 0) - dotnum = 1; -#if PROGRESS_BARS - FPRINTF (stdout, "%s", "Peer connection progress: ["); -#endif -} - -static void -create_topology () -{ - peers_left = num_peers; /* Reset counter */ - if (GNUNET_TESTING_create_topology - (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) - { -#if PROGRESS_BARS - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Topology set up, now starting peers!\n"); - FPRINTF (stdout, "%s", "Daemon start progress ["); -#endif - GNUNET_TESTING_daemons_continue_startup (pg); - } - else - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from create topology (bad return)"); - } - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - SECONDS_PER_PEER_START * num_peers), - &end_badly, - "from continue startup (timeout)"); -} - - -static void -peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to start daemon with error: `%s'\n", emsg); - return; - } - GNUNET_assert (id != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", - (num_peers - peers_left) + 1, num_peers); -#if PROGRESS_BARS - if ((num_peers - peers_left) % modnum == 0) - { - if (num_peers - peers_left == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) (num_peers - peers_left) / num_peers) * 100)); - - } - else if ((num_peers - peers_left) % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - peers_left--; - if (peers_left == 0) - { -#if PROGRESS_BARS - FPRINTF (stdout, "%s", "100%%]\n"); -#endif - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d daemons started, now connecting peers!\n", num_peers); - GNUNET_SCHEDULER_cancel (die_task); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, 8), &end_badly, - "from peers_started_callback"); -#if DELAY_FOR_LOGGING - FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); - gather_log_data (); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 10), - &connect_topology, NULL); -#else - connect_topology (); -#endif - ok = 0; - } -} - -/** - * Callback indicating that the hostkey was created for a peer. - * - * @param cls NULL - * @param id the peer identity - * @param d the daemon handle (pretty useless at this point, remove?) - * @param emsg non-null on failure - */ -void -hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Hostkey callback received error: %s\n", emsg); - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, - num_peers, GNUNET_i2s (id)); -#if PROGRESS_BARS - if ((num_peers - peers_left) % modnum == 0) - { - if (num_peers - peers_left == 0) - FPRINTF (stdout, "%s", "0%%"); - else - FPRINTF (stdout, "%d%%", - (int) (((float) (num_peers - peers_left) / num_peers) * 100)); - - } - else if ((num_peers - peers_left) % dotnum == 0) - { - FPRINTF (stdout, "%s", "."); - } - fflush (stdout); -#endif - peers_left--; - if (peers_left == 0) - { -#if PROGRESS_BARS - FPRINTF (stdout, "%s", "100%%]\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d hostkeys created, now creating topology!\n", num_peers); -#endif - GNUNET_SCHEDULER_cancel (die_task); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - die_task = - GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, - "from create_topology"); - GNUNET_SCHEDULER_add_now (&create_topology, NULL); - ok = 0; - } -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - char *topology_str; - char *connect_topology_str; - char *blacklist_topology_str; - char *connect_topology_option_str; - char *connect_topology_option_modifier_string; - unsigned long long max_outstanding_connections; - - ok = 1; - - dotOutFile = FOPEN (dotOutFileName, "w"); - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "strict graph G {\n"); - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting daemons based on config file %s\n", cfgfile); - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", - &test_directory)) - { - ok = 404; - return; - } - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", - &topology_str)) && - (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid topology `%s' given for section %s option %s\n", - topology_str, "TESTING", "TOPOLOGY"); - topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ - } - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology", - &connect_topology_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_get (&connection_topology, - connect_topology_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid connect topology `%s' given for section %s option %s\n", - connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); - } - GNUNET_free_non_null (connect_topology_str); - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology_option", - &connect_topology_option_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_option_get (&connect_topology_option, - connect_topology_option_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid connect topology option `%s' given for section %s option %s\n", - connect_topology_option_str, "TESTING", - "CONNECT_TOPOLOGY_OPTION"); - connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ - } - GNUNET_free_non_null (connect_topology_option_str); - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology_option_modifier", - &connect_topology_option_modifier_string)) - { - if (SSCANF - (connect_topology_option_modifier_string, "%lf", - &connect_topology_option_modifier) != 1) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - connect_topology_option_modifier_string, - "connect_topology_option_modifier", "TESTING"); - } - GNUNET_free (connect_topology_option_modifier_string); - } - - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "blacklist_transports", - &blacklist_transports)) - blacklist_transports = NULL; - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "blacklist_topology", - &blacklist_topology_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_get (&blacklist_topology, - blacklist_topology_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid topology `%s' given for section %s option %s\n", - topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); - } - GNUNET_free_non_null (topology_str); - GNUNET_free_non_null (blacklist_topology_str); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", - &settle_time)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "SETTLE_TIME"); - return; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", - &connect_timeout)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "CONNECT_TIMEOUT"); - return; - } - - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", - &connect_attempts)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "connect_attempts"); - return; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", - "max_outstanding_connections", - &max_outstanding_connections)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "max_outstanding_connections"); - return; - } - - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", - &num_peers)) - num_peers = DEFAULT_NUM_PEERS; - - main_cfg = cfg; - - peers_left = num_peers; - modnum = num_peers / 4; - dotnum = (num_peers / 50) + 1; - if (modnum == 0) - modnum = 1; - if (dotnum == 0) - dotnum = 1; -#if PROGRESS_BARS - FPRINTF (stdout, "%s", "Hostkey generation progress: ["); -#endif - /* Set up a task to end testing if peer start fails */ - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - SECONDS_PER_PEER_START * num_peers), - &end_badly, - "didn't generate all hostkeys within a reasonable amount of time!!!"); - - GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); - pg = GNUNET_TESTING_daemons_start (cfg, peers_left, - max_outstanding_connections, peers_left, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - SECONDS_PER_PEER_START * num_peers), - &hostkey_callback, NULL, - &peers_started_callback, NULL, - &topology_callback, NULL, NULL); - -} - - -static int -check () -{ - char *binary_name; - char *config_file_name; - - GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); - GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", - topology_string); - int ret; - - char *const argv[] = { binary_name, - "-c", - config_file_name, - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - ret = - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - binary_name, "nohelp", options, &run, &ok); - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "`test-testing-topology-%s': Failed with error code %d\n", - topology_string, ret); - } - GNUNET_free (binary_name); - GNUNET_free (config_file_name); - return ok; -} - - -int -main (int argc, char *argv[]) -{ - int ret; - char *binary_start_pos; - char *our_binary_name; - char *dotexe; - - binary_start_pos = strchr (argv[0], '/'); - GNUNET_assert (binary_start_pos != NULL); - topology_string = strstr (binary_start_pos, "_topology"); - GNUNET_assert (topology_string != NULL); - topology_string++; - topology_string = strstr (topology_string, "_"); - GNUNET_assert (topology_string != NULL); - topology_string++; - topology_string = GNUNET_strdup (topology_string); - if (NULL != (dotexe = strstr (topology_string, ".exe"))) - dotexe[0] = '\0'; - GNUNET_asprintf (&our_binary_name, "test-testing-topology_%s", - topology_string); - GNUNET_asprintf (&dotOutFileName, "topology_%s.dot", topology_string); - - GNUNET_log_setup (our_binary_name, - "WARNING", - NULL); - ret = check (); - GNUNET_free (topology_string); - - /** - * Need to remove base directory, subdirectories taken care - * of by the testing framework. - */ - if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to remove testing directory %s\n", test_directory); - } - GNUNET_free (our_binary_name); - return ret; -} - -/* end of test_testing_topology.c */ diff --git a/src/testing/test_testing_topology_blacklist.c b/src/testing/test_testing_topology_blacklist.c deleted file mode 100644 index c90f48d9b..000000000 --- a/src/testing/test_testing_topology_blacklist.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_topology_blacklist.c - * @brief base testcase for testing transport level blacklisting - */ -#include "platform.h" -#include "gnunet_testing_lib.h" -#include "gnunet_core_service.h" - -#define VERBOSE GNUNET_NO - -/** - * How long until we fail the whole testcase? - */ -#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) - -/** - * How long until we give up on starting the peers? (Must be longer than the connect timeout!) - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -#define DEFAULT_NUM_PEERS 4 - -#define MAX_OUTSTANDING_CONNECTIONS 300 - -static int ok; - -struct GNUNET_TIME_Relative connect_timeout; - -static unsigned long long connect_attempts; - -static unsigned long long num_peers; - -static unsigned int total_connections; - -static unsigned int failed_connections; - -static unsigned int expected_connections; - -static unsigned int expected_failed_connections; - -static unsigned long long peers_left; - -static struct GNUNET_TESTING_PeerGroup *pg; - -const struct GNUNET_CONFIGURATION_Handle *main_cfg; - -GNUNET_SCHEDULER_TaskIdentifier die_task; - -static char *dotOutFileName; - -static FILE *dotOutFile; - -static char *blacklist_transports; - -static enum GNUNET_TESTING_Topology topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Overlay should allow all connections */ - -static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_RING; /* Blacklist underlay into a ring */ - -static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ - -static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Try to connect all possible OVERLAY connections */ - -static double connect_topology_option_modifier = 0.0; - -static char *test_directory; - -#define MTYPE 12345 - -GNUNET_NETWORK_STRUCT_BEGIN - -struct GNUNET_TestMessage -{ - /** - * Header of the message - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this message. - */ - uint32_t uid; -}; -GNUNET_NETWORK_STRUCT_END - -/** - * Check whether peers successfully shut down. - */ -void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); -#endif - if (ok == 0) - ok = 666; - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); -#endif - } -} - -static void -finish_testing () -{ - GNUNET_assert (pg != NULL); - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Called finish testing, stopping daemons.\n"); -#endif - sleep (1); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); -#endif - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); -#endif - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "}"); - FCLOSE (dotOutFile); - } - - ok = 0; -} - -static void -end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - char *msg = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "End badly was called (%s)... stopping daemons.\n", msg); - - if (pg != NULL) - { - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - ok = 7331; /* Opposite of leet */ - } - else - ok = 401; /* Never got peers started */ - - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "}"); - FCLOSE (dotOutFile); - } -} - - - -void -topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, uint32_t distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - if (emsg == NULL) - { - total_connections++; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n", - first_daemon->shortname, second_daemon->shortname); -#endif - if (dotOutFile != NULL) - FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, - second_daemon->shortname); - } - - else - { - failed_connections++; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to connect peer %s to peer %s with error :\n%s\n", - first_daemon->shortname, second_daemon->shortname, emsg); -#endif - } - - - if (total_connections == expected_connections) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Created %d total connections, which is our target number (that's bad)!\n", - total_connections); -#endif - - GNUNET_SCHEDULER_cancel (die_task); - die_task = GNUNET_SCHEDULER_NO_TASK; - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from topology_callback (too many successful connections)"); - } - else if (total_connections + failed_connections == expected_connections) - { - if ((failed_connections == expected_failed_connections) && - (total_connections == - expected_connections - expected_failed_connections)) - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = GNUNET_SCHEDULER_NO_TASK; - die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); - } - else - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from topology_callback (wrong number of failed connections)"); - } - } - else - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Have %d total connections, %d failed connections, Want %d (failed) and %d (successful)\n", - total_connections, failed_connections, - expected_failed_connections, - expected_connections - expected_failed_connections); -#endif - } -} - -static void -connect_topology () -{ - expected_connections = -1; - if ((pg != NULL) && (peers_left == 0)) - { - expected_connections = - GNUNET_TESTING_connect_topology (pg, connection_topology, - connect_topology_option, - connect_topology_option_modifier, - connect_timeout, connect_attempts, - NULL, NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", - expected_connections); -#endif - } - - GNUNET_SCHEDULER_cancel (die_task); - if (expected_connections == GNUNET_SYSERR) - { - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from connect topology (bad return)"); - } - - die_task = - GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, - "from connect topology (timeout)"); -} - -static void -create_topology () -{ - peers_left = num_peers; /* Reset counter */ - if (GNUNET_TESTING_create_topology - (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Topology set up, now starting peers!\n"); -#endif - GNUNET_TESTING_daemons_continue_startup (pg); - } - else - { - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_now (&end_badly, - "from create topology (bad return)"); - } - GNUNET_SCHEDULER_cancel (die_task); - die_task = - GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, - "from continue startup (timeout)"); -} - - -static void -peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to start daemon with error: `%s'\n", emsg); - return; - } - GNUNET_assert (id != NULL); -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", - (num_peers - peers_left) + 1, num_peers); -#endif - peers_left--; - if (peers_left == 0) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d daemons started, now creating topology!\n", num_peers); -#endif - GNUNET_SCHEDULER_cancel (die_task); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, - "from peers_started_callback"); - connect_topology (); - ok = 0; - } -} - -/** - * Callback indicating that the hostkey was created for a peer. - * - * @param cls NULL - * @param id the peer identity - * @param d the daemon handle (pretty useless at this point, remove?) - * @param emsg non-null on failure - */ -void -hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Hostkey callback received error: %s\n", emsg); - } - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey created for peer `%s'\n", - GNUNET_i2s (id)); -#endif - peers_left--; - if (peers_left == 0) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d hostkeys created, now creating topology!\n", num_peers); -#endif - GNUNET_SCHEDULER_cancel (die_task); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, - "from hostkey_callback"); - GNUNET_SCHEDULER_add_now (&create_topology, NULL); - ok = 0; - } -} - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - unsigned long long topology_num; - unsigned long long connect_topology_num; - unsigned long long blacklist_topology_num; - unsigned long long connect_topology_option_num; - char *connect_topology_option_modifier_string; - - ok = 1; - - dotOutFile = FOPEN (dotOutFileName, "w"); - if (dotOutFile != NULL) - { - FPRINTF (dotOutFile, "%s", "strict graph G {\n"); - } - -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting daemons based on config file %s\n", cfgfile); -#endif - - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", - &test_directory)) - { - ok = 404; - if (dotOutFile != NULL) - { - FCLOSE (dotOutFile); - } - return; - } - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "topology", - &topology_num)) - topology = topology_num; - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology", - &connect_topology_num)) - connection_topology = connect_topology_num; - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", - "connect_topology_option", - &connect_topology_option_num)) - connect_topology_option = connect_topology_option_num; - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology_option_modifier", - &connect_topology_option_modifier_string)) - { - if (SSCANF - (connect_topology_option_modifier_string, "%lf", - &connect_topology_option_modifier) != 1) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - connect_topology_option_modifier_string, - "connect_topology_option_modifier", "TESTING"); - GNUNET_free (connect_topology_option_modifier_string); - ok = 707; - if (dotOutFile != NULL) - { - FCLOSE (dotOutFile); - } - return; - } - GNUNET_free (connect_topology_option_modifier_string); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "blacklist_transports", - &blacklist_transports)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No transports specified for blacklisting in blacklist testcase (this shouldn't happen!)\n"); - ok = 808; - if (dotOutFile != NULL) - { - FCLOSE (dotOutFile); - } - return; - } - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", - "blacklist_topology", - &blacklist_topology_num)) - blacklist_topology = blacklist_topology_num; - - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", - &num_peers)) - num_peers = DEFAULT_NUM_PEERS; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", - &connect_timeout)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "CONNECT_TIMEOUT"); - return; - } - - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", - &connect_attempts)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "connect_attempts"); - return; - } - - main_cfg = cfg; - - GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); - peers_left = num_peers; - - /* For this specific test we only really want a CLIQUE topology as the - * overlay allowed topology, and a RING topology as the underlying connection - * allowed topology. So we will expect only num_peers * 2 connections to - * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. - */ - expected_connections = num_peers * (num_peers - 1); - expected_failed_connections = expected_connections - (num_peers * 2); - - - /* Set up a task to end testing if peer start fails */ - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, - "didn't start all daemons in reasonable amount of time!!!"); - - pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, - TIMEOUT, &hostkey_callback, NULL, - &peers_started_callback, NULL, - &topology_callback, NULL, NULL); - -} - -static int -check () -{ - int ret; - - char *const argv[] = { "test-testing-topology-blacklist", - "-c", - "test_testing_data_topology_blacklist.conf", -#if VERBOSE - "-L", "DEBUG", -#endif - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - ret = - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing-topology-blacklist", "nohelp", options, - &run, &ok); - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "`test-testing-topology-blacklist': Failed with error code %d\n", - ret); - } - - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test_testing_topology_blacklist", -#if VERBOSE - "DEBUG", -#else - "WARNING", -#endif - NULL); - ret = check (); - - /** - * Need to remove base directory, subdirectories taken care - * of by the testing framework. - */ - if (test_directory != NULL) - { - if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to remove testing directory %s\n", test_directory); - } - } - - return ret; -} - -/* end of test_testing_topology_blacklist.c */ diff --git a/src/testing/test_testing_topology_churn.c b/src/testing/test_testing_topology_churn.c deleted file mode 100644 index 9c0bbf27d..000000000 --- a/src/testing/test_testing_topology_churn.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/test_testing_topology_churn.c - * @brief base testcase for testing simple churn functionality - */ -#include "platform.h" -#include "gnunet_testing_lib.h" -#include "gnunet_core_service.h" - - -/** - * How long until we fail the whole testcase? - */ -#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) - -/** - * How long until we give up on starting the peers? (Must be longer than the connect timeout!) - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) - -#define DEFAULT_NUM_PEERS 4 - -static int ok; - -static unsigned long long num_peers; - -static unsigned int expected_connections; - -static unsigned int expected_failed_connections; - -static unsigned long long peers_left; - -static struct GNUNET_TESTING_PeerGroup *pg; - -const struct GNUNET_CONFIGURATION_Handle *main_cfg; - -GNUNET_SCHEDULER_TaskIdentifier die_task; - -static char *test_directory; - -#define MTYPE 12345 - -GNUNET_NETWORK_STRUCT_BEGIN - -struct GNUNET_TestMessage -{ - /** - * Header of the message - */ - struct GNUNET_MessageHeader header; - - /** - * Unique identifier for this message. - */ - uint32_t uid; -}; -GNUNET_NETWORK_STRUCT_END - -/** - * Check whether peers successfully shut down. - */ -void -shutdown_callback (void *cls, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); - if (ok == 0) - ok = 666; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); - } -} - -static void -finish_testing () -{ - GNUNET_assert (pg != NULL); - - if (die_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (die_task); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Called finish testing, stopping daemons.\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); - ok = 0; -} - -static void -end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - char *msg = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "End badly was called (%s)... stopping daemons.\n", msg); - - if (pg != NULL) - { - GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); - ok = 7331; /* Opposite of leet */ - } - else - ok = 401; /* Never got peers started */ - -} - -struct ChurnTestContext -{ - GNUNET_SCHEDULER_Task next_task; - -}; - -static struct ChurnTestContext churn_ctx; - -/** - * Churn callback, report on success or failure of churn operation. - * - * @param cls closure - * @param emsg NULL on success - */ -void -churn_callback (void *cls, const char *emsg) -{ - if (emsg == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully churned peers!\n", - emsg); - GNUNET_SCHEDULER_add_now (churn_ctx.next_task, NULL); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to churn peers with error `%s'\n", emsg); - GNUNET_SCHEDULER_cancel (die_task); - die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); - } -} - - -static void -churn_peers_both () -{ - churn_ctx.next_task = &finish_testing; - GNUNET_TESTING_daemons_churn (pg, NULL, 1, 1, TIMEOUT, &churn_callback, NULL); -} - -static void -churn_peers_off_again () -{ - churn_ctx.next_task = &churn_peers_both; - GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); -} - -static void -churn_peers_on () -{ - churn_ctx.next_task = &churn_peers_off_again; - GNUNET_TESTING_daemons_churn (pg, NULL, 0, 2, TIMEOUT, &churn_callback, NULL); -} - -static void -churn_peers_off () -{ - churn_ctx.next_task = &churn_peers_on; - GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); -} - -static void -peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to start daemon with error: `%s'\n", emsg); - return; - } - GNUNET_assert (id != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", - (num_peers - peers_left) + 1, num_peers); - peers_left--; - if (peers_left == 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d daemons started, now testing churn!\n", num_peers); - GNUNET_SCHEDULER_cancel (die_task); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, - "from peers_started_callback"); - churn_peers_off (); - ok = 0; - } -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - ok = 1; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting daemons based on config file %s\n", cfgfile); - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", - &test_directory)) - { - ok = 404; - return; - } - - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", - &num_peers)) - num_peers = DEFAULT_NUM_PEERS; - - main_cfg = cfg; - - peers_left = num_peers; - GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); - - /* For this specific test we only really want a CLIQUE topology as the - * overlay allowed topology, and a RING topology as the underlying connection - * allowed topology. So we will expect only num_peers * 2 connections to - * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. - */ - expected_connections = num_peers * (num_peers - 1); - expected_failed_connections = expected_connections - (num_peers * 2); - - - /* Set up a task to end testing if peer start fails */ - die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, - "didn't start all daemons in reasonable amount of time!!!"); - - pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, - TIMEOUT, NULL, NULL, - &peers_started_callback, NULL, NULL, NULL, - NULL); - -} - -static int -check () -{ - int ret; - - char *const argv[] = { "test-testing-topology-churn", - "-c", - "test_testing_data_topology_churn.conf", - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - ret = - GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, - "test-testing-topology-churn", "nohelp", options, - &run, &ok); - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "`test-testing-topology-churn': Failed with error code %d\n", - ret); - } - - return ok; -} - -int -main (int argc, char *argv[]) -{ - int ret; - - GNUNET_log_setup ("test_testing_topology_churn", - "WARNING", - NULL); - ret = check (); - - /** - * Need to remove base directory, subdirectories taken care - * of by the testing framework. - */ - if (test_directory != NULL) - { - if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to remove testing directory %s\n", test_directory); - } - } - - return ret; -} - -/* end of test_testing_topology_churn.c */ diff --git a/src/testing/testing.c b/src/testing/testing.c deleted file mode 100644 index a80ad25cf..000000000 --- a/src/testing/testing.c +++ /dev/null @@ -1,2204 +0,0 @@ -/* - This file is part of GNUnet - (C) 2008, 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/testing.c - * @brief convenience API for writing testcases for GNUnet - * Many testcases need to start and stop gnunetd, - * and this library is supposed to make that easier - * for TESTCASES. Normal programs should always - * use functions from gnunet_{util,arm}_lib.h. This API is - * ONLY for writing testcases! - * @author Christian Grothoff - * - */ -#include "platform.h" -#include "gnunet_arm_service.h" -#include "gnunet_core_service.h" -#include "gnunet_constants.h" -#include "gnunet_testing_lib.h" -#include "gnunet_transport_service.h" -#include "gnunet_hello_lib.h" - -/** - * Hack to deal with initial HELLO's being often devoid of addresses. - * This hack causes 'process_hello' to ignore HELLOs without addresses. - * The correct implementation would continue with 'process_hello' until - * the connection could be established... - */ -#define EMPTY_HACK GNUNET_YES - -/** - * How long do we wait after starting gnunet-service-arm - * for the core service to be alive? - */ -#define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) - -/** - * How many times are we willing to try to wait for "scp" or - * "gnunet-service-arm" to complete (waitpid) before giving up? - */ -#define MAX_EXEC_WAIT_RUNS 250 - -static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; - -#if EMPTY_HACK -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; -} -#endif - -/** - * Receive the HELLO from one peer, give it to the other - * and ask them to connect. - * - * @param cls Closure (daemon whose hello is this). - * @param message HELLO message of peer - */ -static void -process_hello (void *cls, const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_TESTING_Daemon *daemon = cls; - int msize; - -#if EMPTY_HACK - int empty; - - empty = GNUNET_YES; - GNUNET_assert (message != NULL); - GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *) message, - GNUNET_NO, &test_address, &empty); - if (GNUNET_YES == empty) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Skipping empty HELLO address of peer %s\n", - GNUNET_i2s (&daemon->id)); - return; - } -#endif - GNUNET_assert (daemon->phase == SP_GET_HELLO || - daemon->phase == SP_START_DONE); - daemon->cb = NULL; // FIXME: why??? (see fsm:SP_START_CORE, notify_daemon_started) - if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */ - GNUNET_SCHEDULER_cancel (daemon->task); - - if (daemon->server != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s' from transport service of `%4s', disconnecting core!\n", - "HELLO", GNUNET_i2s (&daemon->id)); - GNUNET_CORE_disconnect (daemon->server); - daemon->server = NULL; - } - - msize = ntohs (message->size); - if (msize < 1) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "HELLO message of peer %s is of size 0\n", - GNUNET_i2s (&daemon->id)); - return; - } - if (daemon->ghh != NULL) - { - GNUNET_TRANSPORT_get_hello_cancel (daemon->ghh); - daemon->ghh = NULL; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s' from transport service of `%4s'\n", "HELLO", - GNUNET_i2s (&daemon->id)); - GNUNET_free_non_null (daemon->hello); - daemon->hello = GNUNET_malloc (msize); - memcpy (daemon->hello, message, msize); - - if (daemon->th != NULL) - { - GNUNET_TRANSPORT_disconnect (daemon->th); - daemon->th = NULL; - } - daemon->phase = SP_START_DONE; -} - - -/** - * Notify of a peer being up and running. Scheduled as a task - * so that variables which may need to be set are set before - * the connect callback can set up new operations. - * FIXME: what variables?????? where from???? - * - * @param cls the testing daemon - * @param tc task scheduler context - */ -static void -notify_daemon_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TESTING_Daemon *d = cls; - GNUNET_TESTING_NotifyDaemonRunning cb; - - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, &d->id, d->cfg, d, NULL); -} - - -/** - * Finite-state machine for starting GNUnet. - * - * @param cls our "struct GNUNET_TESTING_Daemon" - * @param tc unused - */ -static void -start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TESTING_Daemon *d = cls; - GNUNET_TESTING_NotifyDaemonRunning cb; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - char *dst; - int bytes_read; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %s FSM is in phase %u.\n", - GNUNET_i2s (&d->id), d->phase); - d->task = GNUNET_SCHEDULER_NO_TASK; - switch (d->phase) - { - case SP_COPYING: - /* confirm copying complete */ - if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) - { - if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - _ - ("`scp' does not seem to terminate (timeout copying config).\n")); - return; - } - /* wait some more */ - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - return; - } - if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, _("`scp' did not complete cleanly.\n")); - return; - } - GNUNET_OS_process_destroy (d->proc_arm_copying); - d->proc_arm_copying = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Successfully copied configuration file.\n"); - d->phase = SP_COPIED; - /* fall-through */ - case SP_COPIED: - /* Start create hostkey process if we don't already know the peer identity! */ - if (GNUNET_NO == d->have_hostkey) - { - GNUNET_assert (NULL == d->proc_arm_peerinfo); - d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES); - if (d->pipe_stdout == NULL) - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - (NULL == - d->hostname) ? - _("Failed to create pipe for `gnunet-peerinfo' process.\n") : - _("Failed to create pipe for `ssh' process.\n")); - return; - } - if (NULL == d->hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting `%s', with command `%s %s %s %s'.\n", - "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile, - "-sq"); - d->proc_arm_peerinfo = - GNUNET_OS_start_process (GNUNET_YES, NULL, d->pipe_stdout, "gnunet-peerinfo", - "gnunet-peerinfo", "-c", d->cfgfile, "-sq", - NULL); - GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); - } - else - { - if (d->username != NULL) - GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); - else - dst = GNUNET_strdup (d->hostname); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting `%s', with command `%s %s %s %s %s %s'.\n", - "gnunet-peerinfo", "ssh", dst, "gnunet-peerinfo", "-c", - d->cfgfile, "-sq"); - if (d->ssh_port_str == NULL) - { - d->proc_arm_peerinfo = GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", - "-q", - dst, "gnunet-peerinfo", "-c", - d->cfgfile, "-sq", NULL); - } - else - { - d->proc_arm_peerinfo = - GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", "-p", - d->ssh_port_str, - "-q", - dst, "gnunet-peerinfo", "-c", d->cfgfile, - "-sq", NULL); - } - GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); - GNUNET_free (dst); - } - if (NULL == d->proc_arm_peerinfo) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not start `%s' process to create hostkey.\n"), - (NULL == d->hostname) ? "gnunet-peerinfo" : "ssh"); - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - (NULL == - d->hostname) ? _("Failed to start `gnunet-peerinfo' process.\n") - : _("Failed to start `ssh' process.\n")); - GNUNET_DISK_pipe_close (d->pipe_stdout); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Started `%s', waiting for hostkey.\n", "gnunet-peerinfo"); - d->phase = SP_HOSTKEY_CREATE; - d->task = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining - (d->max_timeout), - GNUNET_DISK_pipe_handle - (d->pipe_stdout, - GNUNET_DISK_PIPE_END_READ), - &start_fsm, d); - } - else /* Already have a hostkey! */ - { - if (d->hostkey_callback != NULL) - { - d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); - d->hostkey_callback = NULL; - d->phase = SP_HOSTKEY_CREATED; - } - else - d->phase = SP_TOPOLOGY_SETUP; - - /* wait some more */ - d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); - } - break; - case SP_HOSTKEY_CREATE: - bytes_read = - GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle - (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ), - &d->hostkeybuf[d->hostkeybufpos], - sizeof (d->hostkeybuf) - d->hostkeybufpos); - if (bytes_read > 0) - d->hostkeybufpos += bytes_read; - - if ((d->hostkeybufpos < 104) && (bytes_read > 0)) - { - /* keep reading */ - d->task = - GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining - (d->max_timeout), - GNUNET_DISK_pipe_handle - (d->pipe_stdout, - GNUNET_DISK_PIPE_END_READ), - &start_fsm, d); - return; - } - d->hostkeybuf[103] = '\0'; - - if ((bytes_read < 0) || - (GNUNET_OK != - GNUNET_CRYPTO_hash_from_string (d->hostkeybuf, &d->id.hashPubKey))) - { - /* error */ - if (bytes_read < 0) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Error reading from gnunet-peerinfo: %s\n"), - STRERROR (errno)); - else - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Malformed output from gnunet-peerinfo!\n")); - cb = d->cb; - d->cb = NULL; - GNUNET_DISK_pipe_close (d->pipe_stdout); - d->pipe_stdout = NULL; - (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); - GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); - GNUNET_OS_process_destroy (d->proc_arm_peerinfo); - d->proc_arm_peerinfo = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, _("Failed to get hostkey!\n")); - return; - } - d->shortname = GNUNET_strdup (GNUNET_i2s (&d->id)); - GNUNET_DISK_pipe_close (d->pipe_stdout); - d->pipe_stdout = NULL; - (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); - GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); - GNUNET_OS_process_destroy (d->proc_arm_peerinfo); - d->proc_arm_peerinfo = NULL; - d->have_hostkey = GNUNET_YES; - if (d->hostkey_callback != NULL) - { - d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); - d->hostkey_callback = NULL; - d->phase = SP_HOSTKEY_CREATED; - } - else - { - d->phase = SP_TOPOLOGY_SETUP; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully got hostkey!\n"); - /* Fall through */ - case SP_HOSTKEY_CREATED: - /* wait for topology finished */ - if ((GNUNET_YES == d->dead) || - (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)) - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - _("`Failed while waiting for topology setup!\n")); - return; - } - - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - break; - case SP_TOPOLOGY_SETUP: /* Indicates topology setup has completed! */ - /* start GNUnet on remote host */ - if (NULL == d->hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting `%s', with command `%s %s %s %s'.\n", - "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, - "-s"); - d->proc_arm_start = - GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", - d->cfgfile, - "-s", "-q", "-T", - GNUNET_TIME_relative_to_string - (GNUNET_TIME_absolute_get_remaining - (d->max_timeout)), NULL); - } - else - { - if (d->username != NULL) - GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); - else - dst = GNUNET_strdup (d->hostname); - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Starting `%s', with command `%s %s %s %s %s %s %s'.\n", - "gnunet-arm", "ssh", dst, "gnunet-arm", "-c", d->cfgfile, - "-s", "-q"); - if (d->ssh_port_str == NULL) - { - d->proc_arm_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", - "-q", - dst, "gnunet-arm", - "-c", d->cfgfile, "-s", "-q", "-T", - GNUNET_TIME_relative_to_string - (GNUNET_TIME_absolute_get_remaining - (d->max_timeout)), NULL); - } - else - { - - d->proc_arm_start = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-p", - d->ssh_port_str, - "-q", - dst, "gnunet-arm", - "-c", d->cfgfile, "-s", "-q", "-T", - GNUNET_TIME_relative_to_string - (GNUNET_TIME_absolute_get_remaining - (d->max_timeout)), NULL); - } - GNUNET_free (dst); - } - if (NULL == d->proc_arm_start) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not start `%s' process to start GNUnet.\n"), - (NULL == d->hostname) ? "gnunet-arm" : "ssh"); - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - (NULL == - d->hostname) ? _("Failed to start `gnunet-arm' process.\n") : - _("Failed to start `ssh' process.\n")); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Started `%s', waiting for `%s' to be up.\n", "gnunet-arm", - "gnunet-service-core"); - d->phase = SP_START_ARMING; - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - // FIXME: busy wait? - break; - case SP_START_ARMING: - if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_start, &type, &code)) - { - if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - (NULL == - d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : - _("`ssh' does not seem to terminate.\n")); - if (d->cfg != NULL) - { - GNUNET_CONFIGURATION_destroy (d->cfg); - d->cfg = NULL; - } - if (d->cfgfile != NULL) - { - GNUNET_free (d->cfgfile); - d->cfgfile = NULL; - } - GNUNET_free_non_null (d->hostname); - GNUNET_free_non_null (d->username); - GNUNET_OS_process_destroy (d->proc_arm_start); - d->proc_arm_start = NULL; - d->username = NULL; - d->hostname = NULL; // Quick hack to avoid crashing (testing need to be - d->cfg = NULL; // overhauled anyway, and the error managing is - // GNUNET_free (d); // FIXME (could this leak) - // pretty broken anyway. - return; - } - /* wait some more */ - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - // FIXME: busy wait? - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully started `%s'.\n", - "gnunet-arm"); - GNUNET_OS_process_destroy (d->proc_arm_start); - d->proc_arm_start = NULL; - d->phase = SP_START_CORE; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling CORE_connect\n"); - /* Fall through */ - case SP_START_CORE: - if (d->server != NULL) - GNUNET_CORE_disconnect (d->server); - - d->th = GNUNET_TRANSPORT_connect (d->cfg, &d->id, d, NULL, NULL, NULL); - if (d->th == NULL) - { - if (GNUNET_YES == d->dead) - GNUNET_TESTING_daemon_stop (d, - GNUNET_TIME_absolute_get_remaining - (d->max_timeout), d->dead_cb, - d->dead_cb_cls, GNUNET_YES, GNUNET_NO); - else if (NULL != d->cb) - d->cb (d->cb_cls, &d->id, d->cfg, d, - _("Failed to connect to transport service!\n")); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connected to transport service `%s', getting HELLO\n", - GNUNET_i2s (&d->id)); - d->ghh = GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d); - /* FIXME: store task ID somewhere! */ - GNUNET_SCHEDULER_add_now (¬ify_daemon_started, d); - /*cb = d->cb; - * d->cb = NULL; - * if (NULL != cb) - * cb (d->cb_cls, &d->id, d->cfg, d, NULL); */ - d->running = GNUNET_YES; - d->phase = SP_GET_HELLO; - break; - case SP_GET_HELLO: - if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) - { - if (d->server != NULL) - GNUNET_CORE_disconnect (d->server); - if (d->th != NULL) - GNUNET_TRANSPORT_disconnect (d->th); - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, _("Unable to get HELLO for peer!\n")); - GNUNET_CONFIGURATION_destroy (d->cfg); - GNUNET_free (d->cfgfile); - GNUNET_free_non_null (d->hostname); - GNUNET_free_non_null (d->username); - GNUNET_free (d); - return; - } - if (d->hello != NULL) - return; - GNUNET_assert (d->task == GNUNET_SCHEDULER_NO_TASK); - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_CONSTANTS_SERVICE_RETRY, 2), - &start_fsm, d); - break; - case SP_START_DONE: - GNUNET_break (0); - break; - case SP_SERVICE_START: - /* confirm gnunet-arm exited */ - if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_start, &type, &code)) - { - if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - (NULL == - d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : - _("`ssh' does not seem to terminate.\n")); - return; - } - /* wait some more */ - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - return; - } -#if EXTRA_CHECKS - if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - (NULL == - d->hostname) ? - _ - ("`gnunet-arm' terminated with non-zero exit status (or timed out)!\n") - : _("`ssh' does not seem to terminate.\n")); - return; - } -#endif - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service startup complete!\n"); - cb = d->cb; - d->cb = NULL; - d->phase = SP_START_DONE; - if (NULL != cb) - cb (d->cb_cls, &d->id, d->cfg, d, NULL); - GNUNET_OS_process_destroy (d->proc_arm_srv_start); - d->proc_arm_srv_start = NULL; - break; - case SP_SERVICE_SHUTDOWN_START: - /* confirm copying complete */ - if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_stop, &type, &code)) - { - if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) - { - if (NULL != d->dead_cb) - d->dead_cb (d->dead_cb_cls, - _ - ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); - return; - } - /* wait some more */ - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - return; - } -#if EXTRA_CHECKS - if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) - { - if (NULL != d->dead_cb) - d->dead_cb (d->dead_cb_cls, - _ - ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); - return; - } -#endif - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); - if (NULL != d->dead_cb) - d->dead_cb (d->dead_cb_cls, NULL); - break; - case SP_SHUTDOWN_START: - /* confirm copying complete !??? */ - if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_stop, &type, &code)) - { - if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) - { - if (NULL != d->dead_cb) - d->dead_cb (d->dead_cb_cls, - _ - ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); - if (d->th != NULL) - { - GNUNET_TRANSPORT_get_hello_cancel (d->ghh); - d->ghh = NULL; - GNUNET_TRANSPORT_disconnect (d->th); - d->th = NULL; - } - if (d->cfg != NULL) - { - GNUNET_CONFIGURATION_destroy (d->cfg); - d->cfg = NULL; - } - if (d->cfgfile != NULL) - { - GNUNET_free (d->cfgfile); - d->cfgfile = NULL; - } - GNUNET_free_non_null (d->hello); - GNUNET_free_non_null (d->hostname); - GNUNET_free_non_null (d->username); - GNUNET_free_non_null (d->shortname); - GNUNET_OS_process_destroy (d->proc_arm_stop); - d->proc_arm_stop = NULL; - GNUNET_free (d); - return; - } - /* wait some more */ - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - return; - } - if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) - { - if (NULL != d->dead_cb) - d->dead_cb (d->dead_cb_cls, - _ - ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); - if (d->th != NULL) - { - GNUNET_TRANSPORT_get_hello_cancel (d->ghh); - d->ghh = NULL; - GNUNET_TRANSPORT_disconnect (d->th); - d->th = NULL; - } - if (d->server != NULL) - { - GNUNET_CORE_disconnect (d->server); - d->server = NULL; - } - GNUNET_CONFIGURATION_destroy (d->cfg); - d->cfg = NULL; - GNUNET_free (d->cfgfile); - GNUNET_free_non_null (d->hello); - GNUNET_free_non_null (d->hostname); - GNUNET_free_non_null (d->username); - GNUNET_free_non_null (d->shortname); - GNUNET_OS_process_destroy (d->proc_arm_stop); - d->proc_arm_stop = NULL; - GNUNET_free (d); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n"); - if (d->server != NULL) - { - GNUNET_CORE_disconnect (d->server); - d->server = NULL; - } - - if (d->th != NULL) - { - GNUNET_TRANSPORT_get_hello_cancel (d->ghh); - d->ghh = NULL; - GNUNET_TRANSPORT_disconnect (d->th); - d->th = NULL; - } - - if (NULL != d->dead_cb) - d->dead_cb (d->dead_cb_cls, NULL); - - /* state clean up and notifications */ - if (d->churn == GNUNET_NO) - { - GNUNET_CONFIGURATION_destroy (d->cfg); - d->cfg = NULL; - GNUNET_free (d->cfgfile); - GNUNET_free_non_null (d->hostname); - GNUNET_free_non_null (d->username); - } - - GNUNET_free_non_null (d->hello); - d->hello = NULL; - GNUNET_free_non_null (d->shortname); - GNUNET_OS_process_destroy (d->proc_arm_stop); - d->proc_arm_stop = NULL; - d->shortname = NULL; - if (d->churn == GNUNET_NO) - GNUNET_free (d); - - break; - case SP_CONFIG_UPDATE: - /* confirm copying complete */ - if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) - { - if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) /* FIXME: config update should take timeout parameter! */ - { - cb = d->cb; - d->cb = NULL; - if (NULL != cb) - cb (d->cb_cls, NULL, d->cfg, d, - _("`scp' does not seem to terminate.\n")); - return; - } - /* wait some more */ - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - d); - return; - } - if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) - { - if (NULL != d->update_cb) - d->update_cb (d->update_cb_cls, _("`scp' did not complete cleanly.\n")); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Successfully copied configuration file.\n"); - if (NULL != d->update_cb) - d->update_cb (d->update_cb_cls, NULL); - d->phase = SP_START_DONE; - break; - } -} - -/** - * Continues GNUnet daemon startup when user wanted to be notified - * once a hostkey was generated (for creating friends files, blacklists, - * etc.). - * - * @param daemon the daemon to finish starting - */ -void -GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon) -{ - GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED); - daemon->phase = SP_TOPOLOGY_SETUP; -} - -/** - * Check whether the given daemon is running. - * - * @param daemon the daemon to check - * - * @return GNUNET_YES if the daemon is up, GNUNET_NO if the - * daemon is down, GNUNET_SYSERR on error. - */ -int -GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon) -{ - if (daemon == NULL) - return GNUNET_SYSERR; - - if (daemon->running == GNUNET_YES) - return GNUNET_YES; - return GNUNET_NO; -} - - -/** - * Starts a GNUnet daemon service which has been previously stopped. - * - * @param d the daemon for which the service should be started - * @param service the name of the service to start - * @param timeout how long to wait for process for shutdown to complete - * @param cb function called once the service starts - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d, - char *service, - struct GNUNET_TIME_Relative - timeout, - GNUNET_TESTING_NotifyDaemonRunning - cb, void *cb_cls) -{ - char *arg; - - d->cb = cb; - d->cb_cls = cb_cls; - - GNUNET_assert (d->running == GNUNET_YES); - - if (d->phase == SP_CONFIG_UPDATE) - { - GNUNET_SCHEDULER_cancel (d->task); - d->phase = SP_START_DONE; - } - - if (d->churned_services == NULL) - { - d->cb (d->cb_cls, &d->id, d->cfg, d, - "No service has been churned off yet!!"); - return; - } - d->phase = SP_SERVICE_START; - GNUNET_free (d->churned_services); - d->churned_services = NULL; - d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - /* Check if this is a local or remote process */ - if (NULL != d->hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting gnunet-arm with config `%s' on host `%s'.\n", - d->cfgfile, d->hostname); - if (d->username != NULL) - GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); - else - arg = GNUNET_strdup (d->hostname); - - d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", - "-q", - arg, "gnunet-arm", - "-c", d->cfgfile, "-i", service, "-q", - "-T", - GNUNET_TIME_relative_to_string (timeout), - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q\n", - arg, "gnunet-arm", d->cfgfile, service); - GNUNET_free (arg); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); - d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", - "-c", d->cfgfile, "-i", service, "-q", - "-T", - GNUNET_TIME_relative_to_string (timeout), - NULL); - } - - d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); -} - -/** - * Starts a GNUnet daemon's service. - * - * @param d the daemon for which the service should be started - * @param service the name of the service to start - * @param timeout how long to wait for process for startup - * @param cb function called once gnunet-arm returns - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d, - const char *service, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls) -{ - char *arg; - - d->cb = cb; - d->cb_cls = cb_cls; - - GNUNET_assert (service != NULL); - GNUNET_assert (d->running == GNUNET_YES); - GNUNET_assert (d->phase == SP_START_DONE); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Starting service %s for peer `%4s'\n"), service, - GNUNET_i2s (&d->id)); - d->phase = SP_SERVICE_START; - d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - /* Check if this is a local or remote process */ - if (NULL != d->hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting gnunet-arm with config `%s' on host `%s'.\n", - d->cfgfile, d->hostname); - if (d->username != NULL) - GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); - else - arg = GNUNET_strdup (d->hostname); - - d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", - "-q", - arg, "gnunet-arm", - "-c", d->cfgfile, "-i", service, "-q", - "-T", - GNUNET_TIME_relative_to_string (timeout), - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q -T %s\n", - arg, "gnunet-arm", d->cfgfile, service, - GNUNET_TIME_relative_to_string (timeout)); - GNUNET_free (arg); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); - d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", - "-c", d->cfgfile, "-i", service, "-q", - "-T", - GNUNET_TIME_relative_to_string (timeout), - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Starting gnunet-arm with command %s -c %s -i %s -q -T %s\n", - "gnunet-arm", d->cfgfile, service, - GNUNET_TIME_relative_to_string (timeout)); - } - - d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); -} - -/** - * Start a peer that has previously been stopped using the daemon_stop - * call (and files weren't deleted and the allow restart flag) - * - * @param daemon the daemon to start (has been previously stopped) - * @param timeout how long to wait for restart - * @param cb the callback for notification when the peer is running - * @param cb_cls closure for the callback - */ -void -GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls) -{ - if (daemon->running == GNUNET_YES) - { - cb (cb_cls, &daemon->id, daemon->cfg, daemon, - "Daemon already running, can't restart!"); - return; - } - - daemon->cb = cb; - daemon->cb_cls = cb_cls; - daemon->phase = SP_TOPOLOGY_SETUP; - daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - /* FIXME: why add_continuation? */ - GNUNET_SCHEDULER_add_continuation (&start_fsm, daemon, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); -} - -/** - * Starts a GNUnet daemon. GNUnet must be installed on the target - * system and available in the PATH. The machine must furthermore be - * reachable via "ssh" (unless the hostname is "NULL") without the - * need to enter a password. - * - * @param cfg configuration to use - * @param timeout how long to wait starting up peers - * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO - * to really start the peer (default) - * @param hostname name of the machine where to run GNUnet - * (use NULL for localhost). - * @param ssh_username ssh username to use when connecting to hostname - * @param sshport port to pass to ssh process when connecting to hostname - * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) - * @param hostkey_callback function to call once the hostkey has been - * generated for this peer, but it hasn't yet been started - * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) - * @param hostkey_cls closure for hostkey callback - * @param cb function to call once peer is up, or failed to start - * @param cb_cls closure for cb - * @return handle to the daemon (actual start will be completed asynchronously) - */ -struct GNUNET_TESTING_Daemon * -GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TIME_Relative timeout, int pretend, - const char *hostname, const char *ssh_username, - uint16_t sshport, const char *hostkey, - GNUNET_TESTING_NotifyHostkeyCreated - hostkey_callback, void *hostkey_cls, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls) -{ - struct GNUNET_TESTING_Daemon *ret; - char *arg; - char *username; - char *servicehome; - char *baseservicehome; - char *slash; - char *hostkeyfile; - char *temp_file_name; - struct GNUNET_DISK_FileHandle *fn; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; - struct GNUNET_CRYPTO_RsaPrivateKey *private_key; - - ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon)); - ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname); - if (sshport != 0) - { - GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport); - } - else - ret->ssh_port_str = NULL; - - /* Find service home and base service home directories, create it if it doesn't exist */ - GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", - "SERVICEHOME", - &servicehome)); - - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome)); - GNUNET_asprintf (&temp_file_name, "%s/gnunet-testing-config", servicehome); - ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name); - GNUNET_free (temp_file_name); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Setting up peer with configuration file `%s'.\n", ret->cfgfile); - if (NULL == ret->cfgfile) - { - GNUNET_free_non_null (ret->ssh_port_str); - GNUNET_free_non_null (ret->hostname); - GNUNET_free (ret); - return NULL; - } - ret->hostkey_callback = hostkey_callback; - ret->hostkey_cls = hostkey_cls; - ret->cb = cb; - ret->cb_cls = cb_cls; - ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - ret->cfg = GNUNET_CONFIGURATION_dup (cfg); - GNUNET_CONFIGURATION_set_value_string (ret->cfg, "PATHS", "DEFAULTCONFIG", - ret->cfgfile); - - if (hostkey != NULL) /* Get the peer identity from the hostkey */ - { - private_key = GNUNET_CRYPTO_rsa_decode_key (hostkey, HOSTKEYFILESIZE); - GNUNET_assert (private_key != NULL); - GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key); - GNUNET_CRYPTO_hash (&public_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &ret->id.hashPubKey); - ret->shortname = GNUNET_strdup (GNUNET_i2s (&ret->id)); - ret->have_hostkey = GNUNET_YES; - GNUNET_CRYPTO_rsa_key_free (private_key); - } - - /* Write hostkey to file, if we were given one */ - hostkeyfile = NULL; - if (hostkey != NULL) - { - GNUNET_asprintf (&hostkeyfile, "%s/.hostkey", servicehome); - fn = GNUNET_DISK_file_open (hostkeyfile, - GNUNET_DISK_OPEN_READWRITE | - GNUNET_DISK_OPEN_CREATE, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - GNUNET_assert (fn != NULL); - GNUNET_assert (HOSTKEYFILESIZE == - GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE)); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn)); - } - - /* write configuration to temporary file */ - if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile)) - { - if (0 != UNLINK (ret->cfgfile)) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", - ret->cfgfile); - GNUNET_CONFIGURATION_destroy (ret->cfg); - GNUNET_free_non_null (ret->hostname); - GNUNET_free (ret->cfgfile); - GNUNET_free (ret); - return NULL; - } - if (ssh_username != NULL) - username = GNUNET_strdup (ssh_username); - if ((ssh_username == NULL) && - (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "USERNAME", - &username))) - { - if (NULL != getenv ("USER")) - username = GNUNET_strdup (getenv ("USER")); - else - username = NULL; - } - ret->username = username; - - if (GNUNET_NO == pretend) /* Copy files, enter finite state machine */ - { - /* copy directory to remote host */ - if (NULL != hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying configuration directory to host `%s'.\n", hostname); - baseservicehome = GNUNET_strdup (servicehome); - /* Remove trailing /'s */ - while (baseservicehome[strlen (baseservicehome) - 1] == '/') - baseservicehome[strlen (baseservicehome) - 1] = '\0'; - /* Find next directory /, jump one ahead */ - slash = strrchr (baseservicehome, '/'); - if (slash != NULL) - *(++slash) = '\0'; - - ret->phase = SP_COPYING; - if (NULL != username) - GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome); - else - GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome); - GNUNET_free (baseservicehome); - if (ret->ssh_port_str == NULL) - { - ret->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", - "-q", - servicehome, arg, NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "copying directory with command scp -r %s %s\n", - servicehome, arg); - } - else - { - ret->proc_arm_copying = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", "-P", - ret->ssh_port_str, - "-q", - servicehome, arg, NULL); - } - GNUNET_free (arg); - if (NULL == ret->proc_arm_copying) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ - ("Could not start `%s' process to copy configuration directory.\n"), - "scp"); - if (0 != UNLINK (ret->cfgfile)) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", - ret->cfgfile); - GNUNET_CONFIGURATION_destroy (ret->cfg); - GNUNET_free_non_null (ret->hostname); - GNUNET_free_non_null (ret->username); - GNUNET_free (ret->cfgfile); - GNUNET_free (ret); - if ((hostkey != NULL) && (0 != UNLINK (hostkeyfile))) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", - hostkeyfile); - GNUNET_free_non_null (hostkeyfile); - GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome)); - GNUNET_free (servicehome); - return NULL; - } - - ret->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, - ret); - GNUNET_free_non_null (hostkeyfile); - GNUNET_free (servicehome); - return ret; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "No need to copy configuration file since we are running locally.\n"); - ret->phase = SP_COPIED; - /* FIXME: why add_cont? */ - GNUNET_SCHEDULER_add_continuation (&start_fsm, ret, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - } - GNUNET_free_non_null (hostkeyfile); - GNUNET_free (servicehome); - return ret; -} - - -/** - * Restart (stop and start) a GNUnet daemon. - * - * @param d the daemon that should be restarted - * @param cb function called once the daemon is (re)started - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls) -{ - char *arg; - char *del_arg; - - del_arg = NULL; - if (NULL != d->cb) - { - d->dead = GNUNET_YES; - return; - } - - d->cb = cb; - d->cb_cls = cb_cls; - - if (d->phase == SP_CONFIG_UPDATE) - { - GNUNET_SCHEDULER_cancel (d->task); - d->phase = SP_START_DONE; - } - if (d->server != NULL) - { - GNUNET_CORE_disconnect (d->server); - d->server = NULL; - } - - if (d->th != NULL) - { - GNUNET_TRANSPORT_get_hello_cancel (d->ghh); - d->ghh = NULL; - GNUNET_TRANSPORT_disconnect (d->th); - d->th = NULL; - } - /* state clean up and notifications */ - GNUNET_free_non_null (d->hello); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), - GNUNET_i2s (&d->id)); - d->phase = SP_START_ARMING; - - /* Check if this is a local or remote process */ - if (NULL != d->hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with config `%s' on host `%s'.\n", - d->cfgfile, d->hostname); - if (d->username != NULL) - GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); - else - arg = GNUNET_strdup (d->hostname); - - d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", - "-q", - arg, "gnunet-arm", - "-c", d->cfgfile, "-e", "-r", NULL); - /* Use -r to restart arm and all services */ - - GNUNET_free (arg); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); - d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", - "-c", d->cfgfile, "-e", "-r", NULL); - } - - GNUNET_free_non_null (del_arg); - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); - -} - - -/** - * Stops a GNUnet daemon. - * - * @param d the daemon that should be stopped - * @param service the name of the service to stop - * @param timeout how long to wait for process for shutdown to complete - * @param cb function called once the daemon was stopped - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d, - const char *service, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls) -{ - char *arg; - - d->dead_cb = cb; - d->dead_cb_cls = cb_cls; - - GNUNET_assert (d->running == GNUNET_YES); - - if (d->phase == SP_CONFIG_UPDATE) - { - GNUNET_SCHEDULER_cancel (d->task); - d->phase = SP_START_DONE; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), - GNUNET_i2s (&d->id)); - if (d->churned_services != NULL) - { - d->dead_cb (d->dead_cb_cls, "A service has already been turned off!!"); - return; - } - d->phase = SP_SERVICE_SHUTDOWN_START; - d->churned_services = GNUNET_strdup (service); - d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - /* Check if this is a local or remote process */ - if (NULL != d->hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with config `%s' on host `%s'.\n", - d->cfgfile, d->hostname); - if (d->username != NULL) - GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); - else - arg = GNUNET_strdup (d->hostname); - - d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", - "-q", - arg, "gnunet-arm", - "-c", d->cfgfile, "-k", service, "-q", - "-T", - GNUNET_TIME_relative_to_string (timeout), - NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n", - arg, "gnunet-arm", d->cfgfile, service); - GNUNET_free (arg); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); - d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", - "-c", d->cfgfile, "-k", service, "-q", - "-T", - GNUNET_TIME_relative_to_string (timeout), - NULL); - } - - d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); -} - - -/** - * Forcefully terminate a process and clean up the child. - * - * @param proc handle to process to kill - */ -static void -kill_and_close_process (struct GNUNET_OS_Process *proc) -{ - (void) GNUNET_OS_process_kill (proc, SIGKILL); - GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); - GNUNET_OS_process_destroy (proc); -} - - -/** - * Stops a GNUnet daemon. - * - * @param d the daemon that should be stopped - * @param timeout how long to wait for process for shutdown to complete - * @param cb function called once the daemon was stopped - * @param cb_cls closure for cb - * @param delete_files GNUNET_YES to remove files, GNUNET_NO - * to leave them - * @param allow_restart GNUNET_YES to restart peer later (using this API) - * GNUNET_NO to kill off and clean up for good - */ -void -GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, - int delete_files, int allow_restart) -{ - char *arg; - char *del_arg; - - d->dead_cb = cb; - d->dead_cb_cls = cb_cls; - - if (NULL != d->cb) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Setting d->dead on peer `%4s'\n"), - GNUNET_i2s (&d->id)); - d->dead = GNUNET_YES; - return; - } - if (NULL != d->proc_arm_start) - { - kill_and_close_process (d->proc_arm_start); - d->proc_arm_start = NULL; - } - if (NULL != d->proc_arm_srv_start) - { - kill_and_close_process (d->proc_arm_srv_start); - d->proc_arm_srv_start = NULL; - } - if (NULL != d->proc_arm_srv_stop) - { - kill_and_close_process (d->proc_arm_srv_stop); - d->proc_arm_srv_stop = NULL; - } - if (NULL != d->proc_arm_copying) - { - kill_and_close_process (d->proc_arm_copying); - d->proc_arm_copying = NULL; - } - if (NULL != d->proc_arm_peerinfo) - { - kill_and_close_process (d->proc_arm_peerinfo); - d->proc_arm_peerinfo = NULL; - } - if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES)) - { - /* Peer has already been stopped in churn context! - * Free what was left from churning! */ - GNUNET_assert (d->cfg != NULL); - GNUNET_CONFIGURATION_destroy (d->cfg); - if (delete_files == GNUNET_YES) - { - if (0 != UNLINK (d->cfgfile)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink"); - } - } - GNUNET_free (d->cfgfile); - GNUNET_free_non_null (d->hostname); - GNUNET_free_non_null (d->username); - if (NULL != d->dead_cb) - d->dead_cb (d->dead_cb_cls, NULL); - /* FIXME: this should be an assert and the test below - should not be required, but testing is broken... */ - GNUNET_break (NULL == d->proc_arm_stop); - if (NULL == d->proc_arm_stop) - GNUNET_free (d); - return; - } - - del_arg = NULL; - if (delete_files == GNUNET_YES) - { - GNUNET_asprintf (&del_arg, "-d"); - } - - if (d->phase == SP_CONFIG_UPDATE) - { - GNUNET_SCHEDULER_cancel (d->task); - d->phase = SP_START_DONE; - } - /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop? - if (d->server != NULL) - { - GNUNET_CORE_disconnect (d->server); - d->server = NULL; - } - */ - /* shutdown ARM process (will terminate others) */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminating peer `%4s'\n" , - GNUNET_i2s (&d->id)); - d->phase = SP_SHUTDOWN_START; - d->running = GNUNET_NO; - if (allow_restart == GNUNET_YES) - d->churn = GNUNET_YES; - if (d->th != NULL) - { - GNUNET_TRANSPORT_get_hello_cancel (d->ghh); - d->ghh = NULL; - GNUNET_TRANSPORT_disconnect (d->th); - d->th = NULL; - } - /* Check if this is a local or remote process */ - - - if (NULL != d->hostname) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with config `%s' on host `%s'.\n", - d->cfgfile, d->hostname); - if (d->username != NULL) - GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); - else - arg = GNUNET_strdup (d->hostname); - - d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", - "-q", - arg, "gnunet-arm", - "-c", d->cfgfile, "-e", "-q", "-T", - GNUNET_TIME_relative_to_string (timeout), - del_arg, NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n", - arg, "gnunet-arm", d->cfgfile, del_arg); - /* Use -e to end arm, and -d to remove temp files */ - GNUNET_free (arg); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); - d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "gnunet-arm", "gnunet-arm", - "-c", d->cfgfile, "-e", "-q", "-T", - GNUNET_TIME_relative_to_string (timeout), - del_arg, NULL); - GNUNET_assert (NULL != d->proc_arm_stop); - } - - GNUNET_free_non_null (del_arg); - d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - if (GNUNET_SCHEDULER_NO_TASK != d->task) - GNUNET_SCHEDULER_cancel(d->task); - d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); -} - - -/** - * Changes the configuration of a GNUnet daemon. - * - * @param d the daemon that should be modified - * @param cfg the new configuration for the daemon - * @param cb function called once the configuration was changed - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, - struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls) -{ - char *arg; - - if (d->phase != SP_START_DONE) - { - if (NULL != cb) - cb (cb_cls, - _ - ("Peer not yet running, can not change configuration at this point.")); - return; - } - - /* 1) write configuration to temporary file */ - if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile)) - { - if (NULL != cb) - cb (cb_cls, _("Failed to write new configuration to disk.")); - return; - } - - /* 2) copy file to remote host (if necessary) */ - if (NULL == d->hostname) - { - /* signal success */ - if (NULL != cb) - cb (cb_cls, NULL); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying updated configuration file to remote host `%s'.\n", - d->hostname); - d->phase = SP_CONFIG_UPDATE; - if (NULL != d->username) - GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile); - else - GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile); - d->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", - "-q", - d->cfgfile, arg, NULL); - GNUNET_free (arg); - if (NULL == d->proc_arm_copying) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not start `%s' process to copy configuration file.\n"), - "scp"); - if (NULL != cb) - cb (cb_cls, _("Failed to copy new configuration to remote machine.")); - d->phase = SP_START_DONE; - return; - } - d->update_cb = cb; - d->update_cb_cls = cb_cls; - d->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); -} - - -/** - * Data kept for each pair of peers that we try - * to connect. - */ -struct GNUNET_TESTING_ConnectContext -{ - /** - * Testing handle to the first daemon. - */ - struct GNUNET_TESTING_Daemon *d1; - - /** - * Handle to core of first daemon (to check connect) - */ - struct GNUNET_CORE_Handle *d1core; - - /** - * Have we actually connected to the core of the first daemon yet? - */ - int d1core_ready; - - /** - * Testing handle to the second daemon. - */ - struct GNUNET_TESTING_Daemon *d2; - - /** - * Transport handle to the first daemon (to offer the HELLO of the second daemon to). - */ - struct GNUNET_TRANSPORT_Handle *d1th; - - /** - * Function to call once we are done (or have timed out). - */ - GNUNET_TESTING_NotifyConnection cb; - - /** - * Closure for "nb". - */ - void *cb_cls; - - /** - * The relative timeout from whence this connect attempt was - * started. Allows for reconnect attempts. - */ - struct GNUNET_TIME_Relative relative_timeout; - - /** - * Maximum number of connect attempts, will retry connection - * this number of times on failures. - */ - unsigned int connect_attempts; - - /** - * Hello timeout task - */ - GNUNET_SCHEDULER_TaskIdentifier hello_send_task; - - /** - * Connect timeout task - */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; - - /** - * When should this operation be complete (or we must trigger - * a timeout). - */ - struct GNUNET_TIME_Relative timeout_hello; - - /** - * Was the connection attempt successful? - */ - int connected; - - /** - * When connecting, do we need to send the HELLO? - */ - int send_hello; - - /** - * The distance between the two connected peers - */ - uint32_t distance; -}; - - -/** Forward declaration **/ -static void -reattempt_daemons_connect (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Notify callback about success or failure of the attempt - * to connect the two peers - * - * @param cls our "struct GNUNET_TESTING_ConnectContext" (freed) - * @param tc reason tells us if we succeeded or failed - */ -static void -notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TESTING_ConnectContext *ctx = cls; - - ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; - if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (ctx->hello_send_task); - ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; - } - - if (ctx->d1th != NULL) - GNUNET_TRANSPORT_disconnect (ctx->d1th); - ctx->d1th = NULL; - if (ctx->d1core != NULL) - GNUNET_CORE_disconnect (ctx->d1core); - ctx->d1core = NULL; - - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - { - GNUNET_free (ctx); - return; - } - - if (ctx->connected == GNUNET_YES) - { - if (ctx->cb != NULL) - { - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->distance, - ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL); - } - } - else if (ctx->connect_attempts > 0) - { - ctx->d1core_ready = GNUNET_NO; - ctx->timeout_task = - GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx); - return; - } - else - { - if (ctx->cb != NULL) - { - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, - ctx->d2->cfg, ctx->d1, ctx->d2, _("Peers failed to connect")); - } - } - GNUNET_free (ctx); -} - - -/** - * Success, connection is up. Signal client our success. - * - * @param cls our "struct GNUNET_TESTING_ConnectContext" - * @param peer identity of the peer that has connected - * @param atsi performance information - * @param atsi_count number of records in 'atsi' - * - */ -static void -connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_ATS_Information *atsi, - unsigned int atsi_count) -{ - struct GNUNET_TESTING_ConnectContext *ctx = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", - ctx->d1->shortname, GNUNET_i2s (peer)); - if (0 != memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))) - return; - ctx->connected = GNUNET_YES; - ctx->distance = 0; /* FIXME: distance */ - if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (ctx->hello_send_task); - ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_SCHEDULER_cancel (ctx->timeout_task); - ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); -} - - -static void -send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TESTING_ConnectContext *ctx = cls; - struct GNUNET_MessageHeader *hello; - - ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - return; - if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL) && - (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)) && - (ctx->d1->phase == SP_START_DONE) && (ctx->d2->phase == SP_START_DONE)) - { - hello = GNUNET_HELLO_get_header (ctx->d2->hello); - GNUNET_assert (hello != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n", - ctx->d2->shortname, ctx->d1->shortname); - GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL); - GNUNET_assert (ctx->d1core != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending connect request to TRANSPORT of %s for peer %s\n", - GNUNET_i2s (&ctx->d1->id), - GNUNET_h2s (&ctx->d2->id.hashPubKey)); - GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); - ctx->timeout_hello = - GNUNET_TIME_relative_add (ctx->timeout_hello, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 500)); - } - ctx->hello_send_task = - GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello, &send_hello, ctx); -} - -/** - * Notify of a successful connection to the core service. - * - * @param cls a ConnectContext - * @param server handle to the core service - * @param my_identity the peer identity of this peer - */ -void -core_init_notify (void *cls, struct GNUNET_CORE_Handle *server, - const struct GNUNET_PeerIdentity *my_identity) -{ - struct GNUNET_TESTING_ConnectContext *connect_ctx = cls; - - connect_ctx->d1core_ready = GNUNET_YES; - - if (connect_ctx->send_hello == GNUNET_NO) - { - GNUNET_TRANSPORT_try_connect (connect_ctx->d1th, &connect_ctx->d2->id); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending connect request to TRANSPORT of %s for peer %s\n", - connect_ctx->d1->shortname, connect_ctx->d2->shortname); - } -} - - -/** - * Try to connect again some peers that failed in an earlier attempt. This will - * be tried as many times as connection_attempts in the configuration file. - * - * @param cls Closure (connection context between the two peers). - * @param tc TaskContext. - */ -static void -reattempt_daemons_connect (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TESTING_ConnectContext *ctx = cls; - - ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "re-attempting connect of peer %s to peer %s\n", - ctx->d1->shortname, ctx->d2->shortname); - ctx->connect_attempts--; - GNUNET_assert (ctx->d1core == NULL); - ctx->d1core_ready = GNUNET_NO; - ctx->d1core = - GNUNET_CORE_connect (ctx->d1->cfg, ctx, &core_init_notify, - &connect_notify, NULL, NULL, GNUNET_NO, NULL, - GNUNET_NO, no_handlers); - if (ctx->d1core == NULL) - { - if (NULL != ctx->cb) - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, - ctx->d2->cfg, ctx->d1, ctx->d2, - _("Failed to connect to core service of first peer!\n")); - GNUNET_free (ctx); - return; - } - - /* Don't know reason for initial connect failure, update the HELLO for the second peer */ - if (NULL != ctx->d2->hello) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "updating %s's HELLO\n", - ctx->d2->shortname); - GNUNET_free (ctx->d2->hello); - ctx->d2->hello = NULL; - if (NULL != ctx->d2->th) - { - GNUNET_TRANSPORT_get_hello_cancel (ctx->d2->ghh); - ctx->d2->ghh = NULL; - GNUNET_TRANSPORT_disconnect (ctx->d2->th); - } - ctx->d2->th = - GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, - NULL); - GNUNET_assert (ctx->d2->th != NULL); - ctx->d2->ghh = - GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "didn't have %s's HELLO\n", - ctx->d2->shortname); - } - - if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "didn't have %s's HELLO, trying to get it now\n", - ctx->d2->shortname); - ctx->d2->th = - GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, - NULL); - if (NULL == ctx->d2->th) - { - GNUNET_CORE_disconnect (ctx->d1core); - GNUNET_free (ctx); - if (NULL != ctx->cb) - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, - ctx->d2->cfg, ctx->d1, ctx->d2, - _("Failed to connect to transport service!\n")); - return; - } - ctx->d2->ghh = - GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); - } - else - { - if (NULL == ctx->d2->hello) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "didn't have %s's HELLO but th wasn't NULL, not trying!!\n", - ctx->d2->shortname); - } - } - - if (ctx->send_hello == GNUNET_YES) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %s's HELLO to %s\n", - ctx->d1->shortname, ctx->d2->shortname); - ctx->d1th = - GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, - NULL, NULL); - if (ctx->d1th == NULL) - { - GNUNET_CORE_disconnect (ctx->d1core); - GNUNET_free (ctx); - if (NULL != ctx->cb) - ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, - ctx->d2->cfg, ctx->d1, ctx->d2, - _("Failed to connect to transport service!\n")); - return; - } - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); - ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to reconnect %s to %s\n", - ctx->d1->shortname, ctx->d2->shortname); - GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); - } - ctx->timeout_task = - GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, - ¬ify_connect_result, ctx); -} - -/** - * Iterator for currently known peers, to ensure - * that we don't try to send duplicate connect - * requests to core. - * - * @param cls our "struct GNUNET_TESTING_ConnectContext" - * @param peer identity of the peer that has connected, - * NULL when iteration has finished - * @param atsi performance information - * @param atsi_count number of records in 'atsi' - * - */ -static void -core_initial_iteration (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_ATS_Information *atsi, - unsigned int atsi_count) -{ - struct GNUNET_TESTING_ConnectContext *ctx = cls; - - if ((peer != NULL) && - (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))) - { - ctx->connected = GNUNET_YES; - ctx->distance = 0; /* FIXME: distance */ - return; - } - if (peer != NULL) - return; /* ignore other peers */ - /* peer == NULL: End of iteration over peers */ - - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->timeout_task); - if (ctx->connected == GNUNET_YES) - { - ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); - return; - } - - /* Peer not already connected, need to schedule connect request! */ - if (ctx->d1core == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Peers are NOT connected, connecting to core!\n"); - ctx->d1core = - GNUNET_CORE_connect (ctx->d1->cfg, ctx, &core_init_notify, - &connect_notify, NULL, NULL, GNUNET_NO, NULL, - GNUNET_NO, no_handlers); - } - - if (ctx->d1core == NULL) - { - ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); - return; - } - - if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) /* Do not yet have the second peer's hello, set up a task to get it */ - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Don't have d2's HELLO, trying to get it!\n"); - ctx->d2->th = - GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, - NULL); - if (ctx->d2->th == NULL) - { - GNUNET_CORE_disconnect (ctx->d1core); - ctx->d1core = NULL; - ctx->timeout_task = - GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); - return; - } - ctx->d2->ghh = - GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); - } - - if (ctx->send_hello == GNUNET_YES) - { - ctx->d1th = - GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, - NULL, NULL); - if (ctx->d1th == NULL) - { - GNUNET_CORE_disconnect (ctx->d1core); - ctx->d1core = NULL; - ctx->timeout_task = - GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); - return; - } - GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); - ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); - } - - ctx->timeout_task = - GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, - ¬ify_connect_result, ctx); - -} - - -/** - * Establish a connection between two GNUnet daemons. The daemons - * must both be running and not be stopped until either the - * 'cb' callback is called OR the connection request has been - * explicitly cancelled. - * - * @param d1 handle for the first daemon - * @param d2 handle for the second daemon - * @param timeout how long is the connection attempt - * allowed to take? - * @param max_connect_attempts how many times should we try to reconnect - * (within timeout) - * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume - * the HELLO has already been exchanged - * @param cb function to call at the end - * @param cb_cls closure for cb - * @return handle to cancel the request - */ -struct GNUNET_TESTING_ConnectContext * -GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, - struct GNUNET_TESTING_Daemon *d2, - struct GNUNET_TIME_Relative timeout, - unsigned int max_connect_attempts, - int send_hello, - GNUNET_TESTING_NotifyConnection cb, - void *cb_cls) -{ - struct GNUNET_TESTING_ConnectContext *ctx; - - if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO)) - { - if (NULL != cb) - cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2, - _("Peers are not fully running yet, can not connect!\n")); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n"); - return NULL; - } - - ctx = GNUNET_malloc (sizeof (struct GNUNET_TESTING_ConnectContext)); - ctx->d1 = d1; - ctx->d2 = d2; - ctx->timeout_hello = - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500); - ctx->relative_timeout = - GNUNET_TIME_relative_divide (timeout, max_connect_attempts); - ctx->cb = cb; - ctx->cb_cls = cb_cls; - ctx->connect_attempts = max_connect_attempts; - ctx->connected = GNUNET_NO; - ctx->send_hello = send_hello; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n", - d1->shortname, d2->shortname); - /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */ - GNUNET_assert (NULL != - GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, - &core_initial_iteration, ctx)); - return ctx; -} - - -/** - * Cancel an attempt to connect two daemons. - * - * @param cc connect context - */ -void -GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext *cc) -{ - if (GNUNET_SCHEDULER_NO_TASK != cc->timeout_task) - { - GNUNET_SCHEDULER_cancel (cc->timeout_task); - cc->timeout_task = GNUNET_SCHEDULER_NO_TASK; - } - if (GNUNET_SCHEDULER_NO_TASK != cc->hello_send_task) - { - GNUNET_SCHEDULER_cancel (cc->hello_send_task); - cc->hello_send_task = GNUNET_SCHEDULER_NO_TASK; - } - if (NULL != cc->d1core) - { - GNUNET_CORE_disconnect (cc->d1core); - cc->d1core = NULL; - } - if (NULL != cc->d1th) - { - GNUNET_TRANSPORT_disconnect (cc->d1th); - cc->d1th = NULL; - } - GNUNET_free (cc); -} - - -/* end of testing.c */ diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c deleted file mode 100644 index 75c0e617d..000000000 --- a/src/testing/testing_group.c +++ /dev/null @@ -1,7038 +0,0 @@ -/* - This file is part of GNUnet - (C) 2008, 2009 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 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 testing/testing_group.c - * @brief convenience API for writing testcases for GNUnet - * @author Nathan Evans - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_constants.h" -#include "gnunet_arm_service.h" -#include "gnunet_testing_lib.h" -#include "gnunet_core_service.h" - -#define USE_START_HELPER GNUNET_YES - -#define OLD 1 - -/* Before connecting peers, send all of the HELLOs */ -#define USE_SEND_HELLOS GNUNET_NO - -#define TOPOLOGY_HACK GNUNET_YES - - -/** - * Lowest port used for GNUnet testing. Should be high enough to not - * conflict with other applications running on the hosts but be low - * enough to not conflict with client-ports (typically starting around - * 32k). - */ -#define LOW_PORT 12000 - -/** - * Highest port used for GNUnet testing. Should be low enough to not - * conflict with the port range for "local" ports (client apps; see - * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). - */ -#define HIGH_PORT 56000 - -/* Maximum time to delay connect attempt */ -#define MAX_CONNECT_DELAY 300 - -/** - * Which list of peers do we need to modify? - */ -enum PeerLists -{ - /** Modify allowed peers */ - ALLOWED, - - /** Modify connect peers */ - CONNECT, - - /** Modify blacklist peers */ - BLACKLIST, - - /** Modify workingset peers */ - WORKING_SET -}; - -/** - * Prototype of a function called whenever two peers would be connected - * in a certain topology. - */ -typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct - GNUNET_TESTING_PeerGroup - * pg, - unsigned int first, - unsigned int second, - enum PeerLists list, - unsigned int check); - -/** - * Context for handling churning a peer group - */ -struct ChurnContext -{ - /** - * The peergroup we are dealing with. - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * Name of the service to churn on/off, NULL - * to churn entire peer. - */ - char *service; - - /** - * Callback used to notify of churning finished - */ - GNUNET_TESTING_NotifyCompletion cb; - - /** - * Closure for callback - */ - void *cb_cls; - - /** - * Number of peers that still need to be started - */ - unsigned int num_to_start; - - /** - * Number of peers that still need to be stopped - */ - unsigned int num_to_stop; - - /** - * Number of peers that failed to start - */ - unsigned int num_failed_start; - - /** - * Number of peers that failed to stop - */ - unsigned int num_failed_stop; -}; - -struct RestartContext -{ - /** - * The group of peers being restarted - */ - struct GNUNET_TESTING_PeerGroup *peer_group; - - /** - * How many peers have been restarted thus far - */ - unsigned int peers_restarted; - - /** - * How many peers got an error when restarting - */ - unsigned int peers_restart_failed; - - /** - * The function to call once all peers have been restarted - */ - GNUNET_TESTING_NotifyCompletion callback; - - /** - * Closure for callback function - */ - void *callback_cls; - -}; - -struct SendHelloContext -{ - /** - * Global handle to the peer group. - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * The data about this specific peer. - */ - struct PeerData *peer; - - /** - * The next HELLO that needs sent to this peer. - */ - struct PeerConnection *peer_pos; - - /** - * Are we connected to CORE yet? - */ - unsigned int core_ready; - - /** - * How many attempts should we make for failed connections? - */ - unsigned int connect_attempts; - - /** - * Task for scheduling core connect requests to be sent. - */ - GNUNET_SCHEDULER_TaskIdentifier core_connect_task; -}; - -struct ShutdownContext -{ - struct GNUNET_TESTING_PeerGroup *pg; - /** - * Total peers to wait for - */ - unsigned int total_peers; - - /** - * Number of peers successfully shut down - */ - unsigned int peers_down; - - /** - * Number of peers failed to shut down - */ - unsigned int peers_failed; - - /** - * Number of peers we have started shutting - * down. If too many, wait on them. - */ - unsigned int outstanding; - - /** - * Timeout for shutdown. - */ - struct GNUNET_TIME_Relative timeout; - - /** - * Callback to call when all peers either - * shutdown or failed to shutdown - */ - GNUNET_TESTING_NotifyCompletion cb; - - /** - * Closure for cb - */ - void *cb_cls; - - /** - * Should we delete all of the files from the peers? - */ - int delete_files; -}; - -/** - * Individual shutdown context for a particular peer. - */ -struct PeerShutdownContext -{ - /** - * Pointer to the high level shutdown context. - */ - struct ShutdownContext *shutdown_ctx; - - /** - * The daemon handle for the peer to shut down. - */ - struct GNUNET_TESTING_Daemon *daemon; -}; - -/** - * Individual shutdown context for a particular peer. - */ -struct PeerRestartContext -{ - /** - * Pointer to the high level restart context. - */ - struct ChurnRestartContext *churn_restart_ctx; - - /** - * The daemon handle for the peer to shut down. - */ - struct GNUNET_TESTING_Daemon *daemon; -}; - -struct ServiceStartContext -{ - struct GNUNET_TESTING_PeerGroup *pg; - unsigned int remaining; - GNUNET_TESTING_NotifyCompletion cb; - unsigned int outstanding; - char *service; - struct GNUNET_TIME_Relative timeout; - void *cb_cls; -}; - -/** - * Individual shutdown context for a particular peer. - */ -struct PeerServiceStartContext -{ - /** - * Pointer to the high level start context. - */ - struct ServiceStartContext *start_ctx; - - /** - * The daemon handle for the peer to start the service on. - */ - struct GNUNET_TESTING_Daemon *daemon; -}; - -struct CreateTopologyContext -{ - - /** - * Function to call with number of connections - */ - GNUNET_TESTING_NotifyConnections cont; - - /** - * Closure for connection notification - */ - void *cls; -}; - -enum States -{ - /** Waiting to read number of peers */ - NUM_PEERS, - - /** Should find next peer index */ - PEER_INDEX, - - /** Should find colon */ - COLON, - - /** Should read other peer index, space, or endline */ - OTHER_PEER_INDEX -}; - -#if OLD -struct PeerConnection -{ - /** - * Doubly Linked list - */ - struct PeerConnection *prev; - - /* - * Doubly Linked list - */ - struct PeerConnection *next; - - /* - * Index of daemon in pg->peers - */ - uint32_t index; - -}; -#endif - -struct InternalStartContext -{ - /** - * Pointer to peerdata - */ - struct PeerData *peer; - - /** - * Timeout for peer startup - */ - struct GNUNET_TIME_Relative timeout; - - /** - * Client callback for hostkey notification - */ - GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; - - /** - * Closure for hostkey_callback - */ - void *hostkey_cls; - - /** - * Client callback for peer start notification - */ - GNUNET_TESTING_NotifyDaemonRunning start_cb; - - /** - * Closure for cb - */ - void *start_cb_cls; - - /** - * Hostname, where to start the peer - */ - const char *hostname; - - /** - * Username to use when connecting to the - * host via ssh. - */ - const char *username; - - /** - * Pointer to starting memory location of a hostkey - */ - const char *hostkey; - - /** - * Port to use for ssh. - */ - uint16_t sshport; - -}; - -struct ChurnRestartContext -{ - /** - * PeerGroup that we are working with. - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * Number of restarts currently in flight. - */ - unsigned int outstanding; - - /** - * Handle to the underlying churn context. - */ - struct ChurnContext *churn_ctx; - - /** - * How long to allow the operation to take. - */ - struct GNUNET_TIME_Relative timeout; -}; - -struct OutstandingSSH -{ - struct OutstandingSSH *next; - - struct OutstandingSSH *prev; - - /** - * Number of current ssh connections. - */ - uint32_t outstanding; - - /** - * The hostname of this peer. - */ - const char *hostname; -}; - -/** - * Data we keep per peer. - */ -struct PeerData -{ - /** - * (Initial) configuration of the host. - * (initial because clients could change - * it and we would not know about those - * updates). - */ - struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Handle for controlling the daemon. - */ - struct GNUNET_TESTING_Daemon *daemon; - - /** - * The peergroup this peer belongs to. - */ - struct GNUNET_TESTING_PeerGroup *pg; - -#if OLD - /** - * Linked list of allowed peer connections. - */ - struct PeerConnection *allowed_peers_head; - - /** - * Linked list of allowed peer connections. - */ - struct PeerConnection *allowed_peers_tail; - - /** - * Linked list of blacklisted peer connections. - */ - struct PeerConnection *blacklisted_peers_head; - - /** - * Linked list of blacklisted peer connections. - */ - struct PeerConnection *blacklisted_peers_tail; - - /** - * Linked list of connect peer connections. - */ - struct PeerConnection *connect_peers_head; - - /** - * Linked list of connect peer connections. - */ - struct PeerConnection *connect_peers_tail; - - /** - * Linked list of connect peer connections. - */ - struct PeerConnection *connect_peers_working_set_head; - - /** - * Linked list of connect peer connections. - */ - struct PeerConnection *connect_peers_working_set_tail; - -#else - /** - * Hash map of allowed peer connections (F2F created topology) - */ - struct GNUNET_CONTAINER_MultiHashMap *allowed_peers; - - /** - * Hash map of blacklisted peers - */ - struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers; - - /** - * Hash map of peer connections - */ - struct GNUNET_CONTAINER_MultiHashMap *connect_peers; - - /** - * Temporary hash map of peer connections - */ - struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set; -#endif - - /** - * Temporary variable for topology creation, should be reset before - * creating any topology so the count is valid once finished. - */ - int num_connections; - - /** - * Context to keep track of peers being started, to - * stagger hostkey generation and peer startup. - */ - struct InternalStartContext internal_context; - - /** - * Task ID for the queued internal_continue_startup task - */ - GNUNET_SCHEDULER_TaskIdentifier startup_task; - -}; - -/** - * Linked list of per-host data. - */ -struct HostData -{ - /** - * Name of the host. - */ - char *hostname; - - /** - * SSH username to use when connecting to this host. - */ - char *username; - - /** - * SSH port to use when connecting to this host. - */ - uint16_t sshport; - - /** - * Lowest port that we have not yet used - * for GNUnet. - */ - uint16_t minport; -}; - -struct TopologyIterateContext -{ - /** - * The peergroup we are working with. - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * Callback for notifying of two connected peers. - */ - GNUNET_TESTING_NotifyTopology topology_cb; - - /** - * Closure for topology_cb - */ - void *cls; - - /** - * Number of peers currently connected to. - */ - unsigned int connected; - - /** - * Number of peers we have finished iterating. - */ - unsigned int completed; - - /** - * Number of peers total. - */ - unsigned int total; -}; - -struct StatsIterateContext -{ - /** - * The peergroup that we are dealing with. - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * Continuation to call once all stats information has been retrieved. - */ - GNUNET_STATISTICS_Callback cont; - - /** - * Proc function to call on each value received. - */ - GNUNET_TESTING_STATISTICS_Iterator proc; - - /** - * Closure for topology_cb - */ - void *cls; - - /** - * Number of peers currently connected to. - */ - unsigned int connected; - - /** - * Number of peers we have finished iterating. - */ - unsigned int completed; - - /** - * Number of peers total. - */ - unsigned int total; -}; - -struct CoreContext -{ - void *iter_context; - struct GNUNET_TESTING_Daemon *daemon; -}; - -struct StatsCoreContext -{ - void *iter_context; - struct GNUNET_TESTING_Daemon *daemon; - /** - * Handle to the statistics service. - */ - struct GNUNET_STATISTICS_Handle *stats_handle; - - /** - * Handle for getting statistics. - */ - struct GNUNET_STATISTICS_GetHandle *stats_get_handle; -}; - -struct ConnectTopologyContext -{ - /** - * How many connections are left to create. - */ - unsigned int remaining_connections; - - /** - * Handle to group of peers. - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * How long to try this connection before timing out. - */ - struct GNUNET_TIME_Relative connect_timeout; - - /** - * How many times to retry connecting the two peers. - */ - unsigned int connect_attempts; - - /** - * Temp value set for each iteration. - */ - //struct PeerData *first; - - /** - * Notification that all peers are connected. - */ - GNUNET_TESTING_NotifyCompletion notify_connections_done; - - /** - * Closure for notify. - */ - void *notify_cls; -}; - -struct ConnectContext; - -/** - * Handle to a group of GNUnet peers. - */ -struct GNUNET_TESTING_PeerGroup -{ - /** - * Configuration template. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - struct ConnectContext *cc_head; - - struct ConnectContext *cc_tail; - - /** - * Function to call on each started daemon. - */ - //GNUNET_TESTING_NotifyDaemonRunning cb; - - /** - * Closure for cb. - */ - //void *cb_cls; - - /* - * Function to call on each topology connection created - */ - GNUNET_TESTING_NotifyConnection notify_connection; - - /* - * Callback for notify_connection - */ - void *notify_connection_cls; - - /** - * Array of information about hosts. - */ - struct HostData *hosts; - - /** - * Number of hosts (size of HostData) - */ - unsigned int num_hosts; - - /** - * Array of "total" peers. - */ - struct PeerData *peers; - - /** - * Number of peers in this group. - */ - unsigned int total; - - /** - * At what time should we fail the peer startup process? - */ - struct GNUNET_TIME_Absolute max_timeout; - - /** - * How many peers are being started right now? - */ - unsigned int starting; - - /** - * How many peers have already been started? - */ - unsigned int started; - - /** - * Number of possible connections to peers - * at a time. - */ - unsigned int max_outstanding_connections; - - /** - * Number of ssh connections to peers (max). - */ - unsigned int max_concurrent_ssh; - - /** - * Number of connects we are waiting on, allows us to rate limit - * connect attempts. - */ - unsigned int outstanding_connects; - - /** - * Number of HELLOs we have yet to send. - */ - unsigned int remaining_hellos; - - /** - * How many connects have already been scheduled? - */ - unsigned int total_connects_scheduled; - - /** - * Hostkeys loaded from a file. - */ - char *hostkey_data; - - /** - * Head of DLL to keep track of the number of outstanding - * ssh connections per peer. - */ - struct OutstandingSSH *ssh_head; - - /** - * Tail of DLL to keep track of the number of outstanding - * ssh connections per peer. - */ - struct OutstandingSSH *ssh_tail; - - /** - * Stop scheduling peers connecting. - */ - unsigned int stop_connects; - - /** - * Connection context for peer group. - */ - struct ConnectTopologyContext ct_ctx; -}; - -struct UpdateContext -{ - /** - * The altered configuration. - */ - struct GNUNET_CONFIGURATION_Handle *ret; - - /** - * The original configuration to alter. - */ - const struct GNUNET_CONFIGURATION_Handle *orig; - - /** - * The hostname that this peer will run on. - */ - const char *hostname; - - /** - * The next possible port to assign. - */ - unsigned int nport; - - /** - * Unique number for unix domain sockets. - */ - unsigned int upnum; - - /** - * Unique number for this peer/host to offset - * things that are grouped by host. - */ - unsigned int fdnum; -}; - -struct ConnectContext -{ - - struct ConnectContext *next; - - struct ConnectContext *prev; - - /** - * Index of peer to connect second to. - */ - uint32_t first_index; - - /** - * Index of peer to connect first to. - */ - uint32_t second_index; - - /** - * Task associated with the attempt to connect. - */ - GNUNET_SCHEDULER_TaskIdentifier task; - - /** - * Context in 'testing.c', to cancel connection attempt. - */ - struct GNUNET_TESTING_ConnectContext *cc; - - /** - * Higher level topology connection context. - */ - struct ConnectTopologyContext *ct_ctx; - - /** - * Whether this connection has been accounted for in the schedule_connect call. - */ - int counted; -}; - -struct UnblacklistContext -{ - /** - * The peergroup - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * uid of the first peer - */ - uint32_t first_uid; -}; - -struct RandomContext -{ - /** - * The peergroup - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * uid of the first peer - */ - uint32_t first_uid; - - /** - * Peer data for first peer. - */ - struct PeerData *first; - - /** - * Random percentage to use - */ - double percentage; -}; - -struct MinimumContext -{ - /** - * The peergroup - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * uid of the first peer - */ - uint32_t first_uid; - - /** - * Peer data for first peer. - */ - struct PeerData *first; - - /** - * Number of conns per peer - */ - unsigned int num_to_add; - - /** - * Permuted array of all possible connections. Only add the Nth - * peer if it's in the Nth position. - */ - unsigned int *pg_array; - - /** - * What number is the current element we are iterating over? - */ - unsigned int current; -}; - -struct DFSContext -{ - /** - * The peergroup - */ - struct GNUNET_TESTING_PeerGroup *pg; - - /** - * uid of the first peer - */ - uint32_t first_uid; - - /** - * uid of the second peer - */ - uint32_t second_uid; - - /** - * Peer data for first peer. - */ - struct PeerData *first; - - /** - * Which peer has been chosen as the one to add? - */ - unsigned int chosen; - - /** - * What number is the current element we are iterating over? - */ - unsigned int current; -}; - -/** - * Simple struct to keep track of progress, and print a - * nice little percentage meter for long running tasks. - */ -struct ProgressMeter -{ - unsigned int total; - - unsigned int modnum; - - unsigned int dotnum; - - unsigned int completed; - - int print; - - char *startup_string; -}; - -#if !OLD -/** - * Convert unique ID to hash code. - * - * @param uid unique ID to convert - * @param hash set to uid (extended with zeros) - */ -static void -hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) -{ - memset (hash, 0, sizeof (GNUNET_HashCode)); - *((uint32_t *) hash) = uid; -} - -/** - * Convert hash code to unique ID. - * - * @param uid unique ID to convert - * @param hash set to uid (extended with zeros) - */ -static void -uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid) -{ - memcpy (uid, hash, sizeof (uint32_t)); -} -#endif - -#if USE_SEND_HELLOS -static struct GNUNET_CORE_MessageHandler no_handlers[] = { - {NULL, 0, 0} -}; -#endif - -/** - * Create a meter to keep track of the progress of some task. - * - * @param total the total number of items to complete - * @param start_string a string to prefix the meter with (if printing) - * @param print GNUNET_YES to print the meter, GNUNET_NO to count - * internally only - * - * @return the progress meter - */ -static struct ProgressMeter * -create_meter (unsigned int total, char *start_string, int print) -{ - struct ProgressMeter *ret; - - ret = GNUNET_malloc (sizeof (struct ProgressMeter)); - ret->print = print; - ret->total = total; - ret->modnum = total / 4; - if (ret->modnum == 0) /* Divide by zero check */ - ret->modnum = 1; - ret->dotnum = (total / 50) + 1; - if (start_string != NULL) - ret->startup_string = GNUNET_strdup (start_string); - else - ret->startup_string = GNUNET_strdup (""); - - return ret; -} - -/** - * Update progress meter (increment by one). - * - * @param meter the meter to update and print info for - * - * @return GNUNET_YES if called the total requested, - * GNUNET_NO if more items expected - */ -static int -update_meter (struct ProgressMeter *meter) -{ - if (meter->print == GNUNET_YES) - { - if (meter->completed % meter->modnum == 0) - { - if (meter->completed == 0) - { - FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); - } - else - FPRINTF (stdout, "%d%%", - (int) (((float) meter->completed / meter->total) * 100)); - } - else if (meter->completed % meter->dotnum == 0) - FPRINTF (stdout, "%s", "."); - - if (meter->completed + 1 == meter->total) - FPRINTF (stdout, "%d%%]\n", 100); - fflush (stdout); - } - meter->completed++; - - if (meter->completed == meter->total) - return GNUNET_YES; - if (meter->completed > meter->total) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Progress meter overflow!!\n"); - return GNUNET_NO; -} - -/** - * Reset progress meter. - * - * @param meter the meter to reset - * - * @return GNUNET_YES if meter reset, - * GNUNET_SYSERR on error - */ -static int -reset_meter (struct ProgressMeter *meter) -{ - if (meter == NULL) - return GNUNET_SYSERR; - - meter->completed = 0; - return GNUNET_YES; -} - -/** - * Release resources for meter - * - * @param meter the meter to free - */ -static void -free_meter (struct ProgressMeter *meter) -{ - GNUNET_free_non_null (meter->startup_string); - GNUNET_free (meter); -} - -/** - * 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_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, - const char *topology_string) -{ - /** - * Strings representing topologies in enum - */ - static const char *topology_strings[] = { - /** - * A clique (everyone connected to everyone else). - */ - "CLIQUE", - - /** - * Small-world network (2d torus plus random links). - */ - "SMALL_WORLD", - - /** - * Small-world network (ring plus random links). - */ - "SMALL_WORLD_RING", - - /** - * Ring topology. - */ - "RING", - - /** - * 2-d torus. - */ - "2D_TORUS", - - /** - * Random graph. - */ - "ERDOS_RENYI", - - /** - * Certain percentage of peers are unable to communicate directly - * replicating NAT conditions - */ - "INTERNAT", - - /** - * Scale free topology. - */ - "SCALE_FREE", - - /** - * Straight line topology. - */ - "LINE", - - /** - * All peers are disconnected. - */ - "NONE", - - /** - * Read the topology from a file. - */ - "FROM_FILE", - - NULL - }; - - int curr = 0; - - if (topology_string == NULL) - return GNUNET_NO; - while (topology_strings[curr] != NULL) - { - if (strcasecmp (topology_strings[curr], topology_string) == 0) - { - *topology = curr; - return GNUNET_YES; - } - curr++; - } - *topology = GNUNET_TESTING_TOPOLOGY_NONE; - return GNUNET_NO; -} - -/** - * Get connect topology option from string input. - * - * @param topology_option where to write the retrieved topology - * @param topology_string The string to attempt to - * get a configuration value from - * @return GNUNET_YES if string matched a known - * topology option, GNUNET_NO if not - */ -int -GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption - *topology_option, - const char *topology_string) -{ - /** - * Options for connecting a topology as strings. - */ - static const char *topology_option_strings[] = { - /** - * Try to connect all peers specified in the topology. - */ - "CONNECT_ALL", - - /** - * Choose a random subset of connections to create. - */ - "CONNECT_RANDOM_SUBSET", - - /** - * Create at least X connections for each peer. - */ - "CONNECT_MINIMUM", - - /** - * Using a depth first search, create one connection - * per peer. If any are missed (graph disconnected) - * start over at those peers until all have at least one - * connection. - */ - "CONNECT_DFS", - - /** - * Find the N closest peers to each allowed peer in the - * topology and make sure a connection to those peers - * exists in the connect topology. - */ - "CONNECT_CLOSEST", - - /** - * No options specified. - */ - "CONNECT_NONE", - - NULL - }; - int curr = 0; - - if (topology_string == NULL) - return GNUNET_NO; - while (NULL != topology_option_strings[curr]) - { - if (strcasecmp (topology_option_strings[curr], topology_string) == 0) - { - *topology_option = curr; - return GNUNET_YES; - } - curr++; - } - *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE; - return GNUNET_NO; -} - -/** - * Function to iterate over options. Copies - * the options to the target configuration, - * updating PORT values as needed. - * - * @param cls closure - * @param section name of the section - * @param option name of the option - * @param value value of the option - */ -static void -update_config (void *cls, const char *section, const char *option, - const char *value) -{ - struct UpdateContext *ctx = cls; - unsigned int ival; - char cval[12]; - char uval[128]; - char *single_variable; - char *per_host_variable; - unsigned long long num_per_host; - - GNUNET_asprintf (&single_variable, "single_%s_per_host", section); - GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); - - if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival))) - { - if ((ival != 0) && - (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", - single_variable))) - { - GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++); - value = cval; - } - else if ((ival != 0) && - (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", - single_variable)) && - GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", - per_host_variable, - &num_per_host)) - { - GNUNET_snprintf (cval, sizeof (cval), "%u", - ival + ctx->fdnum % num_per_host); - value = cval; - } - - /* FIXME: REMOVE FOREVER HACK HACK HACK */ - if (0 == strcasecmp (section, "transport-tcp")) - GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, - "ADVERTISED_PORT", value); - } - - if (0 == strcmp (option, "UNIXPATH")) - { - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", - single_variable)) - { - GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, - ctx->upnum++); - value = uval; - } - else if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", - per_host_variable, - &num_per_host)) && - (num_per_host > 0)) - - { - GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, - ctx->fdnum % num_per_host); - value = uval; - } - } - - if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL)) - { - value = ctx->hostname; - } - GNUNET_free (single_variable); - GNUNET_free (per_host_variable); - GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value); -} - -/** - * Create a new configuration using the given configuration - * as a template; however, each PORT in the existing cfg - * must be renumbered by incrementing "*port". If we run - * out of "*port" numbers, return NULL. - * - * @param cfg template configuration - * @param off the current peer offset - * @param port port numbers to use, update to reflect - * port numbers that were used - * @param upnum number to make unix domain socket names unique - * @param hostname hostname of the controlling host, to allow control connections from - * @param fdnum number used to offset the unix domain socket for grouped processes - * (such as statistics or peerinfo, which can be shared among others) - * - * @return new configuration, NULL on error - */ -struct GNUNET_CONFIGURATION_Handle * -GNUNET_TESTING_create_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, - uint16_t * port, uint32_t * upnum, const char *hostname, - uint32_t * fdnum) -{ - struct UpdateContext uc; - uint16_t orig; - char *control_host; - char *allowed_hosts; - unsigned long long skew_variance; - unsigned long long skew_offset; - long long actual_offset; - - orig = *port; - uc.nport = *port; - uc.upnum = *upnum; - uc.fdnum = *fdnum; - uc.ret = GNUNET_CONFIGURATION_create (); - uc.hostname = hostname; - uc.orig = cfg; - - GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc); - if (uc.nport >= HIGH_PORT) - { - *port = orig; - GNUNET_CONFIGURATION_destroy (uc.ret); - return NULL; - } - - if ((GNUNET_OK == - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "skew_variance", - &skew_variance)) && - (skew_variance > 0)) - { - skew_offset = - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - skew_variance + 1); - actual_offset = - skew_offset - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - skew_variance + 1); - /* Min is -skew_variance, Max is skew_variance */ - skew_offset = skew_variance + actual_offset; /* Normal distribution around 0 */ - GNUNET_CONFIGURATION_set_value_number (uc.ret, "testing", "skew_offset", - skew_offset); - } - - if (GNUNET_CONFIGURATION_get_value_string - (cfg, "testing", "control_host", &control_host) == GNUNET_OK) - { - if (hostname != NULL) - GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1; %s;", control_host, - hostname); - else - GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", control_host); - - GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM", - allowed_hosts); - - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "ACCEPT_FROM", - allowed_hosts); - - GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "ACCEPT_FROM", - allowed_hosts); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM", - allowed_hosts); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "ACCEPT_FROM", - allowed_hosts); - - GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH", ""); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH", ""); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", ""); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", - ""); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "UNIXPATH", ""); - - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", - "USE_LOCALADDR", "YES"); - GNUNET_free_non_null (control_host); - GNUNET_free (allowed_hosts); - } - - /* arm needs to know to allow connections from the host on which it is running, - * otherwise gnunet-arm is unable to connect to it in some instances */ - if (hostname != NULL) - { - GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", hostname); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", hostname); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", - hostname); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", - hostname); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "disablev6", "BINDTO", - "YES"); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", - "USE_LOCALADDR", "YES"); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", - "USE_LOCALADDR", "YES"); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "arm", "ACCEPT_FROM", - allowed_hosts); - GNUNET_free (allowed_hosts); - } - else - { - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", - "USE_LOCALADDR", "YES"); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", - "127.0.0.1"); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", - "127.0.0.1"); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", - "127.0.0.1"); - GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "disablev6", - "YES"); - } - - *port = (uint16_t) uc.nport; - *upnum = uc.upnum; - uc.fdnum++; - *fdnum = uc.fdnum; - return uc.ret; -} - -/* - * Remove entries from the peer connection list - * - * @param pg the peer group we are working with - * @param first index of the first peer - * @param second index of the second peer - * @param list the peer list to use - * @param check UNUSED - * - * @return the number of connections added (can be 0, 1 or 2) - * - */ -static unsigned int -remove_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, - unsigned int second, enum PeerLists list, - unsigned int check) -{ - int removed; - -#if OLD - struct PeerConnection **first_list; - struct PeerConnection **second_list; - struct PeerConnection *first_iter; - struct PeerConnection *second_iter; - struct PeerConnection **first_tail; - struct PeerConnection **second_tail; - -#else - GNUNET_HashCode hash_first; - GNUNET_HashCode hash_second; - - hash_from_uid (first, &hash_first); - hash_from_uid (second, &hash_second); -#endif - - removed = 0; -#if OLD - switch (list) - { - case ALLOWED: - first_list = &pg->peers[first].allowed_peers_head; - second_list = &pg->peers[second].allowed_peers_head; - first_tail = &pg->peers[first].allowed_peers_tail; - second_tail = &pg->peers[second].allowed_peers_tail; - break; - case CONNECT: - first_list = &pg->peers[first].connect_peers_head; - second_list = &pg->peers[second].connect_peers_head; - first_tail = &pg->peers[first].connect_peers_tail; - second_tail = &pg->peers[second].connect_peers_tail; - break; - case BLACKLIST: - first_list = &pg->peers[first].blacklisted_peers_head; - second_list = &pg->peers[second].blacklisted_peers_head; - first_tail = &pg->peers[first].blacklisted_peers_tail; - second_tail = &pg->peers[second].blacklisted_peers_tail; - break; - case WORKING_SET: - first_list = &pg->peers[first].connect_peers_working_set_head; - second_list = &pg->peers[second].connect_peers_working_set_head; - first_tail = &pg->peers[first].connect_peers_working_set_tail; - second_tail = &pg->peers[second].connect_peers_working_set_tail; - break; - default: - GNUNET_break (0); - return 0; - } - - first_iter = *first_list; - while (first_iter != NULL) - { - if (first_iter->index == second) - { - GNUNET_CONTAINER_DLL_remove (*first_list, *first_tail, first_iter); - GNUNET_free (first_iter); - removed++; - break; - } - first_iter = first_iter->next; - } - - second_iter = *second_list; - while (second_iter != NULL) - { - if (second_iter->index == first) - { - GNUNET_CONTAINER_DLL_remove (*second_list, *second_tail, second_iter); - GNUNET_free (second_iter); - removed++; - break; - } - second_iter = second_iter->next; - } -#else - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (pg-> - peers[first].blacklisted_peers, - &hash_second)) - { - GNUNET_CONTAINER_multihashmap_remove_all (pg-> - peers[first].blacklisted_peers, - &hash_second); - } - - if (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_contains (pg-> - peers[second].blacklisted_peers, - &hash_first)) - { - GNUNET_CONTAINER_multihashmap_remove_all (pg-> - peers[second].blacklisted_peers, - &hash_first); - } -#endif - - return removed; -} - -/** - * Add entries to the some list - * - * @param pg the peer group we are working with - * @param first index of the first peer - * @param second index of the second peer - * @param list the list type that we should modify - * @param check GNUNET_YES to check lists before adding - * GNUNET_NO to force add - * - * @return the number of connections added (can be 0, 1 or 2) - * - */ -static unsigned int -add_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, - unsigned int second, enum PeerLists list, unsigned int check) -{ - int added; - int add_first; - int add_second; - - struct PeerConnection **first_list; - struct PeerConnection **second_list; - struct PeerConnection *first_iter; - struct PeerConnection *second_iter; - struct PeerConnection *new_first; - struct PeerConnection *new_second; - struct PeerConnection **first_tail; - struct PeerConnection **second_tail; - - switch (list) - { - case ALLOWED: - first_list = &pg->peers[first].allowed_peers_head; - second_list = &pg->peers[second].allowed_peers_head; - first_tail = &pg->peers[first].allowed_peers_tail; - second_tail = &pg->peers[second].allowed_peers_tail; - break; - case CONNECT: - first_list = &pg->peers[first].connect_peers_head; - second_list = &pg->peers[second].connect_peers_head; - first_tail = &pg->peers[first].connect_peers_tail; - second_tail = &pg->peers[second].connect_peers_tail; - break; - case BLACKLIST: - first_list = &pg->peers[first].blacklisted_peers_head; - second_list = &pg->peers[second].blacklisted_peers_head; - first_tail = &pg->peers[first].blacklisted_peers_tail; - second_tail = &pg->peers[second].blacklisted_peers_tail; - break; - case WORKING_SET: - first_list = &pg->peers[first].connect_peers_working_set_head; - second_list = &pg->peers[second].connect_peers_working_set_head; - first_tail = &pg->peers[first].connect_peers_working_set_tail; - second_tail = &pg->peers[second].connect_peers_working_set_tail; - break; - default: - GNUNET_break (0); - return 0; - } - - add_first = GNUNET_YES; - add_second = GNUNET_YES; - - if (check == GNUNET_YES) - { - first_iter = *first_list; - while (first_iter != NULL) - { - if (first_iter->index == second) - { - add_first = GNUNET_NO; - break; - } - first_iter = first_iter->next; - } - - second_iter = *second_list; - while (second_iter != NULL) - { - if (second_iter->index == first) - { - add_second = GNUNET_NO; - break; - } - second_iter = second_iter->next; - } - } - - added = 0; - if (add_first) - { - new_first = GNUNET_malloc (sizeof (struct PeerConnection)); - new_first->index = second; - GNUNET_CONTAINER_DLL_insert (*first_list, *first_tail, new_first); - pg->peers[first].num_connections++; - added++; - } - - if (add_second) - { - new_second = GNUNET_malloc (sizeof (struct PeerConnection)); - new_second->index = first; - GNUNET_CONTAINER_DLL_insert (*second_list, *second_tail, new_second); - pg->peers[second].num_connections++; - added++; - } - - return added; -} - -/** - * Scale free network construction as described in: - * - * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999. - * - * Start with a network of "one" peer, then progressively add - * peers up to the total number. At each step, iterate over - * all possible peers and connect new peer based on number of - * existing connections of the target peer. - * - * @param pg the peer group we are dealing with - * @param proc the connection processor to use - * @param list the peer list to use - * - * @return the number of connections created - */ -static unsigned int -create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) -{ - - unsigned int total_connections; - unsigned int outer_count; - unsigned int i; - unsigned int previous_total_connections; - double random; - double probability; - - GNUNET_assert (pg->total > 1); - - /* Add a connection between the first two nodes */ - total_connections = proc (pg, 0, 1, list, GNUNET_YES); - - for (outer_count = 1; outer_count < pg->total; outer_count++) - { - previous_total_connections = total_connections; - for (i = 0; i < outer_count; i++) - { - probability = - pg->peers[i].num_connections / (double) previous_total_connections; - random = - ((double) - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX)) / ((double) UINT64_MAX); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Considering connecting peer %d to peer %d\n", outer_count, - i); - if (random < probability) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", - outer_count, i); - total_connections += proc (pg, outer_count, i, list, GNUNET_YES); - } - } - } - - return total_connections; -} - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. Creates a small world topology - * according to the rewired ring construction. The basic - * behavior is that a ring topology is created, but with some - * probability instead of connecting a peer to the next - * neighbor in the ring a connection will be created to a peer - * selected uniformly at random. We use the TESTING - * PERCENTAGE option to specify what number of - * connections each peer should have. Default is 2, - * which makes the ring, any given number is multiplied by - * the log of the network size; i.e. a PERCENTAGE of 2 makes - * each peer have on average 2logn connections. The additional - * connections are made at increasing distance around the ring - * from the original peer, or to random peers based on the re- - * wiring probability. The TESTING - * PROBABILITY option is used as the probability that a given - * connection is rewired. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_small_world_ring (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, - enum PeerLists list) -{ - unsigned int i, j; - int nodeToConnect; - unsigned int natLog; - unsigned int randomPeer; - double random, logNModifier, probability; - unsigned int smallWorldConnections; - int connsPerPeer; - char *p_string; - int max; - int min; - unsigned int useAnd; - int connect_attempts; - - logNModifier = 0.5; /* FIXME: default value? */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", - &p_string)) - { - if (SSCANF (p_string, "%lf", &logNModifier) != 1) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - p_string, "LOGNMODIFIER", "TESTING"); - GNUNET_free (p_string); - } - probability = 0.5; /* FIXME: default percentage? */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", - &p_string)) - { - if (SSCANF (p_string, "%lf", &probability) != 1) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - p_string, "PERCENTAGE", "TESTING"); - GNUNET_free (p_string); - } - natLog = log (pg->total); - connsPerPeer = ceil (natLog * logNModifier); - - if (connsPerPeer % 2 == 1) - connsPerPeer += 1; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Target is %d connections per peer.", - connsPerPeer); - - smallWorldConnections = 0; - connect_attempts = 0; - for (i = 0; i < pg->total; i++) - { - useAnd = 0; - max = i + connsPerPeer / 2; - min = i - connsPerPeer / 2; - - if (max > pg->total - 1) - { - max = max - pg->total; - useAnd = 1; - } - - if (min < 0) - { - min = pg->total - 1 + min; - useAnd = 1; - } - - for (j = 0; j < connsPerPeer / 2; j++) - { - random = - ((double) - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX) / ((double) UINT64_MAX)); - if (random < probability) - { - /* Connect to uniformly selected random peer */ - randomPeer = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); - while ((((randomPeer < max) && (randomPeer > min)) && (useAnd == 0)) || - (((randomPeer > min) || (randomPeer < max)) && (useAnd == 1))) - { - randomPeer = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); - } - smallWorldConnections += proc (pg, i, randomPeer, list, GNUNET_YES); - } - else - { - nodeToConnect = i + j + 1; - if (nodeToConnect > pg->total - 1) - { - nodeToConnect = nodeToConnect - pg->total; - } - connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); - } - } - - } - - connect_attempts += smallWorldConnections; - - return connect_attempts; -} - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, - enum PeerLists list) -{ - unsigned int outer_count, inner_count; - unsigned int cutoff; - int connect_attempts; - double nat_percentage; - char *p_string; - - nat_percentage = 0.6; /* FIXME: default percentage? */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", - &p_string)) - { - if (SSCANF (p_string, "%lf", &nat_percentage) != 1) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - p_string, "PERCENTAGE", "TESTING"); - GNUNET_free (p_string); - } - - cutoff = (unsigned int) (nat_percentage * pg->total); - connect_attempts = 0; - for (outer_count = 0; outer_count < pg->total - 1; outer_count++) - { - for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) - { - if ((outer_count > cutoff) || (inner_count > cutoff)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", - outer_count, inner_count); - connect_attempts += - proc (pg, outer_count, inner_count, list, GNUNET_YES); - } - } - } - return connect_attempts; -} - -#if TOPOLOGY_HACK -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_nated_internet_copy (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, - enum PeerLists list) -{ - unsigned int outer_count, inner_count; - unsigned int cutoff; - int connect_attempts; - double nat_percentage; - char *p_string; - unsigned int count; - struct ProgressMeter *conn_meter; - - nat_percentage = 0.6; /* FIXME: default percentage? */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", - &p_string)) - { - if (SSCANF (p_string, "%lf", &nat_percentage) != 1) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - p_string, "PERCENTAGE", "TESTING"); - GNUNET_free (p_string); - } - - cutoff = (unsigned int) (nat_percentage * pg->total); - count = 0; - for (outer_count = 0; outer_count < pg->total - 1; outer_count++) - { - for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) - { - if ((outer_count > cutoff) || (inner_count > cutoff)) - { - count++; - } - } - } - conn_meter = create_meter (count, "NAT COPY", GNUNET_YES); - connect_attempts = 0; - for (outer_count = 0; outer_count < pg->total - 1; outer_count++) - { - for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) - { - if ((outer_count > cutoff) || (inner_count > cutoff)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", - outer_count, inner_count); - connect_attempts += - proc (pg, outer_count, inner_count, list, GNUNET_YES); - add_connections (pg, outer_count, inner_count, ALLOWED, GNUNET_NO); - update_meter (conn_meter); - } - } - } - free_meter (conn_meter); - - return connect_attempts; -} -#endif - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_small_world (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, - enum PeerLists list) -{ - unsigned int i, j, k; - unsigned int square; - unsigned int rows; - unsigned int cols; - unsigned int toggle = 1; - unsigned int nodeToConnect; - unsigned int natLog; - unsigned int node1Row; - unsigned int node1Col; - unsigned int node2Row; - unsigned int node2Col; - unsigned int distance; - double probability, random, percentage; - unsigned int smallWorldConnections; - unsigned int small_world_it; - char *p_string; - int connect_attempts; - - square = floor (sqrt (pg->total)); - rows = square; - cols = square; - - percentage = 0.5; /* FIXME: default percentage? */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", - &p_string)) - { - if (SSCANF (p_string, "%lf", &percentage) != 1) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - p_string, "PERCENTAGE", "TESTING"); - GNUNET_free (p_string); - } - if (percentage < 0.0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': got %f, needed value greater than 0\n"), - "PERCENTAGE", "TESTING", percentage); - percentage = 0.5; - } - probability = 0.5; /* FIXME: default percentage? */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", - &p_string)) - { - if (SSCANF (p_string, "%lf", &probability) != 1) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - p_string, "PROBABILITY", "TESTING"); - GNUNET_free (p_string); - } - if (square * square != pg->total) - { - while (rows * cols < pg->total) - { - if (toggle % 2 == 0) - rows++; - else - cols++; - - toggle++; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting nodes in 2d torus topology: %u rows %u columns\n", - rows, cols); - connect_attempts = 0; - /* Rows and columns are all sorted out, now iterate over all nodes and connect each - * to the node to its right and above. Once this is over, we'll have our torus! - * Special case for the last node (if the rows and columns are not equal), connect - * to the first in the row to maintain topology. - */ - for (i = 0; i < pg->total; i++) - { - /* First connect to the node to the right */ - if (((i + 1) % cols != 0) && (i + 1 != pg->total)) - nodeToConnect = i + 1; - else if (i + 1 == pg->total) - nodeToConnect = rows * cols - cols; - else - nodeToConnect = i - cols + 1; - - connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); - - if (i < cols) - { - nodeToConnect = (rows * cols) - cols + i; - if (nodeToConnect >= pg->total) - nodeToConnect -= cols; - } - else - nodeToConnect = i - cols; - - if (nodeToConnect < pg->total) - connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); - } - natLog = log (pg->total); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "natural log of %d is %d, will run %d iterations\n", pg->total, - natLog, (int) (natLog * percentage)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Total connections added thus far: %u!\n", connect_attempts); - smallWorldConnections = 0; - small_world_it = (unsigned int) (natLog * percentage); - if (small_world_it < 1) - small_world_it = 1; - GNUNET_assert (small_world_it > 0 && small_world_it < (unsigned int) -1); - for (i = 0; i < small_world_it; i++) - { - for (j = 0; j < pg->total; j++) - { - /* Determine the row and column of node at position j on the 2d torus */ - node1Row = j / cols; - node1Col = j - (node1Row * cols); - for (k = 0; k < pg->total; k++) - { - /* Determine the row and column of node at position k on the 2d torus */ - node2Row = k / cols; - node2Col = k - (node2Row * cols); - /* Simple Cartesian distance */ - distance = abs (node1Row - node2Row) + abs (node1Col - node2Col); - if (distance > 1) - { - /* Calculate probability as 1 over the square of the distance */ - probability = 1.0 / (distance * distance); - /* Choose a random value between 0 and 1 */ - random = - ((double) - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX)) / ((double) UINT64_MAX); - /* If random < probability, then connect the two nodes */ - if (random < probability) - smallWorldConnections += proc (pg, j, k, list, GNUNET_YES); - - } - } - } - } - connect_attempts += smallWorldConnections; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Total connections added for small world: %d!\n", - smallWorldConnections); - return connect_attempts; -} - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, - enum PeerLists list) -{ - double temp_rand; - unsigned int outer_count; - unsigned int inner_count; - int connect_attempts; - double probability; - char *p_string; - - probability = 0.5; /* FIXME: default percentage? */ - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", - &p_string)) - { - if (SSCANF (p_string, "%lf", &probability) != 1) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - p_string, "PROBABILITY", "TESTING"); - GNUNET_free (p_string); - } - connect_attempts = 0; - for (outer_count = 0; outer_count < pg->total - 1; outer_count++) - { - for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) - { - temp_rand = - ((double) - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX)) / ((double) UINT64_MAX); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "rand is %f probability is %f\n", - temp_rand, probability); - if (temp_rand < probability) - { - connect_attempts += - proc (pg, outer_count, inner_count, list, GNUNET_YES); - } - } - } - - return connect_attempts; -} - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. This particular function creates - * the connections for a 2d-torus, plus additional "closest" - * connections per peer. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) -{ - unsigned int i; - unsigned int square; - unsigned int rows; - unsigned int cols; - unsigned int toggle = 1; - unsigned int nodeToConnect; - int connect_attempts; - - connect_attempts = 0; - - square = floor (sqrt (pg->total)); - rows = square; - cols = square; - - if (square * square != pg->total) - { - while (rows * cols < pg->total) - { - if (toggle % 2 == 0) - rows++; - else - cols++; - - toggle++; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting nodes in 2d torus topology: %u rows %u columns\n", - rows, cols); - /* Rows and columns are all sorted out, now iterate over all nodes and connect each - * to the node to its right and above. Once this is over, we'll have our torus! - * Special case for the last node (if the rows and columns are not equal), connect - * to the first in the row to maintain topology. - */ - for (i = 0; i < pg->total; i++) - { - /* First connect to the node to the right */ - if (((i + 1) % cols != 0) && (i + 1 != pg->total)) - nodeToConnect = i + 1; - else if (i + 1 == pg->total) - nodeToConnect = rows * cols - cols; - else - nodeToConnect = i - cols + 1; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, - nodeToConnect); - connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); - - /* Second connect to the node immediately above */ - if (i < cols) - { - nodeToConnect = (rows * cols) - cols + i; - if (nodeToConnect >= pg->total) - nodeToConnect -= cols; - } - else - nodeToConnect = i - cols; - - if (nodeToConnect < pg->total) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, - nodeToConnect); - connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); - } - - } - - return connect_attempts; -} - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * @param check does the connection processor need to check before - * performing an action on the list? - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_clique (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list, - unsigned int check) -{ - unsigned int outer_count; - unsigned int inner_count; - int connect_attempts; - struct ProgressMeter *conn_meter; - - connect_attempts = 0; - - conn_meter = - create_meter ((((pg->total * pg->total) + pg->total) / 2) - pg->total, - "Create Clique ", GNUNET_NO); - for (outer_count = 0; outer_count < pg->total - 1; outer_count++) - { - for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", - outer_count, inner_count); - connect_attempts += proc (pg, outer_count, inner_count, list, check); - update_meter (conn_meter); - } - } - reset_meter (conn_meter); - free_meter (conn_meter); - return connect_attempts; -} - -#if !OLD -/** - * Iterator over hash map entries. - * - * @param cls closure the peer group - * @param key the key stored in the hashmap is the - * index of the peer to connect to - * @param value value in the hash map, handle to the peer daemon - * @return GNUNET_YES if we should continue to - * iterate, - * GNUNET_NO if not. - */ -static int -unblacklist_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct UnblacklistContext *un_ctx = cls; - uint32_t second_pos; - - uid_from_hash (key, &second_pos); - - unblacklist_connections (un_ctx->pg, un_ctx->first_uid, second_pos); - - return GNUNET_YES; -} -#endif - -#if !OLD -/** - * Create a blacklist topology based on the allowed topology - * which disallows any connections not in the allowed topology - * at the transport level. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to allow - * up connections between two peers - * - * @return the number of connections that were set up - * - */ -static unsigned int -copy_allowed (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc) -{ - unsigned int count; - unsigned int total; - struct PeerConnection *iter; - -#if !OLD - struct UnblacklistContext un_ctx; - - un_ctx.pg = pg; -#endif - total = 0; - for (count = 0; count < pg->total - 1; count++) - { -#if OLD - iter = pg->peers[count].allowed_peers_head; - while (iter != NULL) - { - remove_connections (pg, count, iter->index, BLACKLIST, GNUNET_YES); - //unblacklist_connections(pg, count, iter->index); - iter = iter->next; - } -#else - un_ctx.first_uid = count; - total += - GNUNET_CONTAINER_multihashmap_iterate (pg->peers[count].allowed_peers, - &unblacklist_iterator, &un_ctx); -#endif - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unblacklisted %u peers\n", total); - return total; -} -#endif - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list which list should be modified - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_line (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) -{ - unsigned int count; - unsigned int connect_attempts; - - connect_attempts = 0; - /* Connect each peer to the next highest numbered peer */ - for (count = 0; count < pg->total - 1; count++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", - count, count + 1); - connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); - } - - return connect_attempts; -} - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param filename the file to read topology information from - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_from_file (struct GNUNET_TESTING_PeerGroup *pg, char *filename, - GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) -{ - int connect_attempts; - unsigned int first_peer_index; - unsigned int second_peer_index; - struct stat frstat; - int count; - char *data; - const char *buf; - unsigned int total_peers; - enum States curr_state; - - connect_attempts = 0; - if (GNUNET_OK != GNUNET_DISK_file_test (filename)) - GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ); - - if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not open file `%s' specified for topology!", filename); - return connect_attempts; - } - - data = GNUNET_malloc_large (frstat.st_size); - GNUNET_assert (data != NULL); - if (frstat.st_size != GNUNET_DISK_fn_read (filename, data, frstat.st_size)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not read file %s specified for host list, ending test!", - filename); - GNUNET_free (data); - return connect_attempts; - } - - buf = data; - count = 0; - first_peer_index = 0; - /* First line should contain a single integer, specifying the number of peers */ - /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */ - curr_state = NUM_PEERS; - while (count < frstat.st_size - 1) - { - if ((buf[count] == '\n') || (buf[count] == ' ')) - { - count++; - continue; - } - - switch (curr_state) - { - case NUM_PEERS: - errno = 0; - total_peers = strtoul (&buf[count], NULL, 10); - if (errno != 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to read number of peers from topology file!\n"); - GNUNET_free (data); - return connect_attempts; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u total peers in topology\n", - total_peers); - GNUNET_assert (total_peers == pg->total); - curr_state = PEER_INDEX; - while ((buf[count] != '\n') && (count < frstat.st_size - 1)) - count++; - count++; - break; - case PEER_INDEX: - errno = 0; - first_peer_index = strtoul (&buf[count], NULL, 10); - if (errno != 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to read peer index from topology file!\n"); - GNUNET_free (data); - return connect_attempts; - } - while ((buf[count] != ':') && (count < frstat.st_size - 1)) - count++; - count++; - curr_state = OTHER_PEER_INDEX; - break; - case COLON: - if (1 == sscanf (&buf[count], ":")) - curr_state = OTHER_PEER_INDEX; - count++; - break; - case OTHER_PEER_INDEX: - errno = 0; - second_peer_index = strtoul (&buf[count], NULL, 10); - if (errno != 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to peer index from topology file!\n"); - GNUNET_free (data); - return connect_attempts; - } - /* Assume file is written with first peer 1, but array index is 0 */ - connect_attempts += - proc (pg, first_peer_index - 1, second_peer_index - 1, list, - GNUNET_YES); - while ((buf[count] != '\n') && (buf[count] != ',') && - (count < frstat.st_size - 1)) - count++; - if (buf[count] == '\n') - { - curr_state = PEER_INDEX; - } - else if (buf[count] != ',') - { - curr_state = OTHER_PEER_INDEX; - } - count++; - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Found bad data in topology file while in state %d!\n", - curr_state); - GNUNET_break (0); - GNUNET_free (data); - return connect_attempts; - } - } - GNUNET_free (data); - return connect_attempts; -} - -/** - * Create a topology given a peer group (set of running peers) - * and a connection processor. - * - * @param pg the peergroup to create the topology on - * @param proc the connection processor to call to actually set - * up connections between two peers - * @param list the peer list to use - * - * @return the number of connections that were set up - * - */ -static unsigned int -create_ring (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) -{ - unsigned int count; - int connect_attempts; - - connect_attempts = 0; - - /* Connect each peer to the next highest numbered peer */ - for (count = 0; count < pg->total - 1; count++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", - count, count + 1); - connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); - } - - /* Connect the last peer to the first peer */ - connect_attempts += proc (pg, pg->total - 1, 0, list, GNUNET_YES); - - return connect_attempts; -} - -#if !OLD -/** - * Iterator for writing friends of a peer to a file. - * - * @param cls closure, an open writable file handle - * @param key the key the daemon was stored under - * @param value the GNUNET_TESTING_Daemon that needs to be written. - * - * @return GNUNET_YES to continue iteration - * - * TODO: Could replace friend_file_iterator and blacklist_file_iterator - * with a single file_iterator that takes a closure which contains - * the prefix to write before the peer. Then this could be used - * for blacklisting multiple transports and writing the friend - * file. I'm sure *someone* will complain loudly about other - * things that negate these functions even existing so no point in - * "fixing" now. - */ -static int -friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - FILE *temp_friend_handle = cls; - struct GNUNET_TESTING_Daemon *peer = value; - struct GNUNET_PeerIdentity *temppeer; - struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; - - temppeer = &peer->id; - GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); - FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); - - return GNUNET_YES; -} - -struct BlacklistContext -{ - /* - * The (open) file handle to write to - */ - FILE *temp_file_handle; - - /* - * The transport that this peer will be blacklisted on. - */ - char *transport; -}; - -/** - * Iterator for writing blacklist data to appropriate files. - * - * @param cls closure, an open writable file handle - * @param key the key the daemon was stored under - * @param value the GNUNET_TESTING_Daemon that needs to be written. - * - * @return GNUNET_YES to continue iteration - */ -static int -blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct BlacklistContext *blacklist_ctx = cls; - struct GNUNET_TESTING_Daemon *peer = value; - struct GNUNET_PeerIdentity *temppeer; - struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; - - temppeer = &peer->id; - GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", - blacklist_ctx->transport, (char *) &peer_enc); - FPRINTF (blacklist_ctx->temp_file_handle, "%s:%s\n", blacklist_ctx->transport, - (char *) &peer_enc); - - return GNUNET_YES; -} -#endif - -/* - * Create the friend files based on the PeerConnection's - * of each peer in the peer group, and copy the files - * to the appropriate place - * - * @param pg the peer group we are dealing with - */ -static int -create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg) -{ - FILE *temp_friend_handle; - unsigned int pg_iter; - char *temp_service_path; - struct GNUNET_OS_Process **procarr; - char *arg; - char *mytemp; - -#if NOT_STUPID - enum GNUNET_OS_ProcessStatusType type; - unsigned long return_code; - int count; - int max_wait = 10; -#endif - int ret; - - ret = GNUNET_OK; -#if OLD - struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; - struct PeerConnection *conn_iter; -#endif - procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - mytemp = GNUNET_DISK_mktemp ("friends"); - GNUNET_assert (mytemp != NULL); - temp_friend_handle = FOPEN (mytemp, "wt"); - GNUNET_assert (temp_friend_handle != NULL); -#if OLD - conn_iter = pg->peers[pg_iter].allowed_peers_head; - while (conn_iter != NULL) - { - GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> - id.hashPubKey, &peer_enc); - FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); - conn_iter = conn_iter->next; - } -#else - GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, - &friend_file_iterator, - temp_friend_handle); -#endif - FCLOSE (temp_friend_handle); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, - "PATHS", "SERVICEHOME", - &temp_service_path)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), - "SERVICEHOME", "PATHS"); - if (UNLINK (mytemp) != 0) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); - GNUNET_free (mytemp); - break; - } - - if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ - { - GNUNET_asprintf (&arg, "%s/friends", temp_service_path); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying file with RENAME(%s,%s)\n", mytemp, arg); - RENAME (mytemp, arg); - procarr[pg_iter] = NULL; - GNUNET_free (arg); - } - else /* Remote, scp the file to the correct place */ - { - if (NULL != pg->peers[pg_iter].daemon->username) - GNUNET_asprintf (&arg, "%s@%s:%s/friends", - pg->peers[pg_iter].daemon->username, - pg->peers[pg_iter].daemon->hostname, - temp_service_path); - else - GNUNET_asprintf (&arg, "%s:%s/friends", - pg->peers[pg_iter].daemon->hostname, - temp_service_path); - procarr[pg_iter] = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); - GNUNET_assert (procarr[pg_iter] != NULL); - ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */ - GNUNET_OS_process_destroy (procarr[pg_iter]); - if (ret != GNUNET_OK) - { - /* FIXME: free contents of 'procarr' array */ - GNUNET_free (procarr); - GNUNET_free (temp_service_path); - GNUNET_free (mytemp); - GNUNET_free (arg); - return ret; - } - procarr[pg_iter] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying file with command scp %s %s\n", mytemp, arg); - GNUNET_free (arg); - } - GNUNET_free (temp_service_path); - GNUNET_free (mytemp); - } - -#if NOT_STUPID - count = 0; - ret = GNUNET_SYSERR; - while ((count < max_wait) && (ret != GNUNET_OK)) - { - ret = GNUNET_OK; - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking copy status of file %d\n", - pg_iter); - if (procarr[pg_iter] != NULL) /* Check for already completed! */ - { - if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != - GNUNET_OK) - { - ret = GNUNET_SYSERR; - } - else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) - { - ret = GNUNET_SYSERR; - } - else - { - GNUNET_OS_process_destroy (procarr[pg_iter]); - procarr[pg_iter] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); - } - } - } - count++; - if (ret == GNUNET_SYSERR) - { - /* FIXME: why sleep here? -CG */ - sleep (1); - } - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Finished copying all friend files!\n"); -#endif - GNUNET_free (procarr); - return ret; -} - -/* - * Create the blacklist files based on the PeerConnection's - * of each peer in the peer group, and copy the files - * to the appropriate place. - * - * @param pg the peer group we are dealing with - * @param transports space delimited list of transports to blacklist - */ -static int -create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, - const char *transports) -{ - FILE *temp_file_handle; - unsigned int pg_iter; - char *temp_service_path; - struct GNUNET_OS_Process **procarr; - char *arg; - char *mytemp; - enum GNUNET_OS_ProcessStatusType type; - unsigned long return_code; - int count; - int ret; - int max_wait = 10; - int transport_len; - unsigned int i; - char *pos; - char *temp_transports; - -#if OLD - struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; - struct PeerConnection *conn_iter; -#else - static struct BlacklistContext blacklist_ctx; -#endif - - procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - mytemp = GNUNET_DISK_mktemp ("blacklist"); - GNUNET_assert (mytemp != NULL); - temp_file_handle = FOPEN (mytemp, "wt"); - GNUNET_assert (temp_file_handle != NULL); - temp_transports = GNUNET_strdup (transports); -#if !OLD - blacklist_ctx.temp_file_handle = temp_file_handle; -#endif - transport_len = strlen (temp_transports) + 1; - pos = NULL; - - for (i = 0; i < transport_len; i++) - { - if ((temp_transports[i] == ' ') && (pos == NULL)) - continue; /* At start of string (whitespace) */ - else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */ - { - temp_transports[i] = '\0'; -#if OLD - conn_iter = pg->peers[pg_iter].blacklisted_peers_head; - while (conn_iter != NULL) - { - GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> - id.hashPubKey, &peer_enc); - FPRINTF (temp_file_handle, "%s:%s\n", pos, (char *) &peer_enc); - conn_iter = conn_iter->next; - } -#else - blacklist_ctx.transport = pos; - (void) GNUNET_CONTAINER_multihashmap_iterate (pg-> - peers - [pg_iter].blacklisted_peers, - &blacklist_file_iterator, - &blacklist_ctx); -#endif - pos = NULL; - } /* At beginning of actual string */ - else if (pos == NULL) - { - pos = &temp_transports[i]; - } - } - - GNUNET_free (temp_transports); - FCLOSE (temp_file_handle); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, - "PATHS", "SERVICEHOME", - &temp_service_path)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), - "SERVICEHOME", "PATHS"); - if (UNLINK (mytemp) != 0) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); - GNUNET_free (mytemp); - break; - } - - if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ - { - GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path); - RENAME (mytemp, arg); - procarr[pg_iter] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying file with RENAME (%s,%s)\n", mytemp, arg); - GNUNET_free (arg); - } - else /* Remote, scp the file to the correct place */ - { - if (NULL != pg->peers[pg_iter].daemon->username) - GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", - pg->peers[pg_iter].daemon->username, - pg->peers[pg_iter].daemon->hostname, - temp_service_path); - else - GNUNET_asprintf (&arg, "%s:%s/blacklist", - pg->peers[pg_iter].daemon->hostname, - temp_service_path); - procarr[pg_iter] = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); - GNUNET_assert (procarr[pg_iter] != NULL); - GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: add scheduled blacklist file copy that parallelizes file copying! */ - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Copying file with command scp %s %s\n", mytemp, arg); - GNUNET_free (arg); - } - GNUNET_free (temp_service_path); - GNUNET_free (mytemp); - } - - count = 0; - ret = GNUNET_SYSERR; - while ((count < max_wait) && (ret != GNUNET_OK)) - { - ret = GNUNET_OK; - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Checking copy status of file %d\n", pg_iter); - if (procarr[pg_iter] != NULL) /* Check for already completed! */ - { - if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != - GNUNET_OK) - { - ret = GNUNET_SYSERR; - } - else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) - { - ret = GNUNET_SYSERR; - } - else - { - GNUNET_OS_process_destroy (procarr[pg_iter]); - procarr[pg_iter] = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); - } - } - } - count++; - if (ret == GNUNET_SYSERR) - { - /* FIXME: why sleep here? -CG */ - sleep (1); - } - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Finished copying all blacklist files!\n"); - GNUNET_free (procarr); - return ret; -} - -/* Forward Declaration */ -static void -schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - -/** - * Choose a random peer's next connection to create, and - * call schedule_connect to set up the connect task. - * - * @param pg the peer group to connect - */ -static void -preschedule_connect (struct GNUNET_TESTING_PeerGroup *pg) -{ - struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx; - struct PeerConnection *connection_iter; - struct ConnectContext *connect_context; - uint32_t random_peer; - - if (ct_ctx->remaining_connections == 0) - return; - random_peer = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); - while (pg->peers[random_peer].connect_peers_head == NULL) - random_peer = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); - - connection_iter = pg->peers[random_peer].connect_peers_head; - connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); - connect_context->first_index = random_peer; - connect_context->second_index = connection_iter->index; - connect_context->ct_ctx = ct_ctx; - connect_context->task = - GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); - GNUNET_CONTAINER_DLL_insert (pg->cc_head, pg->cc_tail, connect_context); - GNUNET_CONTAINER_DLL_remove (pg->peers[random_peer].connect_peers_head, - pg->peers[random_peer].connect_peers_tail, - connection_iter); - GNUNET_free (connection_iter); - ct_ctx->remaining_connections--; -} - -#if USE_SEND_HELLOS -/* Forward declaration */ -static void -schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - -/** - * Close connections and free the hello context. - * - * @param cls the 'struct SendHelloContext *' - * @param tc scheduler context - */ -static void -free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct SendHelloContext *send_hello_context = cls; - - if (send_hello_context->peer->daemon->server != NULL) - { - GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); - send_hello_context->peer->daemon->server = NULL; - } - if (send_hello_context->peer->daemon->th != NULL) - { - GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); - send_hello_context->peer->daemon->th = NULL; - } - if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (send_hello_context->core_connect_task); - send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; - } - send_hello_context->pg->outstanding_connects--; - GNUNET_free (send_hello_context); -} - -/** - * For peers that haven't yet connected, notify - * the caller that they have failed (timeout). - * - * @param cls the 'struct SendHelloContext *' - * @param tc scheduler context - */ -static void -notify_remaining_connections_failed (void *cls, - const struct GNUNET_SCHEDULER_TaskContext - *tc) -{ - struct SendHelloContext *send_hello_context = cls; - struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; - struct PeerConnection *connection; - - GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); - send_hello_context->peer->daemon->server = NULL; - - connection = send_hello_context->peer->connect_peers_head; - - while (connection != NULL) - { - if (pg->notify_connection != NULL) - { - pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, 0, /* FIXME */ - send_hello_context->peer->daemon->cfg, - pg->peers[connection->index].daemon->cfg, - send_hello_context->peer->daemon, - pg->peers[connection->index].daemon, - "Peers failed to connect (timeout)"); - } - GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, - send_hello_context->peer->connect_peers_tail, - connection); - GNUNET_free (connection); - connection = connection->next; - } - GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); -#if BAD - other_peer = &pg->peers[connection->index]; -#endif -} - -/** - * For peers that haven't yet connected, send - * CORE connect requests. - * - * @param cls the 'struct SendHelloContext *' - * @param tc scheduler context - */ -static void -send_core_connect_requests (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct SendHelloContext *send_hello_context = cls; - struct PeerConnection *conn; - - GNUNET_assert (send_hello_context->peer->daemon->server != NULL); - - send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; - - send_hello_context->connect_attempts++; - if (send_hello_context->connect_attempts < - send_hello_context->pg->ct_ctx.connect_attempts) - { - conn = send_hello_context->peer->connect_peers_head; - while (conn != NULL) - { - GNUNET_TRANSPORT_try_connect (send_hello_context->peer->daemon->th, - &send_hello_context->pg->peers[conn-> - index].daemon-> - id); - conn = conn->next; - } - send_hello_context->core_connect_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide - (send_hello_context->pg-> - ct_ctx.connect_timeout, - send_hello_context->pg-> - ct_ctx.connect_attempts), - &send_core_connect_requests, - send_hello_context); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Timeout before all connections created, marking rest as failed!\n"); - GNUNET_SCHEDULER_add_now (¬ify_remaining_connections_failed, - send_hello_context); - } - -} - -/** - * Success, connection is up. Signal client our success. - * - * @param cls our "struct SendHelloContext" - * @param peer identity of the peer that has connected - * @param atsi performance information - * - * FIXME: remove peers from BOTH lists, call notify twice, should - * double the speed of connections as long as the list iteration - * doesn't take too long! - */ -static void -core_connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_ATS_Information *atsi) -{ - struct SendHelloContext *send_hello_context = cls; - struct PeerConnection *connection; - struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; - -#if BAD - struct PeerData *other_peer; -#endif - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", - ctx->d1->shortname, GNUNET_i2s (peer)); - if (0 == - memcmp (&send_hello_context->peer->daemon->id, peer, - sizeof (struct GNUNET_PeerIdentity))) - return; - - connection = send_hello_context->peer->connect_peers_head; -#if BAD - other_peer = NULL; -#endif - - while ((connection != NULL) && - (0 != - memcmp (&pg->peers[connection->index].daemon->id, peer, - sizeof (struct GNUNET_PeerIdentity)))) - { - connection = connection->next; - } - - if (connection == NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connected peer %s to %s, not in list (no problem(?))\n", - GNUNET_i2s (peer), send_hello_context->peer->daemon->shortname); - } - else - { -#if BAD - other_peer = &pg->peers[connection->index]; -#endif - if (pg->notify_connection != NULL) - { - pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, peer, 0, /* FIXME */ - send_hello_context->peer->daemon->cfg, - pg->peers[connection->index].daemon->cfg, - send_hello_context->peer->daemon, - pg->peers[connection->index].daemon, NULL); - } - GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, - send_hello_context->peer->connect_peers_tail, - connection); - GNUNET_free (connection); - } - -#if BAD - /* Notify of reverse connection and remove from other peers list of outstanding */ - if (other_peer != NULL) - { - connection = other_peer->connect_peers_head; - while ((connection != NULL) && - (0 != - memcmp (&send_hello_context->peer->daemon->id, - &pg->peers[connection->index].daemon->id, - sizeof (struct GNUNET_PeerIdentity)))) - { - connection = connection->next; - } - if (connection != NULL) - { - if (pg->notify_connection != NULL) - { - pg->notify_connection (pg->notify_connection_cls, peer, &send_hello_context->peer->daemon->id, 0, /* FIXME */ - pg->peers[connection->index].daemon->cfg, - send_hello_context->peer->daemon->cfg, - pg->peers[connection->index].daemon, - send_hello_context->peer->daemon, NULL); - } - - GNUNET_CONTAINER_DLL_remove (other_peer->connect_peers_head, - other_peer->connect_peers_tail, connection); - GNUNET_free (connection); - } - } -#endif - - if (send_hello_context->peer->connect_peers_head == NULL) - { - GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); - } -} - -/** - * Notify of a successful connection to the core service. - * - * @param cls a struct SendHelloContext * - * @param server handle to the core service - * @param my_identity the peer identity of this peer - */ -void -core_init (void *cls, struct GNUNET_CORE_Handle *server, - struct GNUNET_PeerIdentity *my_identity) -{ - struct SendHelloContext *send_hello_context = cls; - - send_hello_context->core_ready = GNUNET_YES; -} - -/** - * Function called once a hello has been sent - * to the transport, move on to the next one - * or go away forever. - * - * @param cls the 'struct SendHelloContext *' - * @param tc scheduler context - */ -static void -hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct SendHelloContext *send_hello_context = cls; - - //unsigned int pg_iter; - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - { - GNUNET_free (send_hello_context); - return; - } - - send_hello_context->pg->remaining_hellos--; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent HELLO, have %d remaining!\n", - send_hello_context->pg->remaining_hellos); - if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */ - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All hellos for this peer sent, disconnecting transport!\n"); - GNUNET_assert (send_hello_context->peer->daemon->th != NULL); - GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); - send_hello_context->peer->daemon->th = NULL; - GNUNET_assert (send_hello_context->peer->daemon->server == NULL); - send_hello_context->peer->daemon->server = - GNUNET_CORE_connect (send_hello_context->peer->cfg, 1, - send_hello_context, &core_init, - &core_connect_notify, NULL, NULL, NULL, GNUNET_NO, - NULL, GNUNET_NO, no_handlers); - - send_hello_context->core_connect_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide - (send_hello_context->pg-> - ct_ctx.connect_timeout, - send_hello_context->pg-> - ct_ctx.connect_attempts), - &send_core_connect_requests, - send_hello_context); - } - else - GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); -} - -/** - * Connect to a peer, give it all the HELLO's of those peers - * we will later ask it to connect to. - * - * @param ct_ctx the overall connection context - */ -static void -schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct SendHelloContext *send_hello_context = cls; - struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; - - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - { - GNUNET_free (send_hello_context); - return; - } - - GNUNET_assert (send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */ - - if (((send_hello_context->peer->daemon->th == NULL) && - (pg->outstanding_connects > pg->max_outstanding_connections)) || - (pg->stop_connects == GNUNET_YES)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Delaying connect, we have too many outstanding connections!\n"); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_send_hellos, send_hello_context); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating connection, outstanding_connections is %d\n", - outstanding_connects); - if (send_hello_context->peer->daemon->th == NULL) - { - pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */ - send_hello_context->peer->daemon->th = - GNUNET_TRANSPORT_connect (send_hello_context->peer->cfg, NULL, - send_hello_context, NULL, NULL, NULL); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Offering HELLO of peer %s to peer %s\n", - send_hello_context->peer->daemon->shortname, - pg->peers[send_hello_context->peer_pos->index]. - daemon->shortname); - GNUNET_TRANSPORT_offer_hello (send_hello_context->peer->daemon->th, - (const struct GNUNET_MessageHeader *) - pg->peers[send_hello_context->peer_pos-> - index].daemon->hello, - &hello_sent_callback, send_hello_context); - send_hello_context->peer_pos = send_hello_context->peer_pos->next; - GNUNET_assert (send_hello_context->peer->daemon->th != NULL); - } -} -#endif - -/** - * Internal notification of a connection, kept so that we can ensure some connections - * happen instead of flooding all testing daemons with requests to connect. - */ -static void -internal_connect_notify (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, - uint32_t distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - struct ConnectContext *connect_ctx = cls; - struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx; - struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; - struct PeerConnection *connection; - - GNUNET_assert (NULL != connect_ctx->cc); - connect_ctx->cc = NULL; - GNUNET_assert (0 < pg->outstanding_connects); - pg->outstanding_connects--; - GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, connect_ctx); - /* - * Check whether the inverse connection has been scheduled yet, - * if not, we can remove it from the other peers list and avoid - * even trying to connect them again! - */ - connection = pg->peers[connect_ctx->second_index].connect_peers_head; -#if BAD - other_peer = NULL; -#endif - - while ((connection != NULL) && - (0 != - memcmp (first, &pg->peers[connection->index].daemon->id, - sizeof (struct GNUNET_PeerIdentity)))) - connection = connection->next; - - if (connection != NULL) /* Can safely remove! */ - { - GNUNET_assert (0 < ct_ctx->remaining_connections); - ct_ctx->remaining_connections--; - if (pg->notify_connection != NULL) /* Notify of reverse connection */ - pg->notify_connection (pg->notify_connection_cls, second, first, distance, - second_cfg, first_cfg, second_daemon, first_daemon, - emsg); - - GNUNET_CONTAINER_DLL_remove (pg-> - peers[connect_ctx-> - second_index].connect_peers_head, - pg->peers[connect_ctx-> - second_index].connect_peers_tail, - connection); - GNUNET_free (connection); - } - - if (ct_ctx->remaining_connections == 0) - { - if (ct_ctx->notify_connections_done != NULL) - { - ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); - ct_ctx->notify_connections_done = NULL; - } - } - else - preschedule_connect (pg); - - if (pg->notify_connection != NULL) - pg->notify_connection (pg->notify_connection_cls, first, second, distance, - first_cfg, second_cfg, first_daemon, second_daemon, - emsg); - GNUNET_free (connect_ctx); -} - -/** - * Either delay a connection (because there are too many outstanding) - * or schedule it for right now. - * - * @param cls a connection context - * @param tc the task runtime context - */ -static void -schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct ConnectContext *connect_context = cls; - struct GNUNET_TESTING_PeerGroup *pg = connect_context->ct_ctx->pg; - - connect_context->task = GNUNET_SCHEDULER_NO_TASK; - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - return; - - if ((pg->outstanding_connects > pg->max_outstanding_connections) || - (pg->stop_connects == GNUNET_YES)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Delaying connect, we have too many outstanding connections!\n"); - connect_context->task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_connect, connect_context); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating connection, outstanding_connections is %d (max %d)\n", - pg->outstanding_connects, pg->max_outstanding_connections); - pg->outstanding_connects++; - pg->total_connects_scheduled++; - GNUNET_assert (NULL == connect_context->cc); - connect_context->cc = - GNUNET_TESTING_daemons_connect (pg-> - peers[connect_context-> - first_index].daemon, - pg->peers[connect_context-> - second_index].daemon, - connect_context->ct_ctx->connect_timeout, - connect_context->ct_ctx->connect_attempts, -#if USE_SEND_HELLOS - GNUNET_NO, -#else - GNUNET_YES, -#endif - &internal_connect_notify, - connect_context); - -} - -#if !OLD -/** - * Iterator for actually scheduling connections to be created - * between two peers. - * - * @param cls closure, a GNUNET_TESTING_Daemon - * @param key the key the second Daemon was stored under - * @param value the GNUNET_TESTING_Daemon that the first is to connect to - * - * @return GNUNET_YES to continue iteration - */ -static int -connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct ConnectTopologyContext *ct_ctx = cls; - struct PeerData *first = ct_ctx->first; - struct GNUNET_TESTING_Daemon *second = value; - struct ConnectContext *connect_context; - - connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); - connect_context->first = first->daemon; - connect_context->second = second; - connect_context->ct_ctx = ct_ctx; - connect_context->task = - GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); - GNUNET_CONTAINER_DLL_insert (ct_ctx->pg->cc_head, ct_ctx->pg->cc_tail, - connect_context); - return GNUNET_YES; -} -#endif - -#if !OLD -/** - * Iterator for copying all entries in the allowed hashmap to the - * connect hashmap. - * - * @param cls closure, a GNUNET_TESTING_Daemon - * @param key the key the second Daemon was stored under - * @param value the GNUNET_TESTING_Daemon that the first is to connect to - * - * @return GNUNET_YES to continue iteration - */ -static int -copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct PeerData *first = cls; - - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key, - value, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - - return GNUNET_YES; -} -#endif - -/** - * Make the peers to connect the same as those that are allowed to be - * connected. - * - * @param pg the peer group - */ -static int -copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg) -{ - unsigned int pg_iter; - int ret; - int total; - -#if OLD - struct PeerConnection *iter; -#endif - total = 0; - ret = 0; - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { -#if OLD - iter = pg->peers[pg_iter].allowed_peers_head; - while (iter != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating connection between %d and %d\n", pg_iter, - iter->index); - total += add_connections (pg, pg_iter, iter->index, CONNECT, GNUNET_YES); - //total += add_actual_connections(pg, pg_iter, iter->index); - iter = iter->next; - } -#else - ret = - GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, - ©_topology_iterator, - &pg->peers[pg_iter]); -#endif - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; - - total = total + ret; - } - - return total; -} - -/** - * Connect the topology as specified by the PeerConnection's - * of each peer in the peer group - * - * @param pg the peer group we are dealing with - * @param connect_timeout how long try connecting two peers - * @param connect_attempts how many times (max) to attempt - * @param notify_callback callback to notify when finished - * @param notify_cls closure for notify callback - * - * @return the number of connections that will be attempted - */ -static int -connect_topology (struct GNUNET_TESTING_PeerGroup *pg, - struct GNUNET_TIME_Relative connect_timeout, - unsigned int connect_attempts, - GNUNET_TESTING_NotifyCompletion notify_callback, - void *notify_cls) -{ - unsigned int pg_iter; - unsigned int total; - -#if OLD - struct PeerConnection *connection_iter; -#endif -#if USE_SEND_HELLOS - struct SendHelloContext *send_hello_context; -#endif - - total = 0; - pg->ct_ctx.notify_connections_done = notify_callback; - pg->ct_ctx.notify_cls = notify_cls; - pg->ct_ctx.pg = pg; - - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { -#if OLD - connection_iter = pg->peers[pg_iter].connect_peers_head; - while (connection_iter != NULL) - { - connection_iter = connection_iter->next; - total++; - } -#else - total += - GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers); -#endif - } - - if (total == 0) - return total; - - pg->ct_ctx.connect_timeout = connect_timeout; - pg->ct_ctx.connect_attempts = connect_attempts; - pg->ct_ctx.remaining_connections = total; - -#if USE_SEND_HELLOS - /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */ - pg->remaining_hellos = total; - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - send_hello_context = GNUNET_malloc (sizeof (struct SendHelloContext)); - send_hello_context->peer = &pg->peers[pg_iter]; - send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head; - send_hello_context->pg = pg; - GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); - } -#else - for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) - { - preschedule_connect (pg); - } -#endif - return total; - -} - -/** - * Takes a peer group and creates a topology based on the - * one specified. Creates a topology means generates friend - * files for the peers so they can only connect to those allowed - * by the topology. This will only have an effect once peers - * are started if the FRIENDS_ONLY option is set in the base - * config. Also takes an optional restrict topology which - * disallows connections based on particular transports - * UNLESS they are specified in the restricted topology. - * - * @param pg the peer group struct representing the running peers - * @param topology which topology to connect the peers in - * @param restrict_topology disallow restrict_transports transport - * connections to peers NOT in this topology - * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions - * @param restrict_transports space delimited list of transports to blacklist - * to create restricted topology - * - * @return the maximum number of connections were all allowed peers - * connected to each other - */ -unsigned int -GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, - enum GNUNET_TESTING_Topology topology, - enum GNUNET_TESTING_Topology restrict_topology, - const char *restrict_transports) -{ - int ret; - - unsigned int num_connections; - int unblacklisted_connections; - char *filename; - struct PeerConnection *conn_iter; - struct PeerConnection *temp_conn; - unsigned int off; - -#if !OLD - unsigned int i; - - for (i = 0; i < pg->total; i++) - { - pg->peers[i].allowed_peers = GNUNET_CONTAINER_multihashmap_create (100); - pg->peers[i].connect_peers = GNUNET_CONTAINER_multihashmap_create (100); - pg->peers[i].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create (100); - pg->peers[i].pg = pg; - } -#endif - - switch (topology) - { - case GNUNET_TESTING_TOPOLOGY_CLIQUE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating clique topology\n"); - num_connections = create_clique (pg, &add_connections, ALLOWED, GNUNET_NO); - break; - case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating small world (ring) topology\n"); - num_connections = create_small_world_ring (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating small world (2d-torus) topology\n"); - num_connections = create_small_world (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_RING: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring topology\n"); - num_connections = create_ring (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_2D_TORUS: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating 2d torus topology\n"); - num_connections = create_2d_torus (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Erdos-Renyi topology\n"); - num_connections = create_erdos_renyi (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_INTERNAT: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating InterNAT topology\n"); - num_connections = create_nated_internet (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Scale Free topology\n"); - num_connections = create_scale_free (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_LINE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating straight line topology\n"); - num_connections = create_line (pg, &add_connections, ALLOWED); - break; - case GNUNET_TESTING_TOPOLOGY_FROM_FILE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating topology from file!\n"); - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing", - "topology_file", &filename)) - num_connections = - create_from_file (pg, filename, &add_connections, ALLOWED); - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!\n"); - num_connections = 0; - } - break; - case GNUNET_TESTING_TOPOLOGY_NONE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _ - ("Creating no allowed topology (all peers can connect at core level)\n")); - num_connections = pg->total * pg->total; /* Clique is allowed! */ - break; - default: - num_connections = 0; - break; - } - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F")) - { - ret = create_and_copy_friend_files (pg); - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed during friend file copying!\n"); - return GNUNET_SYSERR; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Friend files created/copied successfully!\n"); - } - } - - /* Use the create clique method to initially set all connections as blacklisted. */ - if ((restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE) && - (restrict_topology != GNUNET_TESTING_TOPOLOGY_FROM_FILE)) - create_clique (pg, &add_connections, BLACKLIST, GNUNET_NO); - else - return num_connections; - - unblacklisted_connections = 0; - /* Un-blacklist connections as per the topology specified */ - switch (restrict_topology) - { - case GNUNET_TESTING_TOPOLOGY_CLIQUE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but clique topology\n"); - unblacklisted_connections = - create_clique (pg, &remove_connections, BLACKLIST, GNUNET_NO); - break; - case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but small world (ring) topology\n"); - unblacklisted_connections = - create_small_world_ring (pg, &remove_connections, BLACKLIST); - break; - case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but small world (2d-torus) topology\n"); - unblacklisted_connections = - create_small_world (pg, &remove_connections, BLACKLIST); - break; - case GNUNET_TESTING_TOPOLOGY_RING: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but ring topology\n"); - unblacklisted_connections = - create_ring (pg, &remove_connections, BLACKLIST); - break; - case GNUNET_TESTING_TOPOLOGY_2D_TORUS: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but 2d torus topology\n"); - unblacklisted_connections = - create_2d_torus (pg, &remove_connections, BLACKLIST); - break; - case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but Erdos-Renyi topology\n"); - unblacklisted_connections = - create_erdos_renyi (pg, &remove_connections, BLACKLIST); - break; - case GNUNET_TESTING_TOPOLOGY_INTERNAT: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but InterNAT topology\n"); - -#if TOPOLOGY_HACK - for (off = 0; off < pg->total; off++) - { - conn_iter = pg->peers[off].allowed_peers_head; - while (conn_iter != NULL) - { - temp_conn = conn_iter->next; - GNUNET_free (conn_iter); - conn_iter = temp_conn; - } - pg->peers[off].allowed_peers_head = NULL; - pg->peers[off].allowed_peers_tail = NULL; - - conn_iter = pg->peers[off].connect_peers_head; - while (conn_iter != NULL) - { - temp_conn = conn_iter->next; - GNUNET_free (conn_iter); - conn_iter = temp_conn; - } - pg->peers[off].connect_peers_head = NULL; - pg->peers[off].connect_peers_tail = NULL; - } - unblacklisted_connections = - create_nated_internet_copy (pg, &remove_connections, BLACKLIST); -#else - unblacklisted_connections = - create_nated_internet (pg, &remove_connections, BLACKLIST); -#endif - - break; - case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but Scale Free topology\n"); - unblacklisted_connections = - create_scale_free (pg, &remove_connections, BLACKLIST); - break; - case GNUNET_TESTING_TOPOLOGY_LINE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklisting all but straight line topology\n"); - unblacklisted_connections = - create_line (pg, &remove_connections, BLACKLIST); - default: - break; - } - - if ((unblacklisted_connections > 0) && (restrict_transports != NULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating blacklist with `%s'\n", - restrict_transports); - ret = create_and_copy_blacklist_files (pg, restrict_transports); - if (ret != GNUNET_OK) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed during blacklist file copying!\n"); - return 0; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Blacklist files created/copied successfully!\n"); - } - } - return num_connections; -} - -#if !OLD -/** - * Iterator for choosing random peers to connect. - * - * @param cls closure, a RandomContext - * @param key the key the second Daemon was stored under - * @param value the GNUNET_TESTING_Daemon that the first is to connect to - * - * @return GNUNET_YES to continue iteration - */ -static int -random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct RandomContext *random_ctx = cls; - double random_number; - uint32_t second_pos; - GNUNET_HashCode first_hash; - - random_number = - ((double) - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX)) / ((double) UINT64_MAX); - if (random_number < random_ctx->percentage) - { - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (random_ctx-> - first->connect_peers_working_set, - key, value, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - } - - /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */ - uid_from_hash (key, &second_pos); - hash_from_uid (random_ctx->first_uid, &first_hash); - GNUNET_assert (random_ctx->pg->total > second_pos); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (random_ctx-> - pg->peers - [second_pos].connect_peers, - &first_hash, - random_ctx-> - first->daemon)); - - return GNUNET_YES; -} - -/** - * Iterator for adding at least X peers to a peers connection set. - * - * @param cls closure, MinimumContext - * @param key the key the second Daemon was stored under - * @param value the GNUNET_TESTING_Daemon that the first is to connect to - * - * @return GNUNET_YES to continue iteration - */ -static int -minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct MinimumContext *min_ctx = cls; - uint32_t second_pos; - GNUNET_HashCode first_hash; - unsigned int i; - - if (GNUNET_CONTAINER_multihashmap_size - (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add) - { - for (i = 0; i < min_ctx->num_to_add; i++) - { - if (min_ctx->pg_array[i] == min_ctx->current) - { - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (min_ctx-> - first->connect_peers_working_set, - key, value, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - uid_from_hash (key, &second_pos); - hash_from_uid (min_ctx->first_uid, &first_hash); - GNUNET_assert (min_ctx->pg->total > second_pos); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (min_ctx-> - pg->peers - [second_pos].connect_peers_working_set, - &first_hash, - min_ctx->first-> - daemon, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */ - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (min_ctx-> - pg->peers - [second_pos].connect_peers, - &first_hash, - min_ctx-> - first->daemon)); - } - } - min_ctx->current++; - return GNUNET_YES; - } - else - return GNUNET_NO; /* We can stop iterating, we have enough peers! */ - -} - -/** - * Iterator for adding peers to a connection set based on a depth first search. - * - * @param cls closure, MinimumContext - * @param key the key the second daemon was stored under - * @param value the GNUNET_TESTING_Daemon that the first is to connect to - * - * @return GNUNET_YES to continue iteration - */ -static int -dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct DFSContext *dfs_ctx = cls; - GNUNET_HashCode first_hash; - - if (dfs_ctx->current == dfs_ctx->chosen) - { - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> - first->connect_peers_working_set, - key, value, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - uid_from_hash (key, &dfs_ctx->second_uid); - hash_from_uid (dfs_ctx->first_uid, &first_hash); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> - pg->peers[dfs_ctx-> - second_uid].connect_peers_working_set, - &first_hash, - dfs_ctx->first->daemon, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (dfs_ctx-> - pg->peers - [dfs_ctx->second_uid].connect_peers, - &first_hash, - dfs_ctx-> - first->daemon)); - /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */ - return GNUNET_NO; /* We have found our peer, don't iterate more */ - } - - dfs_ctx->current++; - return GNUNET_YES; -} -#endif - -/** - * From the set of connections possible, choose percentage percent of connections - * to actually connect. - * - * @param pg the peergroup we are dealing with - * @param percentage what percent of total connections to make - */ -void -choose_random_connections (struct GNUNET_TESTING_PeerGroup *pg, - double percentage) -{ - uint32_t pg_iter; - -#if OLD - struct PeerConnection *conn_iter; - double random_number; -#else - struct RandomContext random_ctx; -#endif - - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { -#if OLD - conn_iter = pg->peers[pg_iter].connect_peers_head; - while (conn_iter != NULL) - { - random_number = - ((double) - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT64_MAX)) / ((double) UINT64_MAX); - if (random_number < percentage) - { - add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, - GNUNET_YES); - } - conn_iter = conn_iter->next; - } -#else - random_ctx.first_uid = pg_iter; - random_ctx.first = &pg->peers[pg_iter]; - random_ctx.percentage = percentage; - random_ctx.pg = pg; - pg->peers[pg_iter].connect_peers_working_set = - GNUNET_CONTAINER_multihashmap_create (pg->total); - GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, - &random_connect_iterator, - &random_ctx); - /* Now remove the old connections */ - GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); - /* And replace with the random set */ - pg->peers[pg_iter].connect_peers = - pg->peers[pg_iter].connect_peers_working_set; -#endif - } - - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - conn_iter = pg->peers[pg_iter].connect_peers_head; - while (pg->peers[pg_iter].connect_peers_head != NULL) - remove_connections (pg, pg_iter, - pg->peers[pg_iter].connect_peers_head->index, CONNECT, - GNUNET_YES); - - pg->peers[pg_iter].connect_peers_head = - pg->peers[pg_iter].connect_peers_working_set_head; - pg->peers[pg_iter].connect_peers_tail = - pg->peers[pg_iter].connect_peers_working_set_tail; - pg->peers[pg_iter].connect_peers_working_set_head = NULL; - pg->peers[pg_iter].connect_peers_working_set_tail = NULL; - } -} - -/** - * Count the number of connections in a linked list of connections. - * - * @param conn_list the connection list to get the count of - * - * @return the number of elements in the list - */ -static unsigned int -count_connections (struct PeerConnection *conn_list) -{ - struct PeerConnection *iter; - unsigned int count; - - count = 0; - iter = conn_list; - while (iter != NULL) - { - iter = iter->next; - count++; - } - return count; -} - -static unsigned int -count_workingset_connections (struct GNUNET_TESTING_PeerGroup *pg) -{ - unsigned int count; - unsigned int pg_iter; - -#if OLD - struct PeerConnection *conn_iter; -#endif - count = 0; - - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { -#if OLD - conn_iter = pg->peers[pg_iter].connect_peers_working_set_head; - while (conn_iter != NULL) - { - count++; - conn_iter = conn_iter->next; - } -#else - count += - GNUNET_CONTAINER_multihashmap_size (pg-> - peers - [pg_iter].connect_peers_working_set); -#endif - } - - return count; -} - -static unsigned int -count_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg) -{ - unsigned int count; - unsigned int pg_iter; - -#if OLD - struct PeerConnection *conn_iter; -#endif - - count = 0; - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { -#if OLD - conn_iter = pg->peers[pg_iter].allowed_peers_head; - while (conn_iter != NULL) - { - count++; - conn_iter = conn_iter->next; - } -#else - count += - GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].allowed_peers); -#endif - } - - return count; -} - -/** - * From the set of connections possible, choose at least num connections per - * peer. - * - * @param pg the peergroup we are dealing with - * @param num how many connections at least should each peer have (if possible)? - */ -static void -choose_minimum (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) -{ -#if !OLD - struct MinimumContext minimum_ctx; -#else - struct PeerConnection *conn_iter; - unsigned int temp_list_size; - unsigned int i; - unsigned int count; - uint32_t random; /* Random list entry to connect peer to */ -#endif - uint32_t pg_iter; - -#if OLD - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - temp_list_size = count_connections (pg->peers[pg_iter].connect_peers_head); - if (temp_list_size == 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peer %d has 0 connections!?!?\n", - pg_iter); - break; - } - for (i = 0; i < num; i++) - { - random = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_list_size); - conn_iter = pg->peers[pg_iter].connect_peers_head; - for (count = 0; count < random; count++) - conn_iter = conn_iter->next; - /* We now have a random connection, connect it! */ - GNUNET_assert (conn_iter != NULL); - add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, GNUNET_YES); - } - } -#else - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - pg->peers[pg_iter].connect_peers_working_set = - GNUNET_CONTAINER_multihashmap_create (num); - } - - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - minimum_ctx.first_uid = pg_iter; - minimum_ctx.pg_array = - GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, - GNUNET_CONTAINER_multihashmap_size - (pg->peers[pg_iter].connect_peers)); - minimum_ctx.first = &pg->peers[pg_iter]; - minimum_ctx.pg = pg; - minimum_ctx.num_to_add = num; - minimum_ctx.current = 0; - GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, - &minimum_connect_iterator, - &minimum_ctx); - } - - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - /* Remove the "old" connections */ - GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); - /* And replace with the working set */ - pg->peers[pg_iter].connect_peers = - pg->peers[pg_iter].connect_peers_working_set; - } -#endif - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - while (pg->peers[pg_iter].connect_peers_head != NULL) - { - conn_iter = pg->peers[pg_iter].connect_peers_head; - GNUNET_CONTAINER_DLL_remove (pg->peers[pg_iter].connect_peers_head, - pg->peers[pg_iter].connect_peers_tail, - conn_iter); - GNUNET_free (conn_iter); - /*remove_connections(pg, pg_iter, pg->peers[pg_iter].connect_peers_head->index, CONNECT, GNUNET_YES); */ - } - - pg->peers[pg_iter].connect_peers_head = - pg->peers[pg_iter].connect_peers_working_set_head; - pg->peers[pg_iter].connect_peers_tail = - pg->peers[pg_iter].connect_peers_working_set_tail; - pg->peers[pg_iter].connect_peers_working_set_head = NULL; - pg->peers[pg_iter].connect_peers_working_set_tail = NULL; - } -} - -#if !OLD -struct FindClosestContext -{ - /** - * The currently known closest peer. - */ - struct GNUNET_TESTING_Daemon *closest; - - /** - * The info for the peer we are adding connections for. - */ - struct PeerData *curr_peer; - - /** - * The distance (bits) between the current - * peer and the currently known closest. - */ - unsigned int closest_dist; - - /** - * The offset of the closest known peer in - * the peer group. - */ - unsigned int closest_num; -}; - -/** - * Iterator over hash map entries of the allowed - * peer connections. Find the closest, not already - * connected peer and return it. - * - * @param cls closure (struct FindClosestContext) - * @param key current key code (hash of offset in pg) - * @param value value in the hash map - a GNUNET_TESTING_Daemon - * @return GNUNET_YES if we should continue to - * iterate, - * GNUNET_NO if not. - */ -static int -find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value) -{ - struct FindClosestContext *closest_ctx = cls; - struct GNUNET_TESTING_Daemon *daemon = value; - - if (((closest_ctx->closest == NULL) || - (GNUNET_CRYPTO_hash_matching_bits - (&daemon->id.hashPubKey, - &closest_ctx->curr_peer->daemon->id.hashPubKey) > - closest_ctx->closest_dist)) && - (GNUNET_YES != - GNUNET_CONTAINER_multihashmap_contains (closest_ctx-> - curr_peer->connect_peers, key))) - { - closest_ctx->closest_dist = - GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey, - &closest_ctx->curr_peer->daemon-> - id.hashPubKey); - closest_ctx->closest = daemon; - uid_from_hash (key, &closest_ctx->closest_num); - } - return GNUNET_YES; -} - -/** - * From the set of connections possible, choose at num connections per - * peer based on depth which are closest out of those allowed. Guaranteed - * to add num peers to connect to, provided there are that many peers - * in the underlay topology to connect to. - * - * @param pg the peergroup we are dealing with - * @param num how many connections at least should each peer have (if possible)? - * @param proc processor to actually add the connections - * @param list the peer list to use - */ -void -add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num, - GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) -{ -#if OLD - -#else - struct FindClosestContext closest_ctx; -#endif - uint32_t pg_iter; - uint32_t i; - - for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */ - { - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - closest_ctx.curr_peer = &pg->peers[pg_iter]; - closest_ctx.closest = NULL; - closest_ctx.closest_dist = 0; - closest_ctx.closest_num = 0; - GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, - &find_closest_peers, &closest_ctx); - if (closest_ctx.closest != NULL) - { - GNUNET_assert (closest_ctx.closest_num < pg->total); - proc (pg, pg_iter, closest_ctx.closest_num, list); - } - } - } -} -#endif - -/** - * From the set of connections possible, choose at least num connections per - * peer based on depth first traversal of peer connections. If DFS leaves - * peers unconnected, ensure those peers get connections. - * - * @param pg the peergroup we are dealing with - * @param num how many connections at least should each peer have (if possible)? - */ -void -perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) -{ - uint32_t pg_iter; - uint32_t dfs_count; - uint32_t starting_peer; - uint32_t least_connections; - uint32_t random_connection; - -#if OLD - unsigned int temp_count; - struct PeerConnection *peer_iter; -#else - struct DFSContext dfs_ctx; - GNUNET_HashCode second_hash; -#endif - -#if OLD - starting_peer = 0; - dfs_count = 0; - while ((count_workingset_connections (pg) < num * pg->total) && - (count_allowed_connections (pg) > 0)) - { - if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ - { - least_connections = -1; /* Set to very high number */ - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - temp_count = - count_connections (pg-> - peers[pg_iter].connect_peers_working_set_head); - if (temp_count < least_connections) - { - starting_peer = pg_iter; - least_connections = temp_count; - } - } - } - - temp_count = - count_connections (pg->peers[starting_peer].connect_peers_head); - if (temp_count == 0) - continue; /* FIXME: infinite loop? */ - - random_connection = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_count); - temp_count = 0; - peer_iter = pg->peers[starting_peer].connect_peers_head; - while (temp_count < random_connection) - { - peer_iter = peer_iter->next; - temp_count++; - } - GNUNET_assert (peer_iter != NULL); - add_connections (pg, starting_peer, peer_iter->index, WORKING_SET, - GNUNET_NO); - remove_connections (pg, starting_peer, peer_iter->index, CONNECT, - GNUNET_YES); - starting_peer = peer_iter->index; - dfs_count++; - } - -#else - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - pg->peers[pg_iter].connect_peers_working_set = - GNUNET_CONTAINER_multihashmap_create (num); - } - - starting_peer = 0; - dfs_count = 0; - while ((count_workingset_connections (pg) < num * pg->total) && - (count_allowed_connections (pg) > 0)) - { - if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ - { - least_connections = -1; /* Set to very high number */ - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - if (GNUNET_CONTAINER_multihashmap_size - (pg->peers[pg_iter].connect_peers_working_set) < least_connections) - { - starting_peer = pg_iter; - least_connections = - GNUNET_CONTAINER_multihashmap_size (pg-> - peers - [pg_iter].connect_peers_working_set); - } - } - } - - if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */ - { - dfs_count = 0; - continue; - } - - /* Choose a random peer from the chosen peers set of connections to add */ - dfs_ctx.chosen = - GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - GNUNET_CONTAINER_multihashmap_size (pg->peers - [starting_peer].connect_peers)); - dfs_ctx.first_uid = starting_peer; - dfs_ctx.first = &pg->peers[starting_peer]; - dfs_ctx.pg = pg; - dfs_ctx.current = 0; - - GNUNET_CONTAINER_multihashmap_iterate (pg-> - peers[starting_peer].connect_peers, - &dfs_connect_iterator, &dfs_ctx); - /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */ - hash_from_uid (dfs_ctx.second_uid, &second_hash); - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (pg->peers - [starting_peer].connect_peers, - &second_hash, - pg-> - peers - [dfs_ctx.second_uid].daemon)); - starting_peer = dfs_ctx.second_uid; - } - - for (pg_iter = 0; pg_iter < pg->total; pg_iter++) - { - /* Remove the "old" connections */ - GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); - /* And replace with the working set */ - pg->peers[pg_iter].connect_peers = - pg->peers[pg_iter].connect_peers_working_set; - } -#endif -} - -/** - * Internal callback for topology information for a particular peer. - */ -static void -internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *peer, - const struct GNUNET_ATS_Information *atsi, - unsigned int atsi_count) -{ - struct CoreContext *core_ctx = cls; - struct TopologyIterateContext *iter_ctx = core_ctx->iter_context; - - if (peer == NULL) /* Either finished, or something went wrong */ - { - iter_ctx->completed++; - iter_ctx->connected--; - /* One core context allocated per iteration, must free! */ - GNUNET_free (core_ctx); - } - else - { - iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id, peer, NULL); - } - - if (iter_ctx->completed == iter_ctx->total) - { - iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL); - /* Once all are done, free the iteration context */ - GNUNET_free (iter_ctx); - } -} - -/** - * Check running topology iteration tasks, if below max start a new one, otherwise - * schedule for some time in the future. - */ -static void -schedule_get_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct CoreContext *core_context = cls; - struct TopologyIterateContext *topology_context = - (struct TopologyIterateContext *) core_context->iter_context; - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - return; - - if (topology_context->connected > - topology_context->pg->max_outstanding_connections) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Delaying connect, we have too many outstanding connections!\n"); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_get_topology, core_context); - } - else - { - topology_context->connected++; - - if (GNUNET_OK != - GNUNET_CORE_iterate_peers (core_context->daemon->cfg, - &internal_topology_callback, core_context)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n"); - internal_topology_callback (core_context, NULL, NULL, 0); - } - } -} - -/** - * Iterate over all (running) peers in the peer group, retrieve - * all connections that each currently has. - */ -void -GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_NotifyTopology cb, void *cls) -{ - struct TopologyIterateContext *topology_context; - struct CoreContext *core_ctx; - unsigned int i; - unsigned int total_count; - - /* Allocate a single topology iteration context */ - topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext)); - topology_context->topology_cb = cb; - topology_context->cls = cls; - topology_context->pg = pg; - total_count = 0; - for (i = 0; i < pg->total; i++) - { - if (pg->peers[i].daemon->running == GNUNET_YES) - { - /* Allocate one core context per core we need to connect to */ - core_ctx = GNUNET_malloc (sizeof (struct CoreContext)); - core_ctx->daemon = pg->peers[i].daemon; - /* Set back pointer to topology iteration context */ - core_ctx->iter_context = topology_context; - GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx); - total_count++; - } - } - if (total_count == 0) - { - cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!"); - GNUNET_free (topology_context); - } - else - topology_context->total = total_count; - return; -} - -/** - * Callback function to process statistic values. - * This handler is here only really to insert a peer - * identity (or daemon) so the statistics can be uniquely - * tied to a single running peer. - * - * @param cls closure - * @param subsystem name of subsystem that created the statistic - * @param name the name of the datum - * @param value the current value - * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration - */ -static int -internal_stats_callback (void *cls, const char *subsystem, const char *name, - uint64_t value, int is_persistent) -{ - struct StatsCoreContext *core_context = cls; - struct StatsIterateContext *stats_context = - (struct StatsIterateContext *) core_context->iter_context; - - return stats_context->proc (stats_context->cls, &core_context->daemon->id, - subsystem, name, value, is_persistent); -} - - -/** - * We don't need the statistics handle anymore, destroy it. - * - * @param cls Closure (the statistics handle to destroy) - * @param tc Task Context - */ -static void -internal_destroy_statistics (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_STATISTICS_Handle *h = cls; - - GNUNET_STATISTICS_destroy (h, GNUNET_NO); -} - - -/** - * Internal continuation call for statistics iteration. - * - * @param cls closure, the CoreContext for this iteration - * @param success whether or not the statistics iterations - * was canceled or not (we don't care) - */ -static void -internal_stats_cont (void *cls, int success) -{ - struct StatsCoreContext *core_context = cls; - struct StatsIterateContext *stats_context = - (struct StatsIterateContext *) core_context->iter_context; - - stats_context->connected--; - stats_context->completed++; - - if (stats_context->completed == stats_context->total) - { - stats_context->cont (stats_context->cls, GNUNET_YES); - GNUNET_free (stats_context); - } - - if (core_context->stats_handle != NULL) - /* Cannot destroy handle inside the continuation */ - GNUNET_SCHEDULER_add_now (&internal_destroy_statistics, - core_context->stats_handle); - - GNUNET_free (core_context); -} - -/** - * Check running topology iteration tasks, if below max start a new one, otherwise - * schedule for some time in the future. - */ -static void -schedule_get_statistics (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct StatsCoreContext *core_context = cls; - struct StatsIterateContext *stats_context = - (struct StatsIterateContext *) core_context->iter_context; - - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - return; - - if (stats_context->connected > stats_context->pg->max_outstanding_connections) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Delaying connect, we have too many outstanding connections!\n"); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_get_statistics, core_context); - } - else - { - stats_context->connected++; - core_context->stats_handle = - GNUNET_STATISTICS_create ("testing", core_context->daemon->cfg); - if (core_context->stats_handle == NULL) - { - internal_stats_cont (core_context, GNUNET_NO); - return; - } - - core_context->stats_get_handle = - GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL, - GNUNET_TIME_UNIT_FOREVER_REL, - &internal_stats_cont, &internal_stats_callback, - core_context); - if (core_context->stats_get_handle == NULL) - internal_stats_cont (core_context, GNUNET_NO); - - } -} - -struct DuplicateStats -{ - /** - * Next item in the list - */ - struct DuplicateStats *next; - - /** - * Nasty string, concatenation of relevant information. - */ - char *unique_string; -}; - -/** - * Check whether the combination of port/host/unix domain socket - * already exists in the list of peers being checked for statistics. - * - * @param pg the peergroup in question - * @param specific_peer the peer we're concerned with - * @param stats_list the list to return to the caller - * - * @return GNUNET_YES if the statistics instance has been seen already, - * GNUNET_NO if not (and we may have added it to the list) - */ -static int -stats_check_existing (struct GNUNET_TESTING_PeerGroup *pg, - struct PeerData *specific_peer, - struct DuplicateStats **stats_list) -{ - struct DuplicateStats *pos; - char *unix_domain_socket; - unsigned long long port; - char *to_match; - - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing", - "single_statistics_per_host")) - return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */ - - pos = *stats_list; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg, "statistics", - "unixpath", &unix_domain_socket)) - return GNUNET_NO; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics", - "port", &port)) - { - GNUNET_free (unix_domain_socket); - return GNUNET_NO; - } - - if (specific_peer->daemon->hostname != NULL) - GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname, - unix_domain_socket, port); - else - GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port); - - while (pos != NULL) - { - if (0 == strcmp (to_match, pos->unique_string)) - { - GNUNET_free (unix_domain_socket); - GNUNET_free (to_match); - return GNUNET_YES; - } - pos = pos->next; - } - pos = GNUNET_malloc (sizeof (struct DuplicateStats)); - pos->unique_string = to_match; - pos->next = *stats_list; - *stats_list = pos; - GNUNET_free (unix_domain_socket); - return GNUNET_NO; -} - -/** - * Iterate over all (running) peers in the peer group, retrieve - * all statistics from each. - * - * @param pg the peergroup to iterate statistics of - * @param cont continuation to call once all stats have been retrieved - * @param proc processing function for each statistic from each peer - * @param cls closure to pass to proc - * - */ -void -GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_STATISTICS_Callback cont, - GNUNET_TESTING_STATISTICS_Iterator proc, - void *cls) -{ - struct StatsIterateContext *stats_context; - struct StatsCoreContext *core_ctx; - unsigned int i; - unsigned int total_count; - struct DuplicateStats *stats_list; - struct DuplicateStats *pos; - - stats_list = NULL; - - /* Allocate a single stats iteration context */ - stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext)); - stats_context->cont = cont; - stats_context->proc = proc; - stats_context->cls = cls; - stats_context->pg = pg; - total_count = 0; - - for (i = 0; i < pg->total; i++) - { - if ((pg->peers[i].daemon->running == GNUNET_YES) && - (GNUNET_NO == stats_check_existing (pg, &pg->peers[i], &stats_list))) - { - /* Allocate one core context per core we need to connect to */ - core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext)); - core_ctx->daemon = pg->peers[i].daemon; - /* Set back pointer to topology iteration context */ - core_ctx->iter_context = stats_context; - GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx); - total_count++; - } - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Retrieving stats from %u total instances.\n", total_count); - if (0 != total_count) - stats_context->total = total_count; - else - GNUNET_free (stats_context); - if (stats_list != NULL) - { - pos = stats_list; - while (pos != NULL) - { - GNUNET_free (pos->unique_string); - stats_list = pos->next; - GNUNET_free (pos); - pos = stats_list->next; - } - } - return; -} - -/** - * Stop the connection process temporarily. - * - * @param pg the peer group to stop connecting - */ -void -GNUNET_TESTING_stop_connections (struct GNUNET_TESTING_PeerGroup *pg) -{ - pg->stop_connects = GNUNET_YES; -} - -/** - * Resume the connection process temporarily. - * - * @param pg the peer group to resume connecting - */ -void -GNUNET_TESTING_resume_connections (struct GNUNET_TESTING_PeerGroup *pg) -{ - pg->stop_connects = GNUNET_NO; -} - -/** - * There are many ways to connect peers that are supported by this function. - * To connect peers in the same topology that was created via the - * GNUNET_TESTING_create_topology, the topology variable must be set to - * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, - * a new instance of that topology will be generated and attempted to be - * connected. This could result in some connections being impossible, - * because some topologies are non-deterministic. - * - * @param pg the peer group struct representing the running peers - * @param topology which topology to connect the peers in - * @param options options for connecting the topology - * @param option_modifier modifier for options that take a parameter - * @param connect_timeout how long to wait before giving up on connecting - * two peers - * @param connect_attempts how many times to attempt to connect two peers - * over the connect_timeout duration - * @param notify_callback notification to be called once all connections completed - * @param notify_cls closure for notification callback - * - * @return the number of connections that will be attempted, GNUNET_SYSERR on error - */ -int -GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, - enum GNUNET_TESTING_Topology topology, - enum GNUNET_TESTING_TopologyOption options, - double option_modifier, - struct GNUNET_TIME_Relative connect_timeout, - unsigned int connect_attempts, - GNUNET_TESTING_NotifyCompletion - notify_callback, void *notify_cls) -{ - switch (topology) - { - case GNUNET_TESTING_TOPOLOGY_CLIQUE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating clique CONNECT topology\n"); - create_clique (pg, &add_connections, CONNECT, GNUNET_NO); - break; - case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating small world (ring) CONNECT topology\n"); - create_small_world_ring (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating small world (2d-torus) CONNECT topology\n"); - create_small_world (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_RING: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring CONNECT topology\n"); - create_ring (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_2D_TORUS: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating 2d torus CONNECT topology\n"); - create_2d_torus (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating Erdos-Renyi CONNECT topology\n"); - create_erdos_renyi (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_INTERNAT: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating InterNAT CONNECT topology\n"); - create_nated_internet (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating Scale Free CONNECT topology\n"); - create_scale_free (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_LINE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating straight line CONNECT topology\n"); - create_line (pg, &add_connections, CONNECT); - break; - case GNUNET_TESTING_TOPOLOGY_NONE: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating no CONNECT topology\n"); - copy_allowed_topology (pg); - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Unknown topology specification, can't connect peers!\n")); - return GNUNET_SYSERR; - } - - switch (options) - { - case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting random subset (%'.2f percent) of possible peers\n", - 100 * option_modifier); - choose_random_connections (pg, option_modifier); - break; - case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting a minimum of %u peers each (if possible)\n", - (unsigned int) option_modifier); - choose_minimum (pg, (unsigned int) option_modifier); - break; - case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Using DFS to connect a minimum of %u peers each (if possible)\n", - (unsigned int) option_modifier); -#if FIXME - perform_dfs (pg, (int) option_modifier); -#endif - break; - case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST: - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Finding additional %u closest peers each (if possible)\n", - (unsigned int) option_modifier); -#if FIXME - add_closest (pg, (unsigned int) option_modifier, &add_connections, CONNECT); -#endif - break; - case GNUNET_TESTING_TOPOLOGY_OPTION_NONE: - break; - case GNUNET_TESTING_TOPOLOGY_OPTION_ALL: - break; - default: - break; - } - - return connect_topology (pg, connect_timeout, connect_attempts, - notify_callback, notify_cls); -} - -/** - * Lookup and return the number of SSH connections to a host. - * - * @param hostname the hostname to lookup in the list - * @param pg the peergroup that the host belongs to - * - * @return the number of current ssh connections to the host - */ -static unsigned int -count_outstanding_at_host (const char *hostname, - struct GNUNET_TESTING_PeerGroup *pg) -{ - struct OutstandingSSH *pos; - - pos = pg->ssh_head; - while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) - pos = pos->next; - GNUNET_assert (pos != NULL); - return pos->outstanding; -} - -/** - * Increment the number of SSH connections to a host by one. - * - * @param hostname the hostname to lookup in the list - * @param pg the peergroup that the host belongs to - * - */ -static void -increment_outstanding_at_host (const char *hostname, - struct GNUNET_TESTING_PeerGroup *pg) -{ - struct OutstandingSSH *pos; - - pos = pg->ssh_head; - while ((NULL != pos) && (strcmp (pos->hostname, hostname) != 0)) - pos = pos->next; - GNUNET_assert (NULL != pos); - pos->outstanding++; -} - -/** - * Decrement the number of SSH connections to a host by one. - * - * @param hostname the hostname to lookup in the list - * @param pg the peergroup that the host belongs to - * - */ -static void -decrement_outstanding_at_host (const char *hostname, - struct GNUNET_TESTING_PeerGroup *pg) -{ - struct OutstandingSSH *pos; - - pos = pg->ssh_head; - while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) - pos = pos->next; - GNUNET_assert (pos != NULL); - pos->outstanding--; -} - -/** - * Callback that is called whenever a hostkey is generated - * for a peer. Call the real callback and decrement the - * starting counter for the peergroup. - * - * @param cls closure - * @param id identifier for the daemon, NULL on error - * @param d handle for the daemon - * @param emsg error message (NULL on success) - */ -static void -internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - struct InternalStartContext *internal_context = cls; - - internal_context->peer->pg->starting--; - internal_context->peer->pg->started++; - if (internal_context->hostname != NULL) - decrement_outstanding_at_host (internal_context->hostname, - internal_context->peer->pg); - if (internal_context->hostkey_callback != NULL) - internal_context->hostkey_callback (internal_context->hostkey_cls, id, d, - emsg); - else if (internal_context->peer->pg->started == - internal_context->peer->pg->total) - { - internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */ - GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg); - } -} - -/** - * Callback that is called whenever a peer has finished starting. - * Call the real callback and decrement the starting counter - * for the peergroup. - * - * @param cls closure - * @param id identifier for the daemon, NULL on error - * @param cfg config - * @param d handle for the daemon - * @param emsg error message (NULL on success) - */ -static void -internal_startup_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - struct InternalStartContext *internal_context = cls; - - internal_context->peer->pg->starting--; - if (internal_context->hostname != NULL) - decrement_outstanding_at_host (internal_context->hostname, - internal_context->peer->pg); - if (internal_context->start_cb != NULL) - internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d, - emsg); -} - - -/** - * Calls GNUNET_TESTING_daemon_continue_startup to set the daemon's state - * from HOSTKEY_CREATED to TOPOLOGY_SETUP. Makes sure not to saturate a host - * with requests delaying them when needed. - * - * @param cls closure: internal context of the daemon. - * @param tc TaskContext - */ -static void -internal_continue_startup (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct InternalStartContext *internal_context = cls; - - internal_context->peer->startup_task = GNUNET_SCHEDULER_NO_TASK; - - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - { - return; - } - - if ((internal_context->peer->pg->starting < - internal_context->peer->pg->max_concurrent_ssh) || - ((internal_context->hostname != NULL) && - (count_outstanding_at_host - (internal_context->hostname, - internal_context->peer->pg) < - internal_context->peer->pg->max_concurrent_ssh))) - { - if (internal_context->hostname != NULL) - increment_outstanding_at_host (internal_context->hostname, - internal_context->peer->pg); - internal_context->peer->pg->starting++; - GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon); - } - else - { - internal_context->peer->startup_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &internal_continue_startup, - internal_context); - } -} - -/** - * Callback for informing us about a successful - * or unsuccessful churn start call. - * - * @param cls a ChurnContext - * @param id the peer identity of the started peer - * @param cfg the handle to the configuration of the peer - * @param d handle to the daemon for the peer - * @param emsg NULL on success, non-NULL on failure - * - */ -void -churn_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - struct ChurnRestartContext *startup_ctx = cls; - struct ChurnContext *churn_ctx = startup_ctx->churn_ctx; - - unsigned int total_left; - char *error_message; - - error_message = NULL; - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Churn stop callback failed with error `%s'\n", emsg); - churn_ctx->num_failed_start++; - } - else - { - churn_ctx->num_to_start--; - } - - total_left = - (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + - (churn_ctx->num_to_start - churn_ctx->num_failed_start); - - if (total_left == 0) - { - if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) - GNUNET_asprintf (&error_message, - "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", - churn_ctx->num_failed_start, churn_ctx->num_failed_stop); - churn_ctx->cb (churn_ctx->cb_cls, error_message); - GNUNET_free_non_null (error_message); - GNUNET_free (churn_ctx); - GNUNET_free (startup_ctx); - } -} - -static void -schedule_churn_restart (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PeerRestartContext *peer_restart_ctx = cls; - struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx; - - if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_churn_restart, peer_restart_ctx); - else - { - if (startup_ctx->churn_ctx->service != NULL) - GNUNET_TESTING_daemon_start_stopped_service (peer_restart_ctx->daemon, - startup_ctx-> - churn_ctx->service, - startup_ctx->timeout, - &churn_start_callback, - startup_ctx); - else - GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon, - startup_ctx->timeout, - &churn_start_callback, startup_ctx); - GNUNET_free (peer_restart_ctx); - } -} - -/** - * Callback for informing us about a successful - * or unsuccessful churn start call. - * - * @param cls a struct ServiceStartContext *startup_ctx - * @param id the peer identity of the started peer - * @param cfg the handle to the configuration of the peer - * @param d handle to the daemon for the peer - * @param emsg NULL on success, non-NULL on failure - * - */ -void -service_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - struct ServiceStartContext *startup_ctx = (struct ServiceStartContext *) cls; - - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Service start failed with error `%s'\n", emsg); - } - - startup_ctx->outstanding--; - startup_ctx->remaining--; - - if (startup_ctx->remaining == 0) - { - startup_ctx->cb (startup_ctx->cb_cls, NULL); - GNUNET_free (startup_ctx->service); - GNUNET_free (startup_ctx); - } -} - -static void -schedule_service_start (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PeerServiceStartContext *peer_ctx = cls; - struct ServiceStartContext *startup_ctx = peer_ctx->start_ctx; - - if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_service_start, peer_ctx); - else - { - - GNUNET_TESTING_daemon_start_service (peer_ctx->daemon, startup_ctx->service, - startup_ctx->timeout, - &service_start_callback, startup_ctx); - GNUNET_free (peer_ctx); - } -} - - -static void -internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct InternalStartContext *internal_context = cls; - - if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) - { - return; - } - - if ((internal_context->peer->pg->starting < - internal_context->peer->pg->max_concurrent_ssh) || - ((internal_context->hostname != NULL) && - (count_outstanding_at_host - (internal_context->hostname, - internal_context->peer->pg) < - internal_context->peer->pg->max_concurrent_ssh))) - { - if (internal_context->hostname != NULL) - increment_outstanding_at_host (internal_context->hostname, - internal_context->peer->pg); - internal_context->peer->pg->starting++; - internal_context->peer->daemon = - GNUNET_TESTING_daemon_start (internal_context->peer->cfg, - internal_context->timeout, GNUNET_NO, - internal_context->hostname, - internal_context->username, - internal_context->sshport, - internal_context->hostkey, - &internal_hostkey_callback, - internal_context, - &internal_startup_callback, - internal_context); - } - else - { - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &internal_start, internal_context); - } -} - -#if USE_START_HELPER - -struct PeerStartHelperContext -{ - struct GNUNET_TESTING_PeerGroup *pg; - - struct HostData *host; - - struct GNUNET_OS_Process *proc; -}; - -static void -check_peers_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PeerStartHelperContext *helper = cls; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - unsigned int i; - GNUNET_TESTING_NotifyDaemonRunning cb; - - if (GNUNET_NO == GNUNET_OS_process_status (helper->proc, &type, &code)) /* Still running, wait some more! */ - { - GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, - &check_peers_started, helper); - return; - } - - helper->pg->starting--; - if (helper->pg->starting == 0) /* All peers have finished starting! */ - { - /* Call the peer started callback for each peer, set proper FSM state (?) */ - for (i = 0; i < helper->pg->total; i++) - { - cb = helper->pg->peers[i].daemon->cb; - helper->pg->peers[i].daemon->cb = NULL; - helper->pg->peers[i].daemon->running = GNUNET_YES; - helper->pg->peers[i].daemon->phase = SP_START_DONE; - if (NULL != cb) - { - if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) - cb (helper->pg->peers[i].daemon->cb_cls, - &helper->pg->peers[i].daemon->id, - helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, - "Failed to execute peerStartHelper.pl, or return code bad!"); - else - cb (helper->pg->peers[i].daemon->cb_cls, - &helper->pg->peers[i].daemon->id, - helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, - NULL); - - } - - } - } - GNUNET_OS_process_destroy (helper->proc); -} - -static void -start_peer_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PeerStartHelperContext *helper = cls; - char *baseservicehome; - char *tempdir; - char *arg; - - /* ssh user@host peerStartHelper /path/to/basedirectory */ - GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (helper->pg->cfg, - "PATHS", "SERVICEHOME", - &baseservicehome)); - GNUNET_asprintf (&tempdir, "%s/%s/", baseservicehome, helper->host->hostname); - if (NULL != helper->host->username) - GNUNET_asprintf (&arg, "%s@%s", helper->host->username, - helper->host->hostname); - else - GNUNET_asprintf (&arg, "%s", helper->host->hostname); - - /* FIXME: Doesn't support ssh_port option! */ - helper->proc = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, - "peerStartHelper.pl", tempdir, NULL); - GNUNET_assert (helper->proc != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting peers with cmd ssh %s %s %s\n", - arg, "peerStartHelper.pl", tempdir); - GNUNET_SCHEDULER_add_now (&check_peers_started, helper); - GNUNET_free (tempdir); - GNUNET_free (baseservicehome); - GNUNET_free (arg); -} -#endif - -/** - * Function which continues a peer group starting up - * after successfully generating hostkeys for each peer. - * - * @param pg the peer group to continue starting - * - */ -void -GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg) -{ - unsigned int i; - -#if USE_START_HELPER - if ((pg->num_hosts > 0) && (pg->hostkey_data != NULL)) - { - struct PeerStartHelperContext *helper; - - pg->starting = pg->num_hosts; - for (i = 0; i < pg->num_hosts; i++) - { - helper = GNUNET_malloc (sizeof (struct PeerStartHelperContext)); - helper->pg = pg; - helper->host = &pg->hosts[i]; - GNUNET_SCHEDULER_add_now (&start_peer_helper, helper); - } - } - else - { - pg->starting = 0; - for (i = 0; i < pg->total; i++) - { - pg->peers[i].startup_task = - GNUNET_SCHEDULER_add_now (&internal_continue_startup, - &pg->peers[i].internal_context); - } - } -#else - pg->starting = 0; - for (i = 0; i < pg->total; i++) - { - pg->peers[i].startup_task = - GNUNET_SCHEDULER_add_now (&internal_continue_startup, - &pg->peers[i].internal_context); - } -#endif -} - -#if USE_START_HELPER -static void -call_hostkey_callbacks (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct GNUNET_TESTING_PeerGroup *pg = cls; - unsigned int i; - - for (i = 0; i < pg->total; i++) - { - if (pg->peers[i].internal_context.hostkey_callback != NULL) - pg->peers[i].internal_context.hostkey_callback (pg->peers[i]. - internal_context.hostkey_cls, - &pg->peers[i].daemon->id, - pg->peers[i].daemon, - NULL); - } - - if (pg->peers[0].internal_context.hostkey_callback == NULL) - GNUNET_TESTING_daemons_continue_startup (pg); -} -#endif - -/** - * Start count gnunet instances with the same set of transports and - * applications. The port numbers (any option called "PORT") will be - * adjusted to ensure that no two peers running on the same system - * have the same port(s) in their respective configurations. - * - * @param cfg configuration template to use - * @param total number of daemons to start - * @param max_concurrent_connections for testing, how many peers can - * we connect to simultaneously - * @param max_concurrent_ssh when starting with ssh, how many ssh - * connections will we allow at once (based on remote hosts allowed!) - * @param timeout total time allowed for peers to start - * @param hostkey_callback function to call on each peers hostkey generation - * if NULL, peers will be started by this call, if non-null, - * GNUNET_TESTING_daemons_continue_startup must be called after - * successful hostkey generation - * @param hostkey_cls closure for hostkey callback - * @param cb function to call on each daemon that was started - * @param cb_cls closure for cb - * @param connect_callback function to call each time two hosts are connected - * @param connect_callback_cls closure for connect_callback - * @param hostnames linked list of host structs to use to start peers on - * (NULL to run on localhost only) - * - * @return NULL on error, otherwise handle to control peer group - */ -struct GNUNET_TESTING_PeerGroup * -GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - unsigned int total, - unsigned int max_concurrent_connections, - unsigned int max_concurrent_ssh, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyHostkeyCreated - hostkey_callback, void *hostkey_cls, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls, - GNUNET_TESTING_NotifyConnection connect_callback, - void *connect_callback_cls, - const struct GNUNET_TESTING_Host *hostnames) -{ - struct GNUNET_TESTING_PeerGroup *pg; - const struct GNUNET_TESTING_Host *hostpos; - const char *hostname; - const char *username; - char *baseservicehome; - char *newservicehome; - char *tmpdir; - char *hostkeys_file; - char *arg; - char *ssh_port_str; - struct GNUNET_DISK_FileHandle *fd; - struct GNUNET_CONFIGURATION_Handle *pcfg; - unsigned int off; - struct OutstandingSSH *ssh_entry; - unsigned int hostcnt; - unsigned int i; - uint16_t minport; - uint16_t sshport; - uint32_t upnum; - uint32_t fdnum; - uint64_t fs; - uint64_t total_hostkeys; - struct GNUNET_OS_Process *proc; - - username = NULL; - if (0 == total) - { - GNUNET_break (0); - return NULL; - } - - upnum = 0; - fdnum = 0; - pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup)); - pg->cfg = cfg; - pg->notify_connection = connect_callback; - pg->notify_connection_cls = connect_callback_cls; - pg->total = total; - pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); - pg->peers = GNUNET_malloc (total * sizeof (struct PeerData)); - pg->max_outstanding_connections = max_concurrent_connections; - pg->max_concurrent_ssh = max_concurrent_ssh; - if (NULL != hostnames) - { - off = 0; - hostpos = hostnames; - while (hostpos != NULL) - { - hostpos = hostpos->next; - off++; - } - pg->hosts = GNUNET_malloc (off * sizeof (struct HostData)); - off = 0; - - hostpos = hostnames; - while (hostpos != NULL) - { - pg->hosts[off].minport = LOW_PORT; - pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname); - if (hostpos->username != NULL) - pg->hosts[off].username = GNUNET_strdup (hostpos->username); - pg->hosts[off].sshport = hostpos->port; - hostpos = hostpos->next; - off++; - } - - if (off == 0) - { - pg->hosts = NULL; - } - hostcnt = off; - minport = 0; - pg->num_hosts = off; - } - else - { - hostcnt = 0; - minport = LOW_PORT; - } - - /* Create the servicehome directory for each remote peer */ - GNUNET_assert (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", - "SERVICEHOME", - &baseservicehome)); - for (i = 0; i < pg->num_hosts; i++) - { - ssh_entry = GNUNET_malloc (sizeof (struct OutstandingSSH)); - ssh_entry->hostname = pg->hosts[i].hostname; /* Don't free! */ - GNUNET_CONTAINER_DLL_insert (pg->ssh_head, pg->ssh_tail, ssh_entry); - GNUNET_asprintf (&tmpdir, "%s/%s", baseservicehome, pg->hosts[i].hostname); - if (NULL != pg->hosts[i].username) - GNUNET_asprintf (&arg, "%s@%s", pg->hosts[i].username, - pg->hosts[i].hostname); - else - GNUNET_asprintf (&arg, "%s", pg->hosts[i].hostname); - if (pg->hosts[i].sshport != 0) - { - GNUNET_asprintf (&ssh_port_str, "%d", pg->hosts[i].sshport); - proc = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-P", ssh_port_str, - "-q", - arg, "mkdir -p", tmpdir, NULL); - } - else - proc = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, "mkdir -p", - tmpdir, NULL); - GNUNET_assert (proc != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Creating remote dir with command ssh %s %s %s\n", arg, - " mkdir -p ", tmpdir); - GNUNET_free (tmpdir); - GNUNET_free (arg); - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_destroy (proc); - } - GNUNET_free (baseservicehome); - baseservicehome = NULL; - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "HOSTKEYSFILE", - &hostkeys_file)) - { - if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Could not read hostkeys file!\n")); - else - { - /* Check hostkey file size, read entire thing into memory */ - fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ, - GNUNET_DISK_PERM_NONE); - if (NULL == fd) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", - hostkeys_file); - GNUNET_free (hostkeys_file); - for (i = 0; i < pg->num_hosts; i++) - { - GNUNET_free (pg->hosts[i].hostname); - GNUNET_free_non_null (pg->hosts[i].username); - } - GNUNET_free (pg->peers); - GNUNET_free (pg->hosts); - GNUNET_free (pg); - return NULL; - } - - if (GNUNET_OK != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES, GNUNET_YES)) - fs = 0; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Found file size %llu for hostkeys\n", fs); - if (0 != (fs % HOSTKEYFILESIZE)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "File size %llu seems incorrect for hostkeys...\n", fs); - } - else - { - total_hostkeys = fs / HOSTKEYFILESIZE; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Will read %llu hostkeys from file\n", total_hostkeys); - pg->hostkey_data = GNUNET_malloc_large (fs); - GNUNET_assert (fs == GNUNET_DISK_file_read (fd, pg->hostkey_data, fs)); - } - GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); - } - GNUNET_free (hostkeys_file); - } - - for (off = 0; off < total; off++) - { - if (hostcnt > 0) - { - hostname = pg->hosts[off % hostcnt].hostname; - username = pg->hosts[off % hostcnt].username; - sshport = pg->hosts[off % hostcnt].sshport; - pcfg = - GNUNET_TESTING_create_cfg (cfg, off, &pg->hosts[off % hostcnt].minport, &upnum, - hostname, &fdnum); - } - else - { - hostname = NULL; - username = NULL; - sshport = 0; - pcfg = GNUNET_TESTING_create_cfg (cfg, off, &minport, &upnum, hostname, &fdnum); - } - - if (NULL == pcfg) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Could not create configuration for peer number %u on `%s'!\n"), - off, hostname == NULL ? "localhost" : hostname); - continue; - } - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME", - &baseservicehome)) - { - if (hostname != NULL) - GNUNET_asprintf (&newservicehome, "%s/%s/%d/", baseservicehome, - hostname, off); - else - GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off); - GNUNET_free (baseservicehome); - baseservicehome = NULL; - } - else - { - tmpdir = getenv ("TMPDIR"); - tmpdir = tmpdir ? tmpdir : "/tmp"; - if (hostname != NULL) - GNUNET_asprintf (&newservicehome, "%s/%s/%s/%d/", tmpdir, hostname, - "gnunet-testing-test-test", off); - else - GNUNET_asprintf (&newservicehome, "%s/%s/%d/", tmpdir, - "gnunet-testing-test-test", off); - } - GNUNET_CONFIGURATION_set_value_string (pcfg, "PATHS", "SERVICEHOME", - newservicehome); - GNUNET_free (newservicehome); - pg->peers[off].cfg = pcfg; - pg->peers[off].pg = pg; - pg->peers[off].internal_context.peer = &pg->peers[off]; - pg->peers[off].internal_context.timeout = timeout; - pg->peers[off].internal_context.hostname = hostname; - pg->peers[off].internal_context.username = username; - pg->peers[off].internal_context.sshport = sshport; - if (pg->hostkey_data != NULL) - pg->peers[off].internal_context.hostkey = - &pg->hostkey_data[off * HOSTKEYFILESIZE]; - pg->peers[off].internal_context.hostkey_callback = hostkey_callback; - pg->peers[off].internal_context.hostkey_cls = hostkey_cls; - pg->peers[off].internal_context.start_cb = cb; - pg->peers[off].internal_context.start_cb_cls = cb_cls; -#if !USE_START_HELPER - GNUNET_SCHEDULER_add_now (&internal_start, - &pg->peers[off].internal_context); -#else - if ((pg->hostkey_data != NULL) && (hostcnt > 0)) - { - pg->peers[off].daemon = - GNUNET_TESTING_daemon_start (pcfg, timeout, GNUNET_YES, hostname, - username, sshport, - pg->peers[off].internal_context.hostkey, - &internal_hostkey_callback, - &pg->peers[off].internal_context, - &internal_startup_callback, - &pg->peers[off].internal_context); - /** - * At this point, given that we had a hostkeyfile, - * we can call the hostkey callback! - * But first, we should copy (rsync) all of the configs - * and hostkeys to the remote peers. Then let topology - * creation happen, then call the peer start helper processes, - * then set pg->whatever_phase for each peer and let them - * enter the fsm to get the HELLO's for peers and start connecting. - */ - } - else - { - GNUNET_SCHEDULER_add_now (&internal_start, - &pg->peers[off].internal_context); - } - -#endif - } - -#if USE_START_HELPER /* Now the peergroup has been set up, hostkeys and configs written to files. */ - if ((pg->hostkey_data != NULL) && (hostcnt > 0)) - { - for (off = 0; off < hostcnt; off++) - { - - if (hostcnt > 0) - { - hostname = pg->hosts[off % hostcnt].hostname; - username = pg->hosts[off % hostcnt].username; - sshport = pg->hosts[off % hostcnt].sshport; - } - else - { - hostname = NULL; - username = NULL; - sshport = 0; - } - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", - &baseservicehome)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "baseservice home is %s\n", - baseservicehome); - if (hostname != NULL) - GNUNET_asprintf (&newservicehome, "%s/%s/", baseservicehome, - hostname); - else - GNUNET_asprintf (&newservicehome, "%s/", baseservicehome); - GNUNET_free (baseservicehome); - baseservicehome = NULL; - } - else - { - tmpdir = getenv ("TMPDIR"); - tmpdir = tmpdir ? tmpdir : "/tmp"; - if (hostname != NULL) - GNUNET_asprintf (&newservicehome, "%s/%s/%s/", tmpdir, hostname, - "gnunet-testing-test-test"); - else - GNUNET_asprintf (&newservicehome, "%s/%s/", tmpdir, - "gnunet-testing-test-test", off); - } - - if (NULL != username) - GNUNET_asprintf (&arg, "%s@%s:%s", username, pg->hosts[off].hostname, - newservicehome); - else - GNUNET_asprintf (&arg, "%s:%s", pg->hosts[off].hostname, - newservicehome); - - /* FIXME: Doesn't support ssh_port option! */ - proc = - GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "rsync", "rsync", "-r", - newservicehome, arg, NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "copying directory with command rsync -r %s %s\n", - newservicehome, arg); - GNUNET_free (newservicehome); - GNUNET_free (arg); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ - ("Could not start `%s' process to copy configuration directory.\n"), - "scp"); - GNUNET_assert (0); - } - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_destroy (proc); - } - /* Now all the configuration files and hostkeys are copied to the remote host. Call the hostkey callback for each peer! */ - GNUNET_SCHEDULER_add_now (&call_hostkey_callbacks, pg); - } -#endif - return pg; -} - -/* - * Get a daemon by number, so callers don't have to do nasty - * offsetting operation. - */ -struct GNUNET_TESTING_Daemon * -GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, - unsigned int position) -{ - if (position < pg->total) - return pg->peers[position].daemon; - return NULL; -} - -/* - * Get a daemon by peer identity, so callers can - * retrieve the daemon without knowing it's offset. - * - * @param pg the peer group to retrieve the daemon from - * @param peer_id the peer identity of the daemon to retrieve - * - * @return the daemon on success, or NULL if no such peer identity is found - */ -struct GNUNET_TESTING_Daemon * -GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, - const struct GNUNET_PeerIdentity *peer_id) -{ - unsigned int i; - - for (i = 0; i < pg->total; i++) - { - if (0 == - memcmp (&pg->peers[i].daemon->id, peer_id, - sizeof (struct GNUNET_PeerIdentity))) - return pg->peers[i].daemon; - } - return NULL; -} - -/** - * Prototype of a function that will be called when a - * particular operation was completed the testing library. - * - * @param cls closure (a struct RestartContext) - * @param id id of the peer that was restarted - * @param cfg handle to the configuration of the peer - * @param d handle to the daemon that was restarted - * @param emsg NULL on success - */ -static void -restart_callback (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - struct RestartContext *restart_context = cls; - - if (emsg == NULL) - { - restart_context->peers_restarted++; - } - else - { - restart_context->peers_restart_failed++; - } - - if (restart_context->peers_restarted == restart_context->peer_group->total) - { - restart_context->callback (restart_context->callback_cls, NULL); - GNUNET_free (restart_context); - } - else if (restart_context->peers_restart_failed + - restart_context->peers_restarted == - restart_context->peer_group->total) - { - restart_context->callback (restart_context->callback_cls, - "Failed to restart peers!"); - GNUNET_free (restart_context); - } - -} - -/** - * Callback for informing us about a successful - * or unsuccessful churn stop call. - * - * @param cls a ChurnContext - * @param emsg NULL on success, non-NULL on failure - * - */ -static void -churn_stop_callback (void *cls, const char *emsg) -{ - struct ShutdownContext *shutdown_ctx = cls; - struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls; - unsigned int total_left; - char *error_message; - - error_message = NULL; - shutdown_ctx->outstanding--; - - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Churn stop callback failed with error `%s'\n", emsg); - churn_ctx->num_failed_stop++; - } - else - { - churn_ctx->num_to_stop--; - } - - total_left = - (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + - (churn_ctx->num_to_start - churn_ctx->num_failed_start); - - if (total_left == 0) - { - if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) - { - GNUNET_asprintf (&error_message, - "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", - churn_ctx->num_failed_start, churn_ctx->num_failed_stop); - } - churn_ctx->cb (churn_ctx->cb_cls, error_message); - GNUNET_free_non_null (error_message); - GNUNET_free (churn_ctx); - GNUNET_free (shutdown_ctx); - } -} - -/** - * Count the number of running peers. - * - * @param pg handle for the peer group - * - * @return the number of currently running peers in the peer group - */ -unsigned int -GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg) -{ - unsigned int i; - unsigned int running = 0; - - for (i = 0; i < pg->total; i++) - { - if (pg->peers[i].daemon->running == GNUNET_YES) - { - GNUNET_assert (running != -1); - running++; - } - } - return running; -} - -/** - * Task to rate limit the number of outstanding peer shutdown - * requests. This is necessary for making sure we don't do - * too many ssh connections at once, but is generally nicer - * to any system as well (graduated task starts, as opposed - * to calling gnunet-arm N times all at once). - */ -static void -schedule_churn_shutdown_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PeerShutdownContext *peer_shutdown_ctx = cls; - struct ShutdownContext *shutdown_ctx; - struct ChurnContext *churn_ctx; - - GNUNET_assert (peer_shutdown_ctx != NULL); - shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; - GNUNET_assert (shutdown_ctx != NULL); - churn_ctx = (struct ChurnContext *) shutdown_ctx->cb_cls; - if (shutdown_ctx->outstanding > churn_ctx->pg->max_concurrent_ssh) - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_churn_shutdown_task, - peer_shutdown_ctx); - else - { - shutdown_ctx->outstanding++; - if (churn_ctx->service != NULL) - GNUNET_TESTING_daemon_stop_service (peer_shutdown_ctx->daemon, - churn_ctx->service, - shutdown_ctx->timeout, - shutdown_ctx->cb, shutdown_ctx); - else - GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, - shutdown_ctx->timeout, shutdown_ctx->cb, - shutdown_ctx, GNUNET_NO, GNUNET_YES); - GNUNET_free (peer_shutdown_ctx); - } -} - - -/** - * Simulate churn by stopping some peers (and possibly - * re-starting others if churn is called multiple times). This - * function can only be used to create leave-join churn (peers "never" - * leave for good). First "voff" random peers that are currently - * online will be taken offline; then "von" random peers that are then - * offline will be put back online. No notifications will be - * generated for any of these operations except for the callback upon - * completion. - * - * @param pg handle for the peer group - * @param service the service to churn off/on, NULL to churn peer - * @param voff number of peers that should go offline - * @param von number of peers that should come back online; - * must be zero on first call (since "testbed_start" - * always starts all of the peers) - * @param timeout how long to wait for operations to finish before - * giving up - * @param cb function to call at the end - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, - char *service, unsigned int voff, - unsigned int von, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) -{ - struct ChurnContext *churn_ctx; - struct ShutdownContext *shutdown_ctx; - struct PeerShutdownContext *peer_shutdown_ctx; - struct PeerRestartContext *peer_restart_ctx; - struct ChurnRestartContext *churn_startup_ctx; - - unsigned int running; - unsigned int stopped; - unsigned int total_running; - unsigned int total_stopped; - unsigned int i; - unsigned int *running_arr; - unsigned int *stopped_arr; - unsigned int *running_permute; - unsigned int *stopped_permute; - char *pos; - - shutdown_ctx = NULL; - peer_shutdown_ctx = NULL; - peer_restart_ctx = NULL; - churn_startup_ctx = NULL; - - running = 0; - stopped = 0; - - if ((von == 0) && (voff == 0)) /* No peers at all? */ - { - cb (cb_cls, NULL); - return; - } - - for (i = 0; i < pg->total; i++) - { - if (service == NULL) - { - if (pg->peers[i].daemon->running == GNUNET_YES) - { - GNUNET_assert (running != -1); - running++; - } - else - { - GNUNET_assert (stopped != -1); - stopped++; - } - } - else - { - /* FIXME: make churned services a list! */ - pos = pg->peers[i].daemon->churned_services; - /* FIXME: while (pos != NULL) */ - if (pos != NULL) - { -#if FIXME - if (0 == strcasecmp (pos, service)) - { - - break; - } -#endif - GNUNET_assert (stopped != -1); - stopped++; - /* FIXME: pos = pos->next; */ - } - if (pos == NULL) - { - GNUNET_assert (running != -1); - running++; - } - } - } - - if (voff > running) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Trying to stop more peers (%d) than are currently running (%d)!\n", - voff, running); - cb (cb_cls, "Trying to stop more peers than are currently running!"); - return; - } - - if (von > stopped) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Trying to start more peers (%d) than are currently stopped (%d)!\n", - von, stopped); - cb (cb_cls, "Trying to start more peers than are currently stopped!"); - return; - } - - churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); - - if (service != NULL) - churn_ctx->service = GNUNET_strdup (service); - running_arr = NULL; - if (running > 0) - running_arr = GNUNET_malloc (running * sizeof (unsigned int)); - - stopped_arr = NULL; - if (stopped > 0) - stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int)); - - running_permute = NULL; - stopped_permute = NULL; - - if (running > 0) - running_permute = - GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, running); - if (stopped > 0) - stopped_permute = - GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, stopped); - - total_running = running; - total_stopped = stopped; - running = 0; - stopped = 0; - - churn_ctx->num_to_start = von; - churn_ctx->num_to_stop = voff; - churn_ctx->cb = cb; - churn_ctx->cb_cls = cb_cls; - churn_ctx->pg = pg; - - for (i = 0; i < pg->total; i++) - { - if (service == NULL) - { - if (pg->peers[i].daemon->running == GNUNET_YES) - { - GNUNET_assert ((running_arr != NULL) && (total_running > running)); - running_arr[running] = i; - running++; - } - else - { - GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); - stopped_arr[stopped] = i; - stopped++; - } - } - else - { - /* FIXME: make churned services a list! */ - pos = pg->peers[i].daemon->churned_services; - /* FIXME: while (pos != NULL) */ - if (pos != NULL) - { - GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); - stopped_arr[stopped] = i; - stopped++; - /* FIXME: pos = pos->next; */ - } - if (pos == NULL) - { - GNUNET_assert ((running_arr != NULL) && (total_running > running)); - running_arr[running] = i; - running++; - } - } - } - - GNUNET_assert (running >= voff); - if (voff > 0) - { - shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); - shutdown_ctx->cb = &churn_stop_callback; - shutdown_ctx->cb_cls = churn_ctx; - shutdown_ctx->total_peers = voff; - shutdown_ctx->timeout = timeout; - } - - for (i = 0; i < voff; i++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer %d!\n", - running_arr[running_permute[i]]); - GNUNET_assert (running_arr != NULL); - peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); - peer_shutdown_ctx->daemon = - pg->peers[running_arr[running_permute[i]]].daemon; - peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; - GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task, peer_shutdown_ctx); - } - - GNUNET_assert (stopped >= von); - if (von > 0) - { - churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); - churn_startup_ctx->churn_ctx = churn_ctx; - churn_startup_ctx->timeout = timeout; - churn_startup_ctx->pg = pg; - } - for (i = 0; i < von; i++) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting up peer %d!\n", - stopped_arr[stopped_permute[i]]); - GNUNET_assert (stopped_arr != NULL); - peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext)); - peer_restart_ctx->churn_restart_ctx = churn_startup_ctx; - peer_restart_ctx->daemon = - pg->peers[stopped_arr[stopped_permute[i]]].daemon; - GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx); - } - - GNUNET_free_non_null (running_arr); - GNUNET_free_non_null (stopped_arr); - GNUNET_free_non_null (running_permute); - GNUNET_free_non_null (stopped_permute); -} - -/* - * Start a given service for each of the peers in the peer group. - * - * @param pg handle for the peer group - * @param service the service to start - * @param timeout how long to wait for operations to finish before - * giving up - * @param cb function to call once finished - * @param cb_cls closure for cb - * - */ -void -GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg, - char *service, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls) -{ - struct ServiceStartContext *start_ctx; - struct PeerServiceStartContext *peer_start_ctx; - unsigned int i; - - GNUNET_assert (service != NULL); - - start_ctx = GNUNET_malloc (sizeof (struct ServiceStartContext)); - start_ctx->pg = pg; - start_ctx->remaining = pg->total; - start_ctx->cb = cb; - start_ctx->cb_cls = cb_cls; - start_ctx->service = GNUNET_strdup (service); - start_ctx->timeout = timeout; - - for (i = 0; i < pg->total; i++) - { - peer_start_ctx = GNUNET_malloc (sizeof (struct PeerServiceStartContext)); - peer_start_ctx->start_ctx = start_ctx; - peer_start_ctx->daemon = pg->peers[i].daemon; - GNUNET_SCHEDULER_add_now (&schedule_service_start, peer_start_ctx); - } -} - -/** - * Restart all peers in the given group. - * - * @param pg the handle to the peer group - * @param callback function to call on completion (or failure) - * @param callback_cls closure for the callback function - */ -void -GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_NotifyCompletion callback, - void *callback_cls) -{ - struct RestartContext *restart_context; - unsigned int off; - - if (pg->total > 0) - { - restart_context = GNUNET_malloc (sizeof (struct RestartContext)); - restart_context->peer_group = pg; - restart_context->peers_restarted = 0; - restart_context->callback = callback; - restart_context->callback_cls = callback_cls; - - for (off = 0; off < pg->total; off++) - { - GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, - restart_context); - } - } -} - - -/** - * Start or stop an individual peer from the given group. - * - * @param pg handle to the peer group - * @param offset which peer to start or stop - * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it - * @param timeout how long to wait for shutdown - * @param cb function to call at the end - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, - unsigned int offset, int desired_status, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) -{ - struct ShutdownContext *shutdown_ctx; - struct ChurnRestartContext *startup_ctx; - struct ChurnContext *churn_ctx; - - if (GNUNET_NO == desired_status) - { - if (NULL != pg->peers[offset].daemon) - { - shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); - churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); - churn_ctx->num_to_start = 0; - churn_ctx->num_to_stop = 1; - churn_ctx->cb = cb; - churn_ctx->cb_cls = cb_cls; - shutdown_ctx->cb_cls = churn_ctx; - GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon, timeout, - &churn_stop_callback, shutdown_ctx, GNUNET_NO, - GNUNET_YES); - } - } - else if (GNUNET_YES == desired_status) - { - if (NULL == pg->peers[offset].daemon) - { - startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); - churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); - churn_ctx->num_to_start = 1; - churn_ctx->num_to_stop = 0; - churn_ctx->cb = cb; - churn_ctx->cb_cls = cb_cls; - startup_ctx->churn_ctx = churn_ctx; - GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon, timeout, - &churn_start_callback, startup_ctx); - } - } - else - GNUNET_break (0); -} - - -/** - * Callback for shutting down peers in a peer group. - * - * @param cls closure (struct ShutdownContext) - * @param emsg NULL on success - */ -static void -internal_shutdown_callback (void *cls, const char *emsg) -{ - struct PeerShutdownContext *peer_shutdown_ctx = cls; - struct ShutdownContext *shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; - unsigned int off; - int i; - struct OutstandingSSH *ssh_pos; - - shutdown_ctx->outstanding--; - if (peer_shutdown_ctx->daemon->hostname != NULL) - decrement_outstanding_at_host (peer_shutdown_ctx->daemon->hostname, - shutdown_ctx->pg); - - if (emsg == NULL) - { - shutdown_ctx->peers_down++; - } - else - { - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "internal_shutdown_callback", - "Failed to stop a peer: %s\n", emsg); - shutdown_ctx->peers_failed++; - } - - if ((shutdown_ctx->cb != NULL) && - (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == - shutdown_ctx->total_peers)) - { - if (shutdown_ctx->peers_failed > 0) - shutdown_ctx->cb (shutdown_ctx->cb_cls, - "Not all peers successfully shut down!"); - else - shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL); - - for (i = 0; i < shutdown_ctx->pg->total; i++) - { - if (shutdown_ctx->pg->peers[i].startup_task != GNUNET_SCHEDULER_NO_TASK) - GNUNET_SCHEDULER_cancel (shutdown_ctx->pg->peers[i].startup_task); - } - GNUNET_free (shutdown_ctx->pg->peers); - GNUNET_free_non_null (shutdown_ctx->pg->hostkey_data); - for (off = 0; off < shutdown_ctx->pg->num_hosts; off++) - { - GNUNET_free (shutdown_ctx->pg->hosts[off].hostname); - GNUNET_free_non_null (shutdown_ctx->pg->hosts[off].username); - } - GNUNET_free_non_null (shutdown_ctx->pg->hosts); - while (NULL != (ssh_pos = shutdown_ctx->pg->ssh_head)) - { - GNUNET_CONTAINER_DLL_remove (shutdown_ctx->pg->ssh_head, - shutdown_ctx->pg->ssh_tail, ssh_pos); - GNUNET_free (ssh_pos); - } - GNUNET_free (shutdown_ctx->pg); - GNUNET_free (shutdown_ctx); - } - GNUNET_free (peer_shutdown_ctx); -} - - -/** - * Task to rate limit the number of outstanding peer shutdown - * requests. This is necessary for making sure we don't do - * too many ssh connections at once, but is generally nicer - * to any system as well (graduated task starts, as opposed - * to calling gnunet-arm N times all at once). - */ -static void -schedule_shutdown_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PeerShutdownContext *peer_shutdown_ctx = cls; - struct ShutdownContext *shutdown_ctx; - struct GNUNET_TESTING_Daemon *d; - - GNUNET_assert (peer_shutdown_ctx != NULL); - d = peer_shutdown_ctx->daemon; - shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; - GNUNET_assert (shutdown_ctx != NULL); - - if ((shutdown_ctx->outstanding < shutdown_ctx->pg->max_concurrent_ssh) || - ((d->hostname != NULL) && - (count_outstanding_at_host - (d->hostname, - shutdown_ctx->pg) < shutdown_ctx->pg->max_concurrent_ssh))) - { - if (d->hostname != NULL) - increment_outstanding_at_host (d->hostname, - shutdown_ctx->pg); - shutdown_ctx->outstanding++; - GNUNET_TESTING_daemon_stop (d, - shutdown_ctx->timeout, - &internal_shutdown_callback, peer_shutdown_ctx, - shutdown_ctx->delete_files, GNUNET_NO); - } - else - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - &schedule_shutdown_task, peer_shutdown_ctx); - -} - -/** - * Read a testing hosts file based on a configuration. - * Returns a DLL of hosts (caller must free!) on success - * or NULL on failure. - * - * @param cfg a configuration with a testing section - * - * @return DLL of hosts on success, NULL on failure - */ -struct GNUNET_TESTING_Host * -GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct GNUNET_TESTING_Host *hosts; - struct GNUNET_TESTING_Host *temphost; - char *data; - char *buf; - char *hostfile; - struct stat frstat; - int count; - int ret; - - /* Check for a hostfile containing user@host:port triples */ - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", - &hostfile)) - return NULL; - - hosts = NULL; - temphost = NULL; - data = NULL; - if (hostfile != NULL) - { - if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) - GNUNET_DISK_fn_write (hostfile, NULL, 0, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not open file specified for host list, ending test!"); - GNUNET_free (hostfile); - return NULL; - } - - data = GNUNET_malloc_large (frstat.st_size); - GNUNET_assert (data != NULL); - if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not read file %s specified for host list, ending test!", - hostfile); - GNUNET_free (hostfile); - GNUNET_free (data); - return NULL; - } - - GNUNET_free_non_null (hostfile); - - buf = data; - count = 0; - while (count < frstat.st_size - 1) - { - count++; - if (((data[count] == '\n')) && (buf != &data[count])) - { - data[count] = '\0'; - temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); - ret = - SSCANF (buf, "%a[a-zA-Z0-9_]@%a[a-zA-Z0-9.]:%hd", - &temphost->username, &temphost->hostname, &temphost->port); - if (3 == ret) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Successfully read host %s, port %d and user %s from file\n", - temphost->hostname, temphost->port, temphost->username); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Error reading line `%s' in hostfile\n", buf); - GNUNET_free (temphost); - buf = &data[count + 1]; - continue; - } - temphost->next = hosts; - hosts = temphost; - buf = &data[count + 1]; - } - else if ((data[count] == '\n') || (data[count] == '\0')) - buf = &data[count + 1]; - } - } - GNUNET_free_non_null (data); - - return hosts; -} - -/** - * Shutdown all peers started in the given group. - * - * @param pg handle to the peer group - * @param timeout how long to wait for shutdown - * @param cb callback to notify upon success or failure - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) -{ - unsigned int off; - struct ShutdownContext *shutdown_ctx; - struct PeerShutdownContext *peer_shutdown_ctx; - -#if OLD - struct PeerConnection *conn_iter; - struct PeerConnection *temp_conn; -#endif - struct ConnectContext *cc; - - GNUNET_assert (pg->total > 0); - while (NULL != (cc = pg->cc_head)) - { - GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, cc); - if (GNUNET_SCHEDULER_NO_TASK != cc->task) - GNUNET_SCHEDULER_cancel (cc->task); - if (NULL != cc->cc) - GNUNET_TESTING_daemons_connect_cancel (cc->cc); - GNUNET_free (cc); - } - - shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); - shutdown_ctx->delete_files = - GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "DELETE_FILES"); - shutdown_ctx->cb = cb; - shutdown_ctx->cb_cls = cb_cls; - shutdown_ctx->total_peers = pg->total; - shutdown_ctx->timeout = timeout; - shutdown_ctx->pg = pg; - - for (off = 0; off < pg->total; off++) - { - GNUNET_assert (NULL != pg->peers[off].daemon); - peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); - peer_shutdown_ctx->daemon = pg->peers[off].daemon; - peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; - GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx); - - if (NULL != pg->peers[off].cfg) - { - GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg); - pg->peers[off].cfg = NULL; - } -#if OLD -// FIXME Do DLL remove for all pg->peers[off].LIST - conn_iter = pg->peers[off].allowed_peers_head; - while (conn_iter != NULL) - { - temp_conn = conn_iter->next; - GNUNET_free (conn_iter); - conn_iter = temp_conn; - } - pg->peers[off].allowed_peers_head = NULL; - - conn_iter = pg->peers[off].connect_peers_head; - while (conn_iter != NULL) - { - temp_conn = conn_iter->next; - GNUNET_free (conn_iter); - conn_iter = temp_conn; - } - pg->peers[off].connect_peers_head = NULL; - - conn_iter = pg->peers[off].blacklisted_peers_head; - while (conn_iter != NULL) - { - temp_conn = conn_iter->next; - GNUNET_free (conn_iter); - conn_iter = temp_conn; - } - pg->peers[off].blacklisted_peers_head = NULL; - - conn_iter = pg->peers[off].connect_peers_working_set_head; - while (conn_iter != NULL) - { - temp_conn = conn_iter->next; - GNUNET_free (conn_iter); - conn_iter = temp_conn; - } - pg->peers[off].connect_peers_working_set_head = NULL; -#else - if (pg->peers[off].allowed_peers != NULL) - GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers); - if (pg->peers[off].connect_peers != NULL) - GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers); - if (pg->peers[off].blacklisted_peers != NULL) - GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].blacklisted_peers); -#endif - } -} - -/* end of testing_group.c */ diff --git a/src/testing/testing_peergroup.c b/src/testing/testing_peergroup.c deleted file mode 100644 index 87504ed6d..000000000 --- a/src/testing/testing_peergroup.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* - This file is part of GNUnet - (C) 2008-2011 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 testing/testing_peergroup.c - * @brief API implementation for easy peer group creation - * @author Nathan Evans - * @author Christian Grothoff - * - */ -#include "platform.h" -#include "gnunet_constants.h" -#include "gnunet_arm_service.h" -#include "gnunet_testing_lib.h" -#include "gnunet_core_service.h" -#include "gnunet_disk_lib.h" - -/** Globals **/ -#define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) - -#define DEFAULT_CONNECT_ATTEMPTS 2 - -/** Struct definitions **/ - -struct PeerGroupStartupContext -{ - struct GNUNET_TESTING_PeerGroup *pg; - const struct GNUNET_CONFIGURATION_Handle *cfg; - unsigned int total; - unsigned int peers_left; - unsigned long long max_concurrent_connections; - - /** - * Maximum attemps to connect two daemons. - */ - unsigned long long connect_attempts; - - /** - * How long to spend trying to establish all the connections? - */ - struct GNUNET_TIME_Relative connect_timeout; - - unsigned long long max_concurrent_ssh; - struct GNUNET_TIME_Absolute timeout; - GNUNET_TESTING_NotifyConnection connect_cb; - GNUNET_TESTING_NotifyCompletion peergroup_cb; - - /** - * Closure for all peergroup callbacks. - */ - void *cls; - - const struct GNUNET_TESTING_Host *hostnames; - - /** - * FIXME document - */ - enum GNUNET_TESTING_Topology topology; - - float topology_percentage; - - float topology_probability; - - /** - * FIXME document - */ - enum GNUNET_TESTING_Topology restrict_topology; - - /** - * FIXME document - */ - char *restrict_transports; - - /** - * Initial connections - */ - enum GNUNET_TESTING_Topology connect_topology; - enum GNUNET_TESTING_TopologyOption connect_topology_option; - double connect_topology_option_modifier; - int verbose; - - struct ProgressMeter *hostkey_meter; - struct ProgressMeter *peer_start_meter; - struct ProgressMeter *connect_meter; - - /** - * Task used to kill the peergroup. - */ - GNUNET_SCHEDULER_TaskIdentifier die_task; - - char *fail_reason; - - /** - * Variable used to store the number of connections we should wait for. - */ - unsigned int expected_connections; - - /** - * Time when the connecting peers was started. - */ - struct GNUNET_TIME_Absolute connect_start_time; - - /** - * The total number of connections that have been created so far. - */ - unsigned int total_connections; - - /** - * The total number of connections that have failed so far. - */ - unsigned int failed_connections; - - /** - * File handle to write out topology in dot format. - */ - struct GNUNET_DISK_FileHandle *topology_output_file; -}; - -struct TopologyOutputContext -{ - struct GNUNET_DISK_FileHandle *file; - GNUNET_TESTING_NotifyCompletion notify_cb; - void *notify_cb_cls; -}; - -/** - * Simple struct to keep track of progress, and print a - * percentage meter for long running tasks. - */ -struct ProgressMeter -{ - /** - * Total number of tasks to complete. - */ - unsigned int total; - - /** - * Print percentage done after modnum tasks. - */ - unsigned int modnum; - - /** - * Print a . each dotnum tasks. - */ - unsigned int dotnum; - - /** - * Total number completed thus far. - */ - unsigned int completed; - - /** - * Whether or not to print. - */ - int print; - - /** - * Startup string for progress meter. - */ - char *startup_string; -}; - - -/** Utility functions **/ - -/** - * Create a meter to keep track of the progress of some task. - * - * @param total the total number of items to complete - * @param start_string a string to prefix the meter with (if printing) - * @param print GNUNET_YES to print the meter, GNUNET_NO to count - * internally only - * - * @return the progress meter - */ -static struct ProgressMeter * -create_meter (unsigned int total, char *start_string, int print) -{ - struct ProgressMeter *ret; - - ret = GNUNET_malloc (sizeof (struct ProgressMeter)); - ret->print = print; - ret->total = total; - ret->modnum = (total / 4 == 0) ? 1 : (total / 4); - ret->dotnum = (total / 50) + 1; - if (start_string != NULL) - ret->startup_string = GNUNET_strdup (start_string); - else - ret->startup_string = GNUNET_strdup (""); - - return ret; -} - -/** - * Update progress meter (increment by one). - * - * @param meter the meter to update and print info for - * - * @return GNUNET_YES if called the total requested, - * GNUNET_NO if more items expected - */ -static int -update_meter (struct ProgressMeter *meter) -{ - if (meter->print == GNUNET_YES) - { - if (meter->completed % meter->modnum == 0) - { - if (meter->completed == 0) - { - FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); - } - else - FPRINTF (stdout, "%d%%", - (int) (((float) meter->completed / meter->total) * 100)); - } - else if (meter->completed % meter->dotnum == 0) - FPRINTF (stdout, "%s", "."); - - if (meter->completed + 1 == meter->total) - FPRINTF (stdout, "%d%%]\n", 100); - fflush (stdout); - } - meter->completed++; - - if (meter->completed == meter->total) - return GNUNET_YES; - return GNUNET_NO; -} - -/** - * Reset progress meter. - * - * @param meter the meter to reset - * - * @return GNUNET_YES if meter reset, - * GNUNET_SYSERR on error - */ -static int -reset_meter (struct ProgressMeter *meter) -{ - if (meter == NULL) - return GNUNET_SYSERR; - - meter->completed = 0; - return GNUNET_YES; -} - -/** - * Release resources for meter - * - * @param meter the meter to free - */ -static void -free_meter (struct ProgressMeter *meter) -{ - GNUNET_free_non_null (meter->startup_string); - GNUNET_free (meter); -} - - -/** Functions for creating, starting and connecting the peergroup **/ - -/** - * Check whether peers successfully shut down. - */ -static void -internal_shutdown_callback (void *cls, const char *emsg) -{ - struct PeerGroupStartupContext *pg_start_ctx = cls; - - if (emsg != NULL) - pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg); - else - pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason); -} - -/** - * Check if the get_handle is being used, if so stop the request. Either - * way, schedule the end_badly_cont function which actually shuts down the - * test. - */ -static void -end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct PeerGroupStartupContext *pg_start_ctx = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failing peer group startup with error: `%s'!\n", - pg_start_ctx->fail_reason); - - GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, - GNUNET_TIME_absolute_get_remaining - (pg_start_ctx->timeout), - &internal_shutdown_callback, pg_start_ctx); - - if (pg_start_ctx->hostkey_meter != NULL) - { - free_meter (pg_start_ctx->hostkey_meter); - pg_start_ctx->hostkey_meter = NULL; - } - if (pg_start_ctx->peer_start_meter != NULL) - { - free_meter (pg_start_ctx->peer_start_meter); - pg_start_ctx->peer_start_meter = NULL; - } - if (pg_start_ctx->connect_meter != NULL) - { - free_meter (pg_start_ctx->connect_meter); - pg_start_ctx->connect_meter = NULL; - } -} - -/** - * This function is called whenever a connection attempt is finished between two of - * the started peers (started with GNUNET_TESTING_daemons_start). The total - * number of times this function is called should equal the number returned - * from the GNUNET_TESTING_connect_topology call. - * - * The emsg variable is NULL on success (peers connected), and non-NULL on - * failure (peers failed to connect). - */ -static void -internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, - uint32_t distance, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle - *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg) -{ - struct PeerGroupStartupContext *pg_start_ctx = cls; - char *temp_str; - char *second_str; - int temp; - -#if TIMING - unsigned long long duration; - unsigned long long total_duration; - unsigned int new_connections; - unsigned int new_failed_connections; - double conns_per_sec_recent; - double conns_per_sec_total; - double failed_conns_per_sec_recent; - double failed_conns_per_sec_total; -#endif - -#if TIMING - if (GNUNET_TIME_absolute_get_difference - (connect_last_time, - GNUNET_TIME_absolute_get ()).rel_value > - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, - CONN_UPDATE_DURATION).rel_value) - { - /* Get number of new connections */ - new_connections = total_connections - previous_connections; - - /* Get number of new FAILED connections */ - new_failed_connections = failed_connections - previous_failed_connections; - - /* Get duration in seconds */ - duration = - GNUNET_TIME_absolute_get_difference (connect_last_time, - GNUNET_TIME_absolute_get - ()).rel_value / 1000; - total_duration = - GNUNET_TIME_absolute_get_difference (connect_start_time, - GNUNET_TIME_absolute_get - ()).rel_value / 1000; - - failed_conns_per_sec_recent = (double) new_failed_connections / duration; - failed_conns_per_sec_total = (double) failed_connections / total_duration; - conns_per_sec_recent = (double) new_connections / duration; - conns_per_sec_total = (double) total_connections / total_duration; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n", - conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total, - failed_conns_per_sec_recent, failed_conns_per_sec_total); - connect_last_time = GNUNET_TIME_absolute_get (); - previous_connections = total_connections; - previous_failed_connections = failed_connections; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "have %u total_connections, %u failed\n", total_connections, - failed_connections); - } -#endif - - - if (emsg == NULL) - { - pg_start_ctx->total_connections++; -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "connected peer %s to peer %s, distance %u\n", - first_daemon->shortname, second_daemon->shortname, distance); -#endif - if (pg_start_ctx->topology_output_file != NULL) - { - second_str = GNUNET_strdup (GNUNET_i2s (second)); - temp = - GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", - GNUNET_i2s (first), second_str); - GNUNET_free (second_str); - if (temp > 0) - GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, - temp); - GNUNET_free (temp_str); - } - } - else - { - pg_start_ctx->failed_connections++; -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to connect peer %s to peer %s with error :\n%s\n", - first_daemon->shortname, second_daemon->shortname, emsg); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to connect peer %s to peer %s with error :\n%s\n", - first_daemon->shortname, second_daemon->shortname, emsg); -#endif - } - - GNUNET_assert (pg_start_ctx->connect_meter != NULL); - if (pg_start_ctx->connect_cb != NULL) - pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance, - first_cfg, second_cfg, first_daemon, - second_daemon, emsg); - if (GNUNET_YES != update_meter (pg_start_ctx->connect_meter)) - { - /* No finished yet */ - return; - } -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Created %d total connections, which is our target number! Starting next phase of testing.\n", - pg_start_ctx->total_connections); -#endif - -#if TIMING - total_duration = - GNUNET_TIME_absolute_get_difference (connect_start_time, - GNUNET_TIME_absolute_get - ()).rel_value / 1000; - failed_conns_per_sec_total = (double) failed_connections / total_duration; - conns_per_sec_total = (double) total_connections / total_duration; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Overall connection info --- Total: %u, Total Failed %u/s\n", - total_connections, failed_connections); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n", - conns_per_sec_total, failed_conns_per_sec_total); -#endif - - GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); - GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); - - /* Call final callback, signifying that the peer group has been started and connected */ - if (pg_start_ctx->peergroup_cb != NULL) - pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL); - - if (pg_start_ctx->topology_output_file != NULL) - { - temp = GNUNET_asprintf (&temp_str, "}\n"); - if (temp > 0) - GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, - temp); - GNUNET_free (temp_str); - GNUNET_DISK_file_close (pg_start_ctx->topology_output_file); - } - GNUNET_free_non_null (pg_start_ctx->fail_reason); - if (NULL != pg_start_ctx->hostkey_meter) - free_meter(pg_start_ctx->hostkey_meter); - if (NULL != pg_start_ctx->peer_start_meter) - free_meter(pg_start_ctx->peer_start_meter); - if (NULL != pg_start_ctx->connect_meter) - free_meter(pg_start_ctx->connect_meter); - GNUNET_free (pg_start_ctx); -} - - -/** - * Callback called for each started daemon. - * - * @param cls Clause (PG Context). - * @param id PeerIdentidy of started daemon. - * @param cfg Configuration used by the daemon. - * @param d Handle for the daemon. - * @param emsg Error message, NULL on success. - */ -static void -internal_peers_started_callback (void *cls, - const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, - const char *emsg) -{ - struct PeerGroupStartupContext *pg_start_ctx = cls; - - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Failed to start daemon with error: `%s'\n", emsg); - return; - } - GNUNET_assert (id != NULL); - -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", - (pg_start_ctx->total - pg_start_ctx->peers_left) + 1, - pg_start_ctx->total); -#endif - - pg_start_ctx->peers_left--; - - if (NULL == pg_start_ctx->peer_start_meter) - { - /* Cancelled Ctrl-C or error */ - return; - } - if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter)) - { -#if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "All %d daemons started, now connecting peers!\n", - pg_start_ctx->total); -#endif - GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); - GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); - - pg_start_ctx->expected_connections = UINT_MAX; - // FIXME: why whould peers_left be != 0?? Or pg NULL? - if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0)) - { - pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get (); - pg_start_ctx->expected_connections = - GNUNET_TESTING_connect_topology (pg_start_ctx->pg, - pg_start_ctx->connect_topology, - pg_start_ctx->connect_topology_option, - pg_start_ctx->connect_topology_option_modifier, - pg_start_ctx->connect_timeout, - pg_start_ctx->connect_attempts, NULL, - NULL); - - pg_start_ctx->connect_meter = - create_meter (pg_start_ctx->expected_connections, "Peer connection ", - pg_start_ctx->verbose); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", - pg_start_ctx->expected_connections); - } - - if (pg_start_ctx->expected_connections == 0) - { - GNUNET_free_non_null (pg_start_ctx->fail_reason); - pg_start_ctx->fail_reason = - GNUNET_strdup ("from connect topology (bad return)"); - pg_start_ctx->die_task = - GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); - return; - } - - GNUNET_free_non_null (pg_start_ctx->fail_reason); - pg_start_ctx->fail_reason = - GNUNET_strdup ("from connect topology (timeout)"); - pg_start_ctx->die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining - (pg_start_ctx->timeout), &end_badly, - pg_start_ctx); - } -} - -/** - * Callback indicating that the hostkey was created for a peer. - * - * @param cls NULL - * @param id the peer identity - * @param d the daemon handle (pretty useless at this point, remove?) - * @param emsg non-null on failure - */ -static void -internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, - struct GNUNET_TESTING_Daemon *d, const char *emsg) -{ - struct PeerGroupStartupContext *pg_start_ctx = cls; - unsigned int create_expected_connections; - - if (emsg != NULL) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Hostkey callback received error: %s\n", emsg); - } - -#if VERBOSE > 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Hostkey (%d/%d) created for peer `%s'\n", - pg_start_ctx->total - pg_start_ctx->peers_left + 1, - pg_start_ctx->total, GNUNET_i2s (id)); -#endif - - pg_start_ctx->peers_left--; - if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter)) - { - GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); - GNUNET_free_non_null (pg_start_ctx->fail_reason); - /* Set up task in case topology creation doesn't finish - * within a reasonable amount of time */ - pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology"); - pg_start_ctx->die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining - (pg_start_ctx->timeout), &end_badly, - pg_start_ctx); - pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */ - create_expected_connections = - GNUNET_TESTING_create_topology (pg_start_ctx->pg, - pg_start_ctx->topology, - pg_start_ctx->restrict_topology, - pg_start_ctx->restrict_transports); - if (create_expected_connections > 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Topology set up, have %u expected connections, now starting peers!\n", - create_expected_connections); - GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg); - } - else - { - GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); - GNUNET_free_non_null (pg_start_ctx->fail_reason); - pg_start_ctx->fail_reason = - GNUNET_strdup ("from create topology (bad return)"); - pg_start_ctx->die_task = - GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); - return; - } - - GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); - GNUNET_free_non_null (pg_start_ctx->fail_reason); - pg_start_ctx->fail_reason = - GNUNET_strdup ("from continue startup (timeout)"); - pg_start_ctx->die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining - (pg_start_ctx->timeout), &end_badly, - pg_start_ctx); - } -} - - -/** - * Prototype of a callback function indicating that two peers - * are currently connected. - * - * @param cls closure - * @param first peer id for first daemon - * @param second peer id for the second daemon - * @param emsg error message (NULL on success) - */ -void -write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, const char *emsg) -{ - struct TopologyOutputContext *topo_ctx; - int temp; - char *temp_str; - char *temp_pid2; - - topo_ctx = (struct TopologyOutputContext *) cls; - GNUNET_assert (topo_ctx->file != NULL); - if ((emsg == NULL) && (first != NULL) && (second != NULL)) - { - GNUNET_assert (first != NULL); - GNUNET_assert (second != NULL); - temp_pid2 = GNUNET_strdup (GNUNET_i2s (second)); - temp = - GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first), - temp_pid2); - GNUNET_free (temp_pid2); - GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); - } - else if ((emsg == NULL) && (first == NULL) && (second == NULL)) - { - temp = GNUNET_asprintf (&temp_str, "}\n"); - GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); - GNUNET_DISK_file_close (topo_ctx->file); - topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL); - GNUNET_free (topo_ctx); - } - else - { - temp = GNUNET_asprintf (&temp_str, "}\n"); - GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); - GNUNET_DISK_file_close (topo_ctx->file); - topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg); - GNUNET_free (topo_ctx); - } -} - -/** - * Print current topology to a graphviz readable file. - * - * @param pg a currently running peergroup to print to file - * @param output_filename the file to write the topology to - * @param notify_cb callback to call upon completion or failure - * @param notify_cb_cls closure for notify_cb - * - */ -void -GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg, - const char *output_filename, - GNUNET_TESTING_NotifyCompletion - notify_cb, void *notify_cb_cls) -{ - struct TopologyOutputContext *topo_ctx; - int temp; - char *temp_str; - - topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext)); - - topo_ctx->notify_cb = notify_cb; - topo_ctx->notify_cb_cls = notify_cb_cls; - topo_ctx->file = - GNUNET_DISK_file_open (output_filename, - GNUNET_DISK_OPEN_READWRITE | - GNUNET_DISK_OPEN_CREATE, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - if (topo_ctx->file == NULL) - { - notify_cb (notify_cb_cls, "Failed to open output file!"); - GNUNET_free (topo_ctx); - return; - } - - temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); - if (temp > 0) - GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); - GNUNET_free_non_null (temp_str); - GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx); -} - -/** - * Start a peer group with a given number of peers. Notify - * on completion of peer startup and connection based on given - * topological constraints. Optionally notify on each - * established connection. - * - * @param cfg configuration template to use - * @param total number of daemons to start - * @param timeout total time allowed for peers to start - * @param connect_cb function to call each time two daemons are connected - * @param peergroup_cb function to call once all peers are up and connected - * @param peergroup_cls closure for peergroup callbacks - * @param hostnames linked list of host structs to use to start peers on - * (NULL to run on localhost only) - * - * @return NULL on error, otherwise handle to control peer group - */ -struct GNUNET_TESTING_PeerGroup * -GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - unsigned int total, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyConnection connect_cb, - GNUNET_TESTING_NotifyCompletion peergroup_cb, - void *peergroup_cls, - const struct GNUNET_TESTING_Host *hostnames) -{ - struct PeerGroupStartupContext *pg_start_ctx; - char *temp_str; - int temp; - struct GNUNET_TIME_Relative rtimeout; - - GNUNET_assert (total > 0); - GNUNET_assert (cfg != NULL); - - pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext)); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", - &pg_start_ctx->connect_attempts)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "connect_attempts"); - GNUNET_free (pg_start_ctx); - return NULL; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", - &pg_start_ctx->connect_timeout)) - { - pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", - "max_outstanding_connections", - &pg_start_ctx->max_concurrent_connections)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "max_outstanding_connections"); - GNUNET_free (pg_start_ctx); - return NULL; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "testing", - "max_concurrent_ssh", - &pg_start_ctx->max_concurrent_ssh)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "max_concurrent_ssh"); - GNUNET_free (pg_start_ctx); - return NULL; - } - - if (GNUNET_SYSERR == - (pg_start_ctx->verbose = - GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing", - "use_progressbars"))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "use_progressbars"); - GNUNET_free (pg_start_ctx); - return NULL; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "PEERGROUP_TIMEOUT", - &rtimeout)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", - "testing", "PEERGROUP_TIMEOUT"); - GNUNET_free (pg_start_ctx); - return NULL; - } - pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout); - - - /* Read topology related options from the configuration file */ - temp_str = NULL; - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", - &temp_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid topology `%s' given for section %s option %s\n", - temp_str, "TESTING", "TOPOLOGY"); - pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ - } - GNUNET_free_non_null (temp_str); - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "topology_output_file", &temp_str)) - { - pg_start_ctx->topology_output_file = - GNUNET_DISK_file_open (temp_str, - GNUNET_DISK_OPEN_READWRITE | - GNUNET_DISK_OPEN_CREATE, - GNUNET_DISK_PERM_USER_READ | - GNUNET_DISK_PERM_USER_WRITE); - if (pg_start_ctx->topology_output_file != NULL) - { - GNUNET_free (temp_str); - temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); - if (temp > 0) - GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, - temp); - } - GNUNET_free (temp_str); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage", - &temp_str)) - pg_start_ctx->topology_percentage = 0.5; - else - { - pg_start_ctx->topology_percentage = atof (temp_str); - GNUNET_free (temp_str); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability", - &temp_str)) - pg_start_ctx->topology_probability = 0.5; - else - { - pg_start_ctx->topology_probability = atof (temp_str); - GNUNET_free (temp_str); - } - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology", &temp_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid connect topology `%s' given for section %s option %s\n", - temp_str, "TESTING", "CONNECT_TOPOLOGY"); - } - GNUNET_free_non_null (temp_str); - - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology_option", - &temp_str)) && - (GNUNET_NO == - GNUNET_TESTING_topology_option_get - (&pg_start_ctx->connect_topology_option, temp_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid connect topology option `%s' given for section %s option %s\n", - temp_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); - pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ - } - GNUNET_free_non_null (temp_str); - - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "connect_topology_option_modifier", - &temp_str)) - { - if (SSCANF - (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), - temp_str, "connect_topology_option_modifier", "TESTING"); - GNUNET_free (temp_str); - GNUNET_free (pg_start_ctx); - return NULL; - } - GNUNET_free (temp_str); - } - - if (GNUNET_YES != - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "blacklist_transports", - &pg_start_ctx->restrict_transports)) - pg_start_ctx->restrict_transports = NULL; - - pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE; - if ((GNUNET_YES == - GNUNET_CONFIGURATION_get_value_string (cfg, "testing", - "blacklist_topology", &temp_str)) - && (GNUNET_NO == - GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology, - temp_str))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid topology `%s' given for section %s option %s\n", - temp_str, "TESTING", "BLACKLIST_TOPOLOGY"); - } - - GNUNET_free_non_null (temp_str); - - pg_start_ctx->cfg = cfg; - pg_start_ctx->total = total; - pg_start_ctx->peers_left = total; - pg_start_ctx->connect_cb = connect_cb; - pg_start_ctx->peergroup_cb = peergroup_cb; - pg_start_ctx->cls = peergroup_cls; - pg_start_ctx->hostnames = hostnames; - pg_start_ctx->hostkey_meter = - create_meter (pg_start_ctx->peers_left, "Hostkeys created ", - pg_start_ctx->verbose); - pg_start_ctx->peer_start_meter = - create_meter (pg_start_ctx->peers_left, "Peers started ", - pg_start_ctx->verbose); - /* Make compilers happy */ - reset_meter (pg_start_ctx->peer_start_meter); - pg_start_ctx->fail_reason = - GNUNET_strdup - ("didn't generate all hostkeys within allowed startup time!"); - pg_start_ctx->die_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining - (pg_start_ctx->timeout), &end_badly, - pg_start_ctx); - - pg_start_ctx->pg = - GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left, - pg_start_ctx->max_concurrent_connections, - pg_start_ctx->max_concurrent_ssh, - GNUNET_TIME_absolute_get_remaining - (pg_start_ctx->timeout), - &internal_hostkey_callback, pg_start_ctx, - &internal_peers_started_callback, - pg_start_ctx, &internal_topology_callback, - pg_start_ctx, pg_start_ctx->hostnames); - - return pg_start_ctx->pg; -} - -/* end of testing_peergroup.c */ diff --git a/src/testing_old/Makefile.am b/src/testing_old/Makefile.am new file mode 100644 index 000000000..298483189 --- /dev/null +++ b/src/testing_old/Makefile.am @@ -0,0 +1,283 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + testing_old.conf + +if HAVE_EXPENSIVE_TESTS + EXPENSIVE_TESTS = \ + test_testing_topology_stability \ + test_testing_topology_clique_random \ + test_testing_topology_clique_minimum \ + test_testing_topology_clique_dfs \ + test_testing_topology_churn \ + test_testing_topology_line \ + test_testing_topology_blacklist \ + test_testing_group_remote \ + test_testing_topology_ring \ + test_testing_topology_2d_torus \ + test_testing_topology_small_world_ring \ + test_testing_topology_small_world_torus \ + test_testing_topology_erdos_renyi \ + test_testing_topology_internat \ + test_testing_topology_scale_free +endif + +lib_LTLIBRARIES = \ + libgnunettestingold.la + +libgnunettestingold_la_SOURCES = \ + helper.c \ + testing.c \ + testing_group.c \ + testing_peergroup.c +libgnunettestingold_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 \ + $(LTLIBINTL) +libgnunettestingold_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 0:1:0 + + +bin_PROGRAMS = \ + gnunet-testing + +check_PROGRAMS = \ + test_testing \ + test_testing_connect \ + test_testing_reconnect \ + test_testing_group \ + test_testing_peergroup \ + test_testing_topology_stability \ + test_testing_topology_clique \ + test_testing_topology_clique_random \ + test_testing_topology_clique_minimum \ + test_testing_topology_clique_dfs \ + test_testing_topology_churn \ + test_testing_topology_line \ + test_testing_topology_blacklist \ + test_testing_group_remote \ + test_testing_2dtorus \ + test_testing_topology_ring \ + test_testing_topology_2d_torus \ + test_testing_topology_small_world_ring \ + test_testing_topology_small_world_torus \ + test_testing_topology_erdos_renyi \ + test_testing_topology_internat \ + test_testing_topology_none \ + test_testing_topology_scale_free + +if ENABLE_TEST_RUN +TESTS = \ + test_testing \ + test_testing_connect \ + test_testing_reconnect \ + test_testing_group \ + test_testing_peergroup \ + test_testing_new_portreservation \ + test_testing_new_peerstartup \ + test_testing_new_servicestartup +endif + +gnunet_testing_SOURCES = \ + gnunet-testing.c +gnunet_testing_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +gnunet_testing_DEPENDENCIES = \ + libgnunettestingold.la + + +test_testing_SOURCES = \ + test_testing.c +test_testing_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_connect_SOURCES = \ + test_testing_connect.c +test_testing_connect_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_reconnect_SOURCES = \ + test_testing_reconnect.c +test_testing_reconnect_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_group_SOURCES = \ + test_testing_group.c +test_testing_group_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_peergroup_SOURCES = \ + test_testing_peergroup.c +test_testing_peergroup_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_stability_SOURCES = \ + test_testing_topology.c +test_testing_topology_stability_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_blacklist_SOURCES = \ + test_testing_topology_blacklist.c +test_testing_topology_blacklist_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_churn_SOURCES = \ + test_testing_topology_churn.c +test_testing_topology_churn_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_random_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_random_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_minimum_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_minimum_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_clique_dfs_SOURCES = \ + test_testing_topology.c +test_testing_topology_clique_dfs_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_line_SOURCES = \ + test_testing_topology.c +test_testing_topology_line_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + + +test_testing_group_remote_SOURCES = \ + test_testing_group_remote.c +test_testing_group_remote_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_2dtorus_SOURCES = \ + test_testing_2dtorus.c +test_testing_2dtorus_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_ring_SOURCES = \ + test_testing_topology.c +test_testing_topology_ring_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_2d_torus_SOURCES = \ + test_testing_topology.c +test_testing_topology_2d_torus_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_small_world_ring_SOURCES = \ + test_testing_topology.c +test_testing_topology_small_world_ring_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_small_world_torus_SOURCES = \ + test_testing_topology.c +test_testing_topology_small_world_torus_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_internat_SOURCES = \ + test_testing_topology.c +test_testing_topology_internat_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_erdos_renyi_SOURCES = \ + test_testing_topology.c +test_testing_topology_erdos_renyi_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_scale_free_SOURCES = \ + test_testing_topology.c +test_testing_topology_scale_free_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + +test_testing_topology_none_SOURCES = \ + test_testing_topology.c +test_testing_topology_none_LDADD = \ + $(top_builddir)/src/testing_old/libgnunettestingold.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(top_builddir)/src/util/libgnunetutil.la + + +EXTRA_DIST = \ + test_testing_defaults.conf \ + test_testing_data.conf \ + test_testing_connect_peer1.conf \ + test_testing_connect_peer2.conf \ + test_testing_2dtorus.conf \ + test_testing_data_topology_clique.conf \ + test_testing_data_topology_clique_random.conf \ + test_testing_data_topology_clique_minimum.conf \ + test_testing_data_topology_clique_dfs.conf \ + test_testing_data_topology_ring.conf \ + test_testing_data_topology_2d_torus.conf \ + test_testing_data_topology_small_world_ring.conf \ + test_testing_data_topology_small_world_torus.conf \ + test_testing_data_topology_erdos_renyi.conf \ + test_testing_data_topology_internat.conf \ + test_testing_data_topology_scale_free.conf \ + test_testing_data_topology_blacklist.conf \ + test_testing_data_topology_churn.conf \ + test_testing_data_topology_none.conf \ + test_testing_data_remote.conf \ + test_testing_data_topology_stability.conf \ + test_testing_peergroup_data.conf diff --git a/src/testing_old/gnunet-testing-remote-peer-start.pl b/src/testing_old/gnunet-testing-remote-peer-start.pl new file mode 100755 index 000000000..e4f72e9d0 --- /dev/null +++ b/src/testing_old/gnunet-testing-remote-peer-start.pl @@ -0,0 +1,92 @@ +# +# This file is part of GNUnet +# (C) 2008, 2009 Christian Grothoff (and other contributing authors) +# +# GNUnet is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published +# by the Free Software Foundation; either version 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 contrib/peerStartHelper.pl +# @brief Helper process for starting gnunet-testing peers. +# @author Nathan Evans +# +# Finds configuration files (or any files) of the format +# /path/*/gnunet-testing-config* and runs gnunet-arm with +# each as the given configuration. +# +# usage: peerStartHelper.pl /path/to/testing_dir/ +#!/usr/bin/perl +use strict; + +my $max_outstanding = 300; + +$ARGV[0] || die "No directory provided for peer information, exiting!\n"; + +my $directory = $ARGV[0]; +my @config_files = `find $directory -iname gnunet-testing-config*`; +my @child_arr = {}; +my $count = 0; +my $outstanding = 0; +foreach my $file (@config_files) +{ + chomp($file); + #print "Starting GNUnet peer with config file $file\n"; + my $pid = fork(); + if ($pid == -1) + { + die; + } + elsif ($pid == 0) + { + exec "gnunet-arm -q -c $file -s" or die; + } + + if ($pid != 0) + { + push @child_arr, $pid; + $count++; + $outstanding++; + if ($outstanding > $max_outstanding) + { + for (my $i = 0; $i < $max_outstanding / 5; $i++) + { + #print "Too many outstanding peers, waiting!\n"; + waitpid($child_arr[0], 0); + shift(@child_arr); + $outstanding--; + } + } + } +} + +print "All $count peers started (waiting for them to finish!\n"; + +while ($outstanding > 0) +{ + waitpid($child_arr[0], 0); + shift(@child_arr); + $outstanding--; + if ($outstanding % 50 == 0) + { + print "All $count peers started (waiting for $outstanding to finish!\n"; + } +} + +while (wait() != -1) {sleep 1} + +print "All $count peers started!\n"; + + diff --git a/src/testing_old/gnunet-testing.c b/src/testing_old/gnunet-testing.c new file mode 100644 index 000000000..bdbb5e8c5 --- /dev/null +++ b/src/testing_old/gnunet-testing.c @@ -0,0 +1,291 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/gnunet-testing.c + * @brief tool to use testing functionality from cmd line + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_program_lib.h" +#include "gnunet_testing_lib.h" + +#define HOSTKEYFILESIZE 914 + +/** + * Final status code. + */ +static int ret; + +static unsigned int create_hostkey; + +static unsigned int create_cfg; + +static int create_no; + +static char * create_cfg_template; + +static char * create_hostkey_file; + +static int +create_unique_cfgs (const char * template, const unsigned int no) +{ + int fail = GNUNET_NO; + + uint16_t port = 20000; + uint32_t upnum = 1; + uint32_t fdnum = 1; + + if (GNUNET_NO == GNUNET_DISK_file_test(template)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Configuration template `%s': file not found\n", create_cfg_template); + return 1; + } + + int cur = 0; + char * cur_file; + char *service_home = NULL; + char *cur_service_home = NULL; + + struct GNUNET_CONFIGURATION_Handle *cfg_new = NULL; + struct GNUNET_CONFIGURATION_Handle *cfg_tmpl = GNUNET_CONFIGURATION_create(); + + /* load template */ + if ((create_cfg_template != NULL) && (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, create_cfg_template))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load template `%s'\n", create_cfg_template); + GNUNET_CONFIGURATION_destroy(cfg_tmpl); + + return 1; + } + /* load defaults */ + else if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, NULL)) + { + GNUNET_break (0); + return 1; + } + + if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg_tmpl, "PATHS", "SERVICEHOME", &service_home)) + { + GNUNET_asprintf(&service_home, "%s", "/tmp/testing"); + } + else + { + int s = strlen (service_home); + if (service_home[s-1] == DIR_SEPARATOR) + service_home[s-1] = '\0'; + } + + while (cur < no) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating configuration no. %u \n", cur); + if (create_cfg_template != NULL) + GNUNET_asprintf (&cur_file,"%04u-%s",cur, create_cfg_template); + else + GNUNET_asprintf (&cur_file,"%04u%s",cur, ".conf"); + + + GNUNET_asprintf (&cur_service_home, "%s-%04u%c",service_home, cur, DIR_SEPARATOR); + GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","SERVICEHOME", cur_service_home); + GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","DEFAULTCONFIG", cur_file); + GNUNET_free (cur_service_home); + + cfg_new = GNUNET_TESTING_create_cfg(cfg_tmpl, cur, &port, &upnum, NULL, &fdnum); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing configuration no. %u to file `%s' \n", cur, cur_file); + if (GNUNET_OK != GNUNET_CONFIGURATION_write(cfg_new, cur_file)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write configuration no. %u \n", cur); + fail = GNUNET_YES; + } + + GNUNET_CONFIGURATION_destroy (cfg_new); + GNUNET_free (cur_file); + if (fail == GNUNET_YES) + break; + cur ++; + } + + GNUNET_CONFIGURATION_destroy(cfg_tmpl); + GNUNET_free (service_home); + if (fail == GNUNET_NO) + return 0; + else + return 1; +} + +static int +create_hostkeys (const unsigned int no) +{ + struct GNUNET_DISK_FileHandle *fd; + int cur = 0; + uint64_t fs; + uint64_t total_hostkeys; + char *hostkey_data; + char *hostkey_src_file; + char *hostkey_dest_file; + + /* prepare hostkeys */ + if (create_hostkey_file == NULL) + hostkey_src_file = "../../contrib/testing_hostkeys.dat"; + else + { + hostkey_src_file = create_hostkey_file; + } + + if (GNUNET_YES != GNUNET_DISK_file_test (hostkey_src_file)) + { + if (create_hostkey_file == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file, specify hostkey file with -H!\n")); + else + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Specified hostkey file `%s' not found!\n"), create_hostkey_file); + return 1; + } + else + { + /* Check hostkey file size, read entire thing into memory */ + fd = GNUNET_DISK_file_open (hostkey_src_file, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fd) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkey_src_file); + return 1; + } + + if (GNUNET_OK != GNUNET_DISK_file_size (hostkey_src_file, &fs, GNUNET_YES, GNUNET_YES)) + fs = 0; + + if (0 != (fs % HOSTKEYFILESIZE)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "File size %llu seems incorrect for hostkeys...\n", fs); + } + else + { + total_hostkeys = fs / HOSTKEYFILESIZE; + hostkey_data = GNUNET_malloc_large (fs); + GNUNET_assert (fs == GNUNET_DISK_file_read (fd, hostkey_data, fs)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Read %llu hostkeys from file\n", total_hostkeys); + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + } + + while (cur < no) + { + GNUNET_asprintf (&hostkey_dest_file, "%04u-hostkey",cur); + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_directory_create_for_file (hostkey_dest_file)); + fd = GNUNET_DISK_file_open (hostkey_dest_file, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_assert (fd != NULL); + GNUNET_assert (HOSTKEYFILESIZE == + GNUNET_DISK_file_write (fd, &hostkey_data[cur * HOSTKEYFILESIZE], HOSTKEYFILESIZE)); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", + "Wrote hostkey to file: `%s' \n", hostkey_dest_file); + GNUNET_free (hostkey_dest_file); + cur ++; + } + + GNUNET_free (hostkey_data); + + return 0; +} + +/** + * 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 cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + /* main code here */ + if (create_cfg == GNUNET_YES) + { + if (create_no > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u configuration files based on template `%s'\n", create_no, create_cfg_template); + ret = create_unique_cfgs (create_cfg_template, create_no); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); + ret = 1; + } + } + + if (create_hostkey == GNUNET_YES) + { + if (create_no > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u hostkeys \n", create_no); + ret = create_hostkeys (create_no); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); + ret = 1; + } + } + + GNUNET_free_non_null (create_cfg_template); +} + + +/** + * The main function. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + {'C', "cfg", NULL, gettext_noop ("create unique configuration files"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &create_cfg}, + {'k', "key", NULL, gettext_noop ("create hostkey files from pre-computed hostkey list"), + GNUNET_NO, &GNUNET_GETOPT_set_one, &create_hostkey}, + {'H', "hostkeys", NULL, gettext_noop ("host key file"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &create_hostkey_file}, + {'n', "number", NULL, gettext_noop ("number of unique configuration files or hostkeys to create"), + GNUNET_YES, &GNUNET_GETOPT_set_uint, &create_no}, + {'t', "template", NULL, gettext_noop ("configuration template"), + GNUNET_YES, &GNUNET_GETOPT_set_string, &create_cfg_template}, + GNUNET_GETOPT_OPTION_END + }; + return (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-testing", + gettext_noop ("Command line tool to access the testing library"), options, &run, + NULL)) ? ret : 1; +} + +/* end of gnunet-testing.c */ diff --git a/src/testing_old/helper.c b/src/testing_old/helper.c new file mode 100644 index 000000000..ebb37ebe5 --- /dev/null +++ b/src/testing_old/helper.c @@ -0,0 +1,75 @@ +/* + 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 testing/helper.c + * @brief helper functions for testing + * @author Christian Grothoff + * + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + + + + +/** + * Obtain the peer identity of the peer with the given configuration + * handle. This function reads the private key of the peer, obtains + * the public key and hashes it. + * + * @param cfg configuration of the peer + * @param pid where to store the peer identity + * @return GNUNET_OK on success, GNUNET_SYSERR on failure + */ +int +GNUNET_TESTING_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_PeerIdentity *pid) +{ + char *keyfile; + struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Peer is lacking HOSTKEY configuration setting.\n")); + return GNUNET_SYSERR; + } + my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access hostkey.\n")); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); + GNUNET_CRYPTO_rsa_key_free (my_private_key); + GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), + &pid->hashPubKey); + return GNUNET_OK; +} + + +/* end of helper.c */ diff --git a/src/testing_old/test_testing.c b/src/testing_old/test_testing.c new file mode 100644 index 000000000..3e2cd65ee --- /dev/null +++ b/src/testing_old/test_testing.c @@ -0,0 +1,126 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing.c + * @brief testcase for testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES + +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +static int ok; + +static void +end_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); + ok = 1; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon terminated, will now exit.\n"); +#endif + ok = 0; + } +} + + + +void +do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d = cls; + + GNUNET_TESTING_daemon_stop (d, TIMEOUT, &end_cb, NULL, GNUNET_YES, GNUNET_NO); +} + + +static void +my_cb (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Daemon `%s' started, will now stop it.\n", GNUNET_i2s (id)); +#endif + GNUNET_SCHEDULER_add_now (&do_shutdown, d); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Daemon *d; + + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); +#endif + d = GNUNET_TESTING_daemon_start (cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb, NULL); + GNUNET_assert (d != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + return ret; +} + +/* end of test_testing.c */ diff --git a/src/testing_old/test_testing_2dtorus.c b/src/testing_old/test_testing_2dtorus.c new file mode 100644 index 000000000..00a66d65c --- /dev/null +++ b/src/testing_old/test_testing_2dtorus.c @@ -0,0 +1,372 @@ +/* + This file is part of GNUnet. + (C) 2011 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 testing/test_testing_2dtorus.c + * + * @brief Test for creating a 2dtorus. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES +#define REMOVE_DIR GNUNET_YES + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) + +/** + * Time to wait for stuff that should be rather fast + */ +#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + + +/** + * How many events have happened + */ +static int ok; + +/** + * Be verbose + */ +static int verbose; + +/** + * Total number of peers in the test. + */ +static unsigned long long num_peers; + +/** + * Global configuration file + */ +static struct GNUNET_CONFIGURATION_Handle *testing_cfg; + +/** + * Total number of currently running peers. + */ +static unsigned long long peers_running; + +/** + * Total number of successful connections in the whole network. + */ +static unsigned int total_connections; + +/** + * Total number of counted topo connections + */ +static unsigned int topo_connections; + +/** + * Total number of failed connections in the whole network. + */ +static unsigned int failed_connections; + +/** + * The currently running peer group. + */ +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Task called to disconnect peers + */ +static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +/** + * Task called to shutdown test. + */ +static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; + + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n"); +#endif + ok--; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: All peers successfully shut down!\n"); +#endif + } +} + + +static void +shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); +#endif + + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_CONFIGURATION_destroy (testing_cfg); +} + + +static void +disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); + + if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) + { + GNUNET_SCHEDULER_cancel (shutdown_handle); + shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); + } +} + + +/** + * Prototype of a callback function indicating that two peers + * are currently connected. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param emsg error message (NULL on success) + */ +void +topo_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + topo_connections++; + if (NULL != emsg) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error by topo %u: %s\n", + topo_connections, emsg); + } + else + { + if (first == NULL || second == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u NULL\n", + topo_connections); + if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (disconnect_task); + GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + } + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u ok\n", + topo_connections); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (first)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (second)); + } +} + + +/** + * peergroup_ready: start test when all peers are connected + * @param cls closure + * @param emsg error message + */ +static void +peergroup_ready (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", + emsg); + ok--; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "************************************************************\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Peer Group started successfully!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", + total_connections); +#endif + + peers_running = GNUNET_TESTING_daemons_running (pg); + if (0 < failed_connections) + { + ok = GNUNET_SYSERR; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n", + failed_connections); + disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); + + } + else + { + GNUNET_TESTING_get_topology (pg, &topo_cb, NULL); + disconnect_task = + GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL); + ok = GNUNET_OK; + } + +} + + +/** + * Function that will be called whenever two daemons are connected by + * the testing library. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param distance distance between the connected peers + * @param first_cfg config for the first daemon + * @param second_cfg config for the second daemon + * @param first_daemon handle for the first daemon + * @param second_daemon handle for the second daemon + * @param emsg error message (NULL on success) + */ +static void +connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; + } + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "test: Problem with new connection (%s)\n", emsg); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (first)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (second)); + } + +} + + +/** + * run: load configuration options and schedule test to run (start peergroup) + * @param cls closure + * @param args argv + * @param cfgfile configuration file name (can be NULL) + * @param cfg configuration handle + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Host *hosts; + + ok = GNUNET_NO; + total_connections = 0; + failed_connections = 0; + testing_cfg = GNUNET_CONFIGURATION_dup (cfg); + + GNUNET_log_setup ("test_testing_2dtorus", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", + "num_peers", &num_peers)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Option TESTING:NUM_PEERS is required!\n"); + return; + } + + hosts = GNUNET_TESTING_hosts_load (testing_cfg); + + pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, + &connect_cb, &peergroup_ready, NULL, + hosts); + GNUNET_assert (pg != NULL); + shutdown_handle = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, NULL); +} + + +/** + * test_testing_2dtorus command line options + */ +static struct GNUNET_GETOPT_CommandLineOption options[] = { + {'V', "verbose", NULL, + gettext_noop ("be verbose (print progress information)"), + 0, &GNUNET_GETOPT_set_one, &verbose}, + GNUNET_GETOPT_OPTION_END +}; + + +/** + * Main: start test + */ +int +main (int argc, char *argv[]) +{ + char *const argv2[] = { + argv[0], + "-c", + "test_testing_2dtorus.conf", +#if VERBOSE + "-L", + "DEBUG", +#endif + NULL + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n"); + + + GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, + "test_testing_2dtorus", + gettext_noop ("Test testing 2d torus."), options, &run, + NULL); +#if REMOVE_DIR + GNUNET_DISK_directory_remove ("/tmp/test_testing_2dtorus"); +#endif + if (GNUNET_OK != ok) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); + return 1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n"); + return 0; +} + +/* end of test_testing_2dtorus.c */ diff --git a/src/testing_old/test_testing_2dtorus.conf b/src/testing_old/test_testing_2dtorus.conf new file mode 100644 index 000000000..d69969f1a --- /dev/null +++ b/src/testing_old/test_testing_2dtorus.conf @@ -0,0 +1,81 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test_testing_2dtorus/ +DEFAULTCONFIG = test_testing_2dtorus.conf + +[arm] +PORT = 10010 +DEFAULTSERVICES = core +#DEBUG = YES + +[statistics] +AUTOSTART = YES +PORT = 10000 + +[dht] +DEBUG = NO +AUTOSTART = YES +ACCEPT_FROM6 = ::1; +ACCEPT_FROM = 127.0.0.1; +HOSTNAME = localhost +PORT = 10001 + +[nse] +WORKBITS = 0 + +[dns] +AUTOSTART = NO +PORT = 10011 + +[transport] +PORT = 10002 +AUTOSTART = YES +PLUGINS = tcp + +[nat] +DISABLEV6 = YES +BINDTO = 127.0.0.1 +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 + +[ats] +WAN_QUOTA_IN = 1 GB +WAN_QUOTA_OUT = 1 GB + +[core] +AUTOSTART = YES +PORT = 10003 + +[peerinfo] +AUTOSTART = YES +PORT = 10004 + +[testing_old] +NUM_PEERS = 16 +WEAKRANDOM = YES +TOPOLOGY = 2D_TORUS +CONNECT_TOPOLOGY = 2D_TORUS +#TOPOLOGY_FILE = small.dat +CONNECT_TOPOLOGY = 2D_TORUS +#CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +#CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 +#PERCENTAGE = 3 +#PROBABILITY = .1 +F2F = NO +CONNECT_TIMEOUT = 600 s +CONNECT_ATTEMPTS = 2 +DEBUG = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat +MAX_CONCURRENT_SSH = 10 +USE_PROGRESSBARS = YES +PEERGROUP_TIMEOUT = 2400 s +TOPOLOGY_OUTPUT_FILE = testing_topo_initial +MAX_OUTSTANDING_CONNECTIONS = 75 +#SINGLE_PEERINFO_PER_HOST = YES +#NUM_PEERINFO_PER_HOST = 10 +#SINGLE_STATISTICS_PER_HOST = YES +#NUM_STATISTICS_PER_HOST = 10 +DELETE_FILES = YES diff --git a/src/testing_old/test_testing_connect.c b/src/testing_old/test_testing_connect.c new file mode 100644 index 000000000..c69c20326 --- /dev/null +++ b/src/testing_old/test_testing_connect.c @@ -0,0 +1,197 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_connect.c + * @brief testcase for functions to connect two peers in testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define CONNECT_ATTEMPTS 3 + +static int ok; + +static struct GNUNET_TESTING_Daemon *d1; + +static struct GNUNET_TESTING_Daemon *d2; + +static struct GNUNET_CONFIGURATION_Handle *c1; + +static struct GNUNET_CONFIGURATION_Handle *c2; + +static struct GNUNET_TESTING_ConnectContext *cc; + +static void +end2_cb (void *cls, const char *emsg) +{ + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); + ok = 1; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Both daemons terminated, will now exit.\n"); +#endif + ok = 0; + } +} + +static void +end1_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", + emsg); + ok = 1; + } + else + { + ok = 0; + } + + GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, GNUNET_YES, + GNUNET_NO); + d2 = NULL; +} + +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, GNUNET_YES, + GNUNET_NO); + d1 = NULL; +} + +static void +my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + unsigned int distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + cc = NULL; + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + + +static void +my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, + GNUNET_YES, &my_connect_complete, NULL); +} + + +static void +my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb2, NULL); + GNUNET_assert (d2 != NULL); + +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); +#endif + c1 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c1, + "test_testing_connect_peer1.conf")); + c2 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c2, + "test_testing_connect_peer2.conf")); + d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb1, NULL); + GNUNET_assert (d1 != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-connect", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-connect", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + return ret; +} + +/* end of test_testing_connect.c */ diff --git a/src/testing_old/test_testing_connect_peer1.conf b/src/testing_old/test_testing_connect_peer1.conf new file mode 100644 index 000000000..cccda5e2a --- /dev/null +++ b/src/testing_old/test_testing_connect_peer1.conf @@ -0,0 +1,37 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-testing-connect-peer1/ +DEFAULTCONFIG = test_testing_connect_peer1.conf + +[transport-tcp] +PORT = 12568 + +[arm] +PORT = 12566 +DEFAULTSERVICES = core +UNIXPATH = /tmp/gnunet-p1-service-arm.sock + +[statistics] +PORT = 12567 +UNIXPATH = /tmp/gnunet-p1-service-statistics.sock + +[resolver] +PORT = 12564 +UNIXPATH = /tmp/gnunet-p1-service-resolver.sock + +[peerinfo] +PORT = 12569 +UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock + +[transport] +PORT = 12565 +UNIXPATH = /tmp/gnunet-p1-service-transport.sock + +[core] +PORT = 12570 +UNIXPATH = /tmp/gnunet-p1-service-core.sock + +[ats] +PORT = 12571 +UNIXPATH = /tmp/gnunet-p1-service-ats.sock + diff --git a/src/testing_old/test_testing_connect_peer2.conf b/src/testing_old/test_testing_connect_peer2.conf new file mode 100644 index 000000000..08ec55113 --- /dev/null +++ b/src/testing_old/test_testing_connect_peer2.conf @@ -0,0 +1,37 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +SERVICEHOME = /tmp/test-gnunet-testing-connect-peer2/ +DEFAULTCONFIG = test_testing_connect_peer2.conf + +[transport-tcp] +PORT = 22568 + +[arm] +PORT = 22566 +DEFAULTSERVICES = core +UNIXPATH = /tmp/gnunet-p2-service-arm.sock + +[statistics] +PORT = 22567 +UNIXPATH = /tmp/gnunet-p2-service-statistics.sock + +[resolver] +PORT = 22564 +UNIXPATH = /tmp/gnunet-p2-service-resolver.sock + +[peerinfo] +PORT = 22569 +UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock + +[transport] +PORT = 22565 +UNIXPATH = /tmp/gnunet-p2-service-transport.sock + +[core] +PORT = 22570 +UNIXPATH = /tmp/gnunet-p2-service-core.sock + +[ats] +PORT = 22571 +UNIXPATH = /tmp/gnunet-p2-service-ats.sock + diff --git a/src/testing_old/test_testing_data.conf b/src/testing_old/test_testing_data.conf new file mode 100644 index 000000000..c46cb0d42 --- /dev/null +++ b/src/testing_old/test_testing_data.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data.conf + +[arm] +DEFAULTSERVICES = core + diff --git a/src/testing_old/test_testing_data_remote.conf b/src/testing_old/test_testing_data_remote.conf new file mode 100644 index 000000000..477baad7e --- /dev/null +++ b/src/testing_old/test_testing_data_remote.conf @@ -0,0 +1,12 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_remote.conf + +[TESTING_old] +CONTROL_HOST = 127.0.0.1 +HOSTFILE = remote_hosts.txt +MAX_OUTSTANDING_SSH = 5 + +[statistics] +AUTOSTART = NO + diff --git a/src/testing_old/test_testing_data_topology_2d_torus.conf b/src/testing_old/test_testing_data_topology_2d_torus.conf new file mode 100644 index 000000000..62fff6925 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_2d_torus.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_2d_torus.conf + +[TESTING_old] +NUM_PEERS = 13 +TOPOLOGY = 2D_TORUS diff --git a/src/testing_old/test_testing_data_topology_blacklist.conf b/src/testing_old/test_testing_data_topology_blacklist.conf new file mode 100644 index 000000000..28e61301a --- /dev/null +++ b/src/testing_old/test_testing_data_topology_blacklist.conf @@ -0,0 +1,13 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_blacklist.conf + +[TESTING_old] +NUM_PEERS = 4 +TOPOLOGY = CLIQUE +BLACKLIST_TOPOLOGY = RING +BLACKLIST_TRANSPORTS = tcp udp http + +[transport-udp] +PORT = 2568 + diff --git a/src/testing_old/test_testing_data_topology_churn.conf b/src/testing_old/test_testing_data_topology_churn.conf new file mode 100644 index 000000000..ae46bf0e6 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_churn.conf @@ -0,0 +1,10 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_churn.conf + +[TESTING_old] +NUM_PEERS = 12 + +[arm] +DEFAULTSERVICES = peerinfo transport core + diff --git a/src/testing_old/test_testing_data_topology_clique.conf b/src/testing_old/test_testing_data_topology_clique.conf new file mode 100644 index 000000000..c71a4b6c2 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_clique.conf @@ -0,0 +1,10 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +CONNECT_TIMEOUT = 180 s +CONNECT_ATTEMPTS = 14 +NUM_PEERS = 4 +TOPOLOGY = CLIQUE +SETTLE_TIME = 0 diff --git a/src/testing_old/test_testing_data_topology_clique_dfs.conf b/src/testing_old/test_testing_data_topology_clique_dfs.conf new file mode 100644 index 000000000..349c398ed --- /dev/null +++ b/src/testing_old/test_testing_data_topology_clique_dfs.conf @@ -0,0 +1,13 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +NUM_PEERS = 7 +TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_DFS +CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 + +[arm] +DEFAULTSERVICES = peerinfo transport core + diff --git a/src/testing_old/test_testing_data_topology_clique_minimum.conf b/src/testing_old/test_testing_data_topology_clique_minimum.conf new file mode 100644 index 000000000..8d8206d33 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_clique_minimum.conf @@ -0,0 +1,10 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +NUM_PEERS = 20 +TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM +CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 + diff --git a/src/testing_old/test_testing_data_topology_clique_random.conf b/src/testing_old/test_testing_data_topology_clique_random.conf new file mode 100644 index 000000000..d76175291 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_clique_random.conf @@ -0,0 +1,16 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +NUM_PEERS = 20 +TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET +CONNECT_TOPOLOGY_OPTION_MODIFIER = .15 + +[statistics] +AUTOSTART = NO + +[resolver] +AUTOSTART = NO + diff --git a/src/testing_old/test_testing_data_topology_erdos_renyi.conf b/src/testing_old/test_testing_data_topology_erdos_renyi.conf new file mode 100644 index 000000000..ece17e505 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_erdos_renyi.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +TOPOLOGY = ERDOS_RENYI + diff --git a/src/testing_old/test_testing_data_topology_internat.conf b/src/testing_old/test_testing_data_topology_internat.conf new file mode 100644 index 000000000..14475ce55 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_internat.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +TOPOLOGY = INTERNAT + diff --git a/src/testing_old/test_testing_data_topology_none.conf b/src/testing_old/test_testing_data_topology_none.conf new file mode 100644 index 000000000..38e658680 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_none.conf @@ -0,0 +1,37 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +NUM_PEERS = 1000 +TOPOLOGY = NONE +F2F = NO +BLACKLIST_TOPOLOGY = NONE +CONNECT_TOPOLOGY = RING + +[arm] +PORT = 0 + +[statistics] +AUTOSTART = NO +PORT = 0 + +[resolver] +AUTOSTART = NO +PORT = 0 + +[peerinfo] +PORT = 0 + +[transport] +PORT = 0 + +[core] +PORT = 0 + +[topology] +PORT = 0 + +[hostlist] +PORT = 0 + diff --git a/src/testing_old/test_testing_data_topology_ring.conf b/src/testing_old/test_testing_data_topology_ring.conf new file mode 100644 index 000000000..5320ae068 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_ring.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +TOPOLOGY = RING + diff --git a/src/testing_old/test_testing_data_topology_scale_free.conf b/src/testing_old/test_testing_data_topology_scale_free.conf new file mode 100644 index 000000000..ae7233588 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_scale_free.conf @@ -0,0 +1,11 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_scale_free.conf + +[TESTING_old] +NUM_PEERS = 50 +TOPOLOGY = SCALE_FREE + +[arm] +DEFAULTSERVICES = peerinfo transport core + diff --git a/src/testing_old/test_testing_data_topology_small_world_ring.conf b/src/testing_old/test_testing_data_topology_small_world_ring.conf new file mode 100644 index 000000000..10e398fa0 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_small_world_ring.conf @@ -0,0 +1,8 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +NUM_PEERS = 25 +TOPOLOGY = SMALL_WORLD_RING + diff --git a/src/testing_old/test_testing_data_topology_small_world_torus.conf b/src/testing_old/test_testing_data_topology_small_world_torus.conf new file mode 100644 index 000000000..d5a58b760 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_small_world_torus.conf @@ -0,0 +1,7 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +TOPOLOGY = SMALL_WORLD + diff --git a/src/testing_old/test_testing_data_topology_stability.conf b/src/testing_old/test_testing_data_topology_stability.conf new file mode 100644 index 000000000..389c0aa25 --- /dev/null +++ b/src/testing_old/test_testing_data_topology_stability.conf @@ -0,0 +1,9 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_data_topology_clique.conf + +[TESTING_old] +SETTLE_TIME = 600 s +NUM_PEERS = 2 +TOPOLOGY = CLIQUE + diff --git a/src/testing_old/test_testing_defaults.conf b/src/testing_old/test_testing_defaults.conf new file mode 100644 index 000000000..a89064f81 --- /dev/null +++ b/src/testing_old/test_testing_defaults.conf @@ -0,0 +1,78 @@ +[PATHS] +SERVICEHOME = /tmp/test-gnunet-testing/ +DEFAULTCONFIG = test_testing_defaults.conf + +[resolver] +PORT = 2564 + +[transport] +PORT = 2565 +PLUGINS = tcp + +[arm] +PORT = 2566 +DEFAULTSERVICES = + +[statistics] +PORT = 2567 + +[transport-tcp] +PORT = 2568 +BINDTO = 127.0.0.1 + +[peerinfo] +PORT = 2569 + +[core] +PORT = 2570 + +[testing_old] +NUM_PEERS = 5 +WEAKRANDOM = YES +F2F = YES +HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat + +[dht] +AUTOSTART = NO + +[nat] +DISABLEV6 = YES +ENABLE_UPNP = NO +BEHIND_NAT = NO +ALLOW_NAT = NO +INTERNAL_ADDRESS = 127.0.0.1 +EXTERNAL_ADDRESS = 127.0.0.1 +USE_LOCALADDR = NO + +[dns] +AUTOSTART = NO + +[nse] +AUTOSTART = NO + +[mesh] +AUTOSTART = NO + +[datastore] +AUTOSTART = NO + +[fs] +AUTOSTART = NO + +[dv] +AUTOSTART = NO + +[chat] +AUTOSTART = NO + +[vpn] +AUTOSTART = NO + +[gns] +AUTOSTART = NO + +[namestore] +AUTOSTART = NO + +[lockmanager] +AUTOSTART = NO diff --git a/src/testing_old/test_testing_group.c b/src/testing_old/test_testing_group.c new file mode 100644 index 000000000..f5df45b19 --- /dev/null +++ b/src/testing_old/test_testing_group.c @@ -0,0 +1,166 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_group.c + * @brief testcase for functions to connect peers in testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +#define NUM_PEERS 4 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +static int ok; + +static int peers_left; + +static int failed_peers; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + + +static void +my_cb (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (id == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Start callback called with error (too long starting peers), aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); + failed_peers++; + if (failed_peers == peers_left) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Too many peers failed, ending test!\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + } + return; + } + + peers_left--; + if (peers_left == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All peers started successfully, ending test!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; + } + else if (failed_peers == peers_left) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Too many peers failed, ending test!\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); +#endif + peers_left = NUM_PEERS; + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ + peers_left, /* Number of outstanding connections */ + peers_left, /* Number of parallel ssh connections, or peers being started at once */ + TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, + NULL, NULL); + GNUNET_assert (pg != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-group", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-group", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Still need to remove the base testing directory here, + * because group starts will create subdirectories under this + * main dir. However, we no longer need to sleep, as the + * shutdown sequence won't return until everything is cleaned + * up. + */ + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); + return ret; +} + +/* end of test_testing_group.c */ diff --git a/src/testing_old/test_testing_group_remote.c b/src/testing_old/test_testing_group_remote.c new file mode 100644 index 000000000..b06655ca4 --- /dev/null +++ b/src/testing_old/test_testing_group_remote.c @@ -0,0 +1,263 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_group_remote.c + * @brief testcase for testing remote and local starting and connecting + * of hosts from the testing library. The test_testing_data_remote.conf + * file should be modified if this testcase is intended to be used. + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES + + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define DEFAULT_NUM_PEERS 8; + +static int ok; + +static int peers_left; + +static int peers_failed; + +static struct GNUNET_TESTING_PeerGroup *pg; + +static unsigned long long num_peers; + + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shutdown of peers failed (error %s)!\n", emsg); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + + +static void +my_cb (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + peers_failed++; + } + + peers_left--; + if (peers_left == 0) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 0; + } + else if (peers_failed == peers_left) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Too many peers failed, ending test!\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Host *hosts; + struct GNUNET_TESTING_Host *hostpos; + struct GNUNET_TESTING_Host *temphost; + char *hostfile; + struct stat frstat; + char *buf; + char *data; + int count; + int ret; + + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); +#endif + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned long long) -1); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", + &hostfile)) + hostfile = NULL; + + hosts = NULL; + data = NULL; + if (hostfile != NULL) + { + if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) + GNUNET_DISK_fn_write (hostfile, NULL, 0, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not open file specified for host list, ending test!"); + ok = 1119; + GNUNET_free (hostfile); + return; + } + + data = GNUNET_malloc_large (frstat.st_size); + GNUNET_assert (data != NULL); + if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not read file %s specified for host list, ending test!", + hostfile); + GNUNET_free (hostfile); + GNUNET_free (data); + return; + } + + GNUNET_free_non_null (hostfile); + + buf = data; + count = 0; + while (count < frstat.st_size) + { + count++; + if (count >= frstat.st_size) + break; + + /* if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count])) */ + if (((data[count] == '\n')) && (buf != &data[count])) + { + data[count] = '\0'; + temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); + ret = + SSCANF (buf, "%a[a-zA-Z0-9]@%a[a-zA-Z0-9.]:%hd", + &temphost->username, &temphost->hostname, &temphost->port); + if (3 == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Successfully read host %s, port %d and user %s from file\n", + temphost->hostname, temphost->port, temphost->username); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Error reading line `%s' in hostfile\n", buf); + GNUNET_free (temphost); + buf = &data[count + 1]; + continue; + } + /* temphost->hostname = buf; */ + temphost->next = hosts; + hosts = temphost; + buf = &data[count + 1]; + } + else if ((data[count] == '\n') || (data[count] == '\0')) + buf = &data[count + 1]; + } + } + + peers_left = num_peers; + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ + peers_left, /* Number of outstanding connections */ + peers_left, /* Number of parallel ssh connections, or peers being started at once */ + TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, + NULL, hosts); + hostpos = hosts; + while (hostpos != NULL) + { + temphost = hostpos->next; + GNUNET_free (hostpos->hostname); + GNUNET_free (hostpos->username); + GNUNET_free (hostpos); + hostpos = temphost; + } + GNUNET_free_non_null (data); + GNUNET_assert (pg != NULL); + +} + +static int +check () +{ + char *const argv[] = { "test-testing", + "-c", + "test_testing_data_remote.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-group", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-group", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + /** + * Still need to remove the base testing directory here, + * because group starts will create subdirectories under this + * main dir. However, we no longer need to sleep, as the + * shutdown sequence won't return until everything is cleaned + * up. + */ + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); + return ret; +} + +/* end of test_testing_group.c */ diff --git a/src/testing_old/test_testing_large_topology.c b/src/testing_old/test_testing_large_topology.c new file mode 100644 index 000000000..cd80db195 --- /dev/null +++ b/src/testing_old/test_testing_large_topology.c @@ -0,0 +1,1197 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_topology.c + * @brief base testcase for testing all the topologies provided + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_os_lib.h" + +#define VERBOSE GNUNET_YES + +#define DELAY_FOR_LOGGING GNUNET_NO + +#define SECONDS_PER_PEER_START 120 + +#define DEFAULT_NUM_PEERS 4 + +#define MAX_OUTSTANDING_CONNECTIONS 100 + +static float fail_percentage = 0.05; + +static int ok; + +struct GNUNET_TIME_Relative connect_timeout; + +static unsigned long long connect_attempts; + +static unsigned long long num_peers; + +static unsigned int topology_connections; + +static unsigned int total_connections; + +static unsigned int failed_connections; + +static unsigned int total_server_connections; + +static unsigned int total_messages_received; + +static unsigned int expected_messages; + +static unsigned int expected_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *dotOutFileName; + +static struct GNUNET_TIME_Relative settle_time; + +static FILE *dotOutFile; + +static char *topology_string; + +static char *blacklist_transports; + +static int transmit_ready_scheduled; + +static int transmit_ready_failed; + +static int transmit_ready_called; + +struct GNUNET_TIME_Relative test_timeout; + +struct GNUNET_TIME_Relative timeout; + +static unsigned int modnum; + +static unsigned int dotnum; + +static enum GNUNET_TESTING_Topology topology; + +static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ + +static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ + +static enum GNUNET_TESTING_TopologyOption connect_topology_option = + GNUNET_TESTING_TOPOLOGY_OPTION_ALL; + +static double connect_topology_option_modifier = 0.0; + +static char *test_directory; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +struct TestMessageContext +{ + /* This is a linked list */ + struct TestMessageContext *next; + + /* Handle to the sending peer core */ + struct GNUNET_CORE_Handle *peer1handle; + + /* Handle to the receiving peer core */ + struct GNUNET_CORE_Handle *peer2handle; + + /* Handle to the sending peer daemon */ + struct GNUNET_TESTING_Daemon *peer1; + + /* Handle to the receiving peer daemon */ + struct GNUNET_TESTING_Daemon *peer2; + + /* Identifier for this message, so we don't disconnect other peers! */ + uint32_t uid; + + /* Has peer1 been notified already of a connection to peer2? */ + int peer1notified; + + /* Has the core of peer2 been connected already? */ + int peer2connected; + + /* Task for disconnecting cores, allow task to be cancelled on shutdown */ + GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +}; + +static struct TestMessageContext *test_messages; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + +#if DELAY_FOR_LOGGING +static void +gather_log_data () +{ + char *peer_number; + char *connect_number; + struct GNUNET_OS_Process *mem_process; + + GNUNET_asprintf (&peer_number, "%llu", num_peers); + GNUNET_asprintf (&connect_number, "%llu", expected_connections); + mem_process = + GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", + "totals.txt", peer_number, connect_number, NULL); + GNUNET_OS_process_wait (mem_process); + GNUNET_OS_process_destroy (mem_process); + mem_process = NULL; +} + +#endif + +static void +finish_testing () +{ + GNUNET_assert (pg != NULL); + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); +#endif + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); + } + GNUNET_free (free_pos); + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", + transmit_ready_scheduled, transmit_ready_failed, + transmit_ready_called); +#endif + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); +#endif + GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL); + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } + + ok = 0; +} + + +static void +disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + /* Disconnect from the respective cores */ +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", + GNUNET_i2s (&pos->peer1->id)); +#endif + if (pos->peer1handle != NULL) + GNUNET_CORE_disconnect (pos->peer1handle); +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); +#endif + if (pos->peer2handle != NULL) + GNUNET_CORE_disconnect (pos->peer2handle); + /* Set handles to NULL so test case can be ended properly */ + pos->peer1handle = NULL; + pos->peer2handle = NULL; + pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + /* Decrement total connections so new can be established */ + total_server_connections -= 2; +} + + +static void +topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + FILE *outfile = cls; + + if (first != NULL) + { + if (outfile != NULL) + { + FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); + FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); + } + topology_connections++; + } + else + { + FPRINTF (stderr, + "Finished iterating over topology, %d total connections!\n", + topology_connections); + if (outfile != NULL) + { + FPRINTF (outfile, "%s", "}\n"); + FCLOSE (outfile); + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + } +} + +static int +process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi) +{ + char *dotOutFileNameFinished; + FILE *dotOutFileFinished; + struct TestMessageContext *pos = cls; + struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; + + if (pos->uid != ntohl (msg->uid)) + return GNUNET_OK; + +#if VERBOSE + if ((total_messages_received) % modnum == 0) + { + if (total_messages_received == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) total_messages_received / expected_messages) * + 100)); + + } + else if (total_messages_received % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + + total_messages_received++; + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), + ntohs (message->type)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total messages received %d, expected %d.\n", + total_messages_received, expected_messages); +#endif + + if (total_messages_received == expected_messages) + { +#if VERBOSE + FPRINTF (stdout, "%s", "100%%]\n"); +#endif + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); + dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); + GNUNET_free (dotOutFileNameFinished); + if (dotOutFileFinished != NULL) + { + FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); + } + topology_connections = 0; + GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); + //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + else + { + pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); + } + + return GNUNET_OK; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "End badly was called (%s)... stopping daemons.\n", msg); + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + GNUNET_free (free_pos); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", + transmit_ready_scheduled, transmit_ready_failed, + transmit_ready_called); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total messages received %d, expected %d.\n", + total_messages_received, expected_messages); +#endif + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } +} + +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_TestMessage *m; + struct TestMessageContext *pos = cls; + + GNUNET_assert (buf != NULL); + m = (struct GNUNET_TestMessage *) buf; + m->header.type = htons (MTYPE); + m->header.size = htons (sizeof (struct GNUNET_TestMessage)); + m->uid = htonl (pos->uid); + transmit_ready_called++; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", + GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, + transmit_ready_called); +#endif + return sizeof (struct GNUNET_TestMessage); +} + + +static struct GNUNET_CORE_MessageHandler no_handlers[] = { + {NULL, 0, 0} +}; + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, + {NULL, 0, 0} +}; + +static void +init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct TestMessageContext *pos = cls; + + total_server_connections++; + + pos->peer2connected = GNUNET_YES; + if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ + { +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", + GNUNET_i2s (my_identity), + GNUNET_h2s (&pos->peer1->id.hashPubKey)); +#endif + if (NULL == + GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout, + &pos->peer2->id, + sizeof (struct GNUNET_TestMessage), + &transmit_ready, pos)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + transmit_ready_failed++; + } + else + { + transmit_ready_scheduled++; + } + } +} + +/** + * Method called whenever a given peer connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param atsi performance data for the connection + */ +static void +connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi) +{ + struct TestMessageContext *pos = cls; + + if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) + { + pos->peer1notified = GNUNET_YES; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer `%s' notified of connection to peer `%s'\n", + GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); +#endif + } + else + return; + + if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ + { +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", + GNUNET_i2s (&pos->peer2->id), + GNUNET_h2s (&pos->peer1->id.hashPubKey)); +#endif + if (NULL == + GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout, + &pos->peer2->id, + sizeof (struct GNUNET_TestMessage), + &transmit_ready, pos)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + transmit_ready_failed++; + } + else + { + transmit_ready_scheduled++; + } + } +} + +static void +init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct TestMessageContext *pos = cls; + + total_server_connections++; + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core connection to `%4s' established, setting up handles\n", + GNUNET_i2s (my_identity)); +#endif + + /* + * Connect to the receiving peer + */ + pos->peer2handle = + GNUNET_CORE_connect (pos->peer2->cfg, pos, &init_notify_peer2, NULL, + NULL, NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, + handlers); + +} + + +static void +send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + if ((pos == test_messages) && (settle_time.rel_value > 0)) + { + topology_connections = 0; + GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); + } + if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) + return; + + if (die_task == GNUNET_SCHEDULER_NO_TASK) + { + die_task = + GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, + "from send test messages (timeout)"); + } + + if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos); + return; /* Otherwise we'll double schedule messages here! */ + } + + /* + * Connect to the sending peer + */ + pos->peer1handle = + GNUNET_CORE_connect (pos->peer1->cfg, pos, &init_notify_peer1, + &connect_notify_peers, NULL, NULL, NULL, GNUNET_NO, + NULL, GNUNET_NO, no_handlers); + + GNUNET_assert (pos->peer1handle != NULL); + + if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); + } + else + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos->next); + } +} + + +void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct TestMessageContext *temp_context; + + if (emsg == NULL) + { +#if VERBOSE + if ((total_connections) % modnum == 0) + { + if (total_connections == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) total_connections / expected_connections) * + 100)); + + } + else if (total_connections % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + total_connections++; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", + first_daemon->shortname, second_daemon->shortname); +#endif + temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); + temp_context->peer1 = first_daemon; + temp_context->peer2 = second_daemon; + temp_context->next = test_messages; + temp_context->uid = total_connections; + temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + test_messages = temp_context; + + expected_messages++; + if (dotOutFile != NULL) + FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, + second_daemon->shortname); + } +#if VERBOSE + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } +#endif + + if (total_connections == expected_connections) + { +#if VERBOSE + FPRINTF (stdout, "%s", "100%%]\n"); +#endif +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Calling send messages.\n", + total_connections); +#endif + modnum = expected_messages / 4; + dotnum = (expected_messages / 50) + 1; + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; +#if DELAY_FOR_LOGGING + FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &send_test_messages, test_messages); + gather_log_data (); +#else + if (settle_time.rel_value > 0) + { + GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); + } + GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, + test_messages); +#endif +#if VERBOSE + FPRINTF (stdout, "%s", "Test message progress: ["); +#endif + + } + else if (total_connections + failed_connections == expected_connections) + { + if (failed_connections < + (unsigned int) (fail_percentage * total_connections)) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } + } + else + { +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have %d total connections, %d failed connections, Want %d (at least %d)\n", + total_connections, failed_connections, expected_connections, + expected_connections - + (unsigned int) (fail_percentage * expected_connections)); +#endif + } +} + +static void +topology_creation_finished (void *cls, const char *emsg) +{ +#if VERBOSE + if (emsg == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All topology connections created successfully!\n"); +#endif +} + +static void +connect_topology () +{ + expected_connections = -1; + if ((pg != NULL) && (peers_left == 0)) + { + expected_connections = + GNUNET_TESTING_connect_topology (pg, connection_topology, + connect_topology_option, + connect_topology_option_modifier, + connect_timeout, connect_attempts, + &topology_creation_finished, NULL); +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", + expected_connections); +#endif + } + + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections == GNUNET_SYSERR) + { + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + } + + die_task = + GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, + "from connect topology (timeout)"); + modnum = expected_connections / 4; + dotnum = (expected_connections / 50) + 1; +#if VERBOSE + FPRINTF (stdout, "%s", "Peer connection progress: ["); +#endif +} + +static void +create_topology () +{ + peers_left = num_peers; /* Reset counter */ + if (GNUNET_TESTING_create_topology + (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, now starting peers!\n"); + FPRINTF (stdout, "%s", "Daemon start progress ["); +#endif + GNUNET_TESTING_daemons_continue_startup (pg); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from create topology (bad return)"); + } + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, + "from continue startup (timeout)"); +} + + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); +#endif +#if VERBOSE + if ((num_peers - peers_left) % modnum == 0) + { + if (num_peers - peers_left == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) (num_peers - peers_left) / num_peers) * 100)); + + } + else if ((num_peers - peers_left) % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + FPRINTF (stdout, "%s", "100%%]\n"); +#endif +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (timeout, &end_badly, + "from peers_started_callback"); +#if DELAY_FOR_LOGGING + FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); + gather_log_data (); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &connect_topology, NULL); +#else + connect_topology (); +#endif + ok = 0; + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +void +hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, + num_peers, GNUNET_i2s (id)); +#endif + +#if VERBOSE + if ((num_peers - peers_left) % modnum == 0) + { + if (num_peers - peers_left == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) (num_peers - peers_left) / num_peers) * 100)); + + } + else if ((num_peers - peers_left) % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + FPRINTF (stdout, "%s", "100%%]\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d hostkeys created, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, + "from create_topology"); + GNUNET_SCHEDULER_add_now (&create_topology, NULL); + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *topology_str; + char *connect_topology_str; + char *blacklist_topology_str; + char *connect_topology_option_str; + char *connect_topology_option_modifier_string; + unsigned long long temp_settle; + + ok = 1; + + dotOutFile = FOPEN (dotOutFileName, "w"); + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "strict graph G {\n"); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); +#endif + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", + &topology_str)) && + (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "TOPOLOGY"); + topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology", + &connect_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&connection_topology, + connect_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology `%s' given for section %s option %s\n", + connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); + } + GNUNET_free_non_null (connect_topology_str); + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option", + &connect_topology_option_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_option_get (&connect_topology_option, + connect_topology_option_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology option `%s' given for section %s option %s\n", + connect_topology_option_str, "TESTING", + "CONNECT_TOPOLOGY_OPTION"); + connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ + } + GNUNET_free_non_null (connect_topology_option_str); + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option_modifier", + &connect_topology_option_modifier_string)) + { + if (SSCANF + (connect_topology_option_modifier_string, "%lf", + &connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + connect_topology_option_modifier_string, + "connect_topology_option_modifier", "TESTING"); + } + GNUNET_free (connect_topology_option_modifier_string); + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_transports", + &blacklist_transports)) + blacklist_transports = NULL; + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_topology", + &blacklist_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&blacklist_topology, + blacklist_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); + } + GNUNET_free_non_null (topology_str); + GNUNET_free_non_null (blacklist_topology_str); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", + &settle_time)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "SETTLE_TIME"); + return; + } + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "CONNECT_TIMEOUT", + &connect_timeout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "CONNECT_TIMEOUT"); + return; + } + + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", + &connect_attempts)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "connect_attempts"); + return; + } + + main_cfg = cfg; + + peers_left = num_peers; + + /** + * How long until we fail the whole testcase? + */ + test_timeout = + GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START), num_peers * 2); + + /** + * How long until we give up on starting the peers? + */ + timeout = + GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START), num_peers); + + modnum = num_peers / 4; + dotnum = (num_peers / 50) + 1; +#if VERBOSE + FPRINTF (stdout, "%s", "Hostkey generation progress: ["); +#endif + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (timeout, &end_badly, + "didn't generate all hostkeys within a reasonable amount of time!!!"); + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left / 2, + peers_left, timeout, &hostkey_callback, + NULL, &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + char *binary_name; + char *config_file_name; + + GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); + GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", + topology_string); + int ret; + + char *const argv[] = { binary_name, + "-c", + config_file_name, +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + binary_name, "nohelp", options, &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-testing-topology-%s': Failed with error code %d\n", + topology_string, ret); + } + GNUNET_free (binary_name); + GNUNET_free (config_file_name); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + char *binary_start_pos; + char *our_binary_name; + + binary_start_pos = rindex (argv[0], '/'); + GNUNET_assert (binary_start_pos != NULL); + topology_string = strstr (binary_start_pos, "_topology"); + GNUNET_assert (topology_string != NULL); + topology_string++; + topology_string = strstr (topology_string, "_"); + GNUNET_assert (topology_string != NULL); + topology_string++; + + GNUNET_asprintf (&our_binary_name, "test-testing-large-topology_%s", + topology_string); + GNUNET_asprintf (&dotOutFileName, "large_topology_%s.dot", topology_string); + + GNUNET_log_setup (our_binary_name, +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + GNUNET_free (our_binary_name); + return ret; +} + +/* end of test_testing_topology.c */ diff --git a/src/testing_old/test_testing_peergroup.c b/src/testing_old/test_testing_peergroup.c new file mode 100644 index 000000000..061a0ca75 --- /dev/null +++ b/src/testing_old/test_testing_peergroup.c @@ -0,0 +1,157 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_peergroup.c + * @brief testcase for functions to connect peers in testing_peergroup.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_NO + +#define NUM_PEERS 4 + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +static int ok; + +static int peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + ok = 0; + } +} + + +static void +my_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peergroup callback called with error, aborting test!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); + ok = 1; + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer Group started successfully, ending test!\n"); + /** + * If something is to actually be DONE with the testcase, it should + * be put in here. Usually there will be a struct declared (or global + * variables can be used) to keep track of the state, statistics, + * handles to peers, etc. The example here is the opaque "TestCaseData" + * struct that could be passed into a function "additional_code_for_testing" + * which can be used to perform actions on the peers in the peergroup. + * Also, the GNUNET_TESTING_daemons_stop call would need to be removed, + * and only called once all of the testing is complete. + */ + + /** + * struct TestcaseData *state_closure; + * GNUNET_SCHEDULER_add_now(&additional_code_for_testing, state_closure); + */ + + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CONFIGURATION_Handle *testing_cfg; + + ok = 1; + testing_cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (testing_cfg, cfgfile)); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); + GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", + "use_progressbars", "YES"); +#endif + peers_left = NUM_PEERS; + pg = GNUNET_TESTING_peergroup_start (testing_cfg, peers_left, TIMEOUT, NULL, + &my_cb, NULL, NULL); + GNUNET_assert (pg != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing-peergroup", + "-c", + "test_testing_peergroup_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-peergroup", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-peergroup", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); + return ret; +} + +/* end of test_testing_peergroup.c */ diff --git a/src/testing_old/test_testing_peergroup_data.conf b/src/testing_old/test_testing_peergroup_data.conf new file mode 100644 index 000000000..880cebf86 --- /dev/null +++ b/src/testing_old/test_testing_peergroup_data.conf @@ -0,0 +1,22 @@ +@INLINE@ test_testing_defaults.conf +[PATHS] +DEFAULTCONFIG = test_testing_peergroup_data.conf + +[TESTING_old] +CONNECT_ATTEMPTS = 2 +MAX_OUTSTANDING_CONNECTIONS = 20 +MAX_CONCURRENT_SSH = 1 +PEERGROUP_TIMEOUT = 300 s +TOPOLOGY = CLIQUE +PERCENTAGE = 0.5 +PROBABILITY = 0.5 +CONNECT_TOPOLOGY = CLIQUE +CONNECT_TOPOLOGY_OPTION = CONNECT_NONE +CONNECT_TOPOLOGY_OPTION_MODIFIER = 0.0 +BLACKLIST_TOPOLOGY = NONE +BLACKLIST_TRANSPORTS = tcp udp +USE_PROGRESSBARS = NO + +[arm] +DEFAULTSERVICES = core + diff --git a/src/testing_old/test_testing_reconnect.c b/src/testing_old/test_testing_reconnect.c new file mode 100644 index 000000000..bcee38659 --- /dev/null +++ b/src/testing_old/test_testing_reconnect.c @@ -0,0 +1,249 @@ +/* + This file is part of GNUnet. + (C) 2010 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 testing/test_testing_reconnect.c + * @brief testcase for functions to connect two peers in testing.c + */ +#include "platform.h" +#include "gnunet_testing_lib.h" + +#define VERBOSE GNUNET_YES + +/** + * How long until we give up on connecting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define CONNECT_ATTEMPTS 3 + +static int ok; + +static struct GNUNET_TESTING_Daemon *d1; + +static struct GNUNET_TESTING_Daemon *d2; + +static struct GNUNET_CONFIGURATION_Handle *c1; + +static struct GNUNET_CONFIGURATION_Handle *c2; + +static struct GNUNET_TESTING_ConnectContext *cc; + +/** + * How many start-connect-stop iterations should we do? + */ +#define NUM_PHASES 2 + +static int phase; + +/** + * Run the next phase of starting daemons, connecting them and + * stopping them again. + */ +static void +run_phase (void); + +static void +end2_cb (void *cls, const char *emsg) +{ + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); + ok = 1; + } + else + { + if (phase < NUM_PHASES) + { + FPRINTF (stderr, "%s", "."); + run_phase (); + return; + } + FPRINTF (stderr, "%s", ".\n"); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Both daemons terminated, will now exit.\n"); +#endif + ok = 0; + } +} + +static void +end1_cb (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", + emsg); + ok = 1; + } + else + { + ok = 0; + } + if (d2 != NULL) + { + GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, + (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, + GNUNET_NO); + d2 = NULL; + } +} + +static void +finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, + (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, + GNUNET_NO); + d1 = NULL; +} + + +static void +my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + unsigned int distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + cc = NULL; +#if VERBOSE + FPRINTF (stderr, "Peer %s ", GNUNET_i2s (first)); + FPRINTF (stderr, "connected to %s\n", GNUNET_i2s (second)); +#endif + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + + + + +static void +my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 2 gave: %s\n", + emsg); + GNUNET_assert (0); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, + GNUNET_YES, &my_connect_complete, NULL); +} + + +static void +my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 1 gave: %s\n", + emsg); + GNUNET_assert (0); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", + GNUNET_i2s (id)); +#endif + d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb2, NULL); + GNUNET_assert (d2 != NULL); +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); +#endif + c1 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c1, + "test_testing_connect_peer1.conf")); + c2 = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (c2, + "test_testing_connect_peer2.conf")); + run_phase (); +} + +static void +run_phase () +{ + phase++; + d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, + NULL, NULL, &my_cb1, NULL); + GNUNET_assert (d1 != NULL); +} + +static int +check () +{ + char *const argv[] = { "test-testing-reconnect", + "-c", + "test_testing_data.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-reconnect", "nohelp", options, &run, &ok); + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test-testing-reconnect", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + return ret; +} + +/* end of test_testing_reconnect.c */ diff --git a/src/testing_old/test_testing_topology.c b/src/testing_old/test_testing_topology.c new file mode 100644 index 000000000..94cbc0df6 --- /dev/null +++ b/src/testing_old/test_testing_topology.c @@ -0,0 +1,1220 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_topology.c + * @brief base testcase for testing all the topologies provided + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_os_lib.h" + + +#define PROGRESS_BARS GNUNET_YES + +#define DELAY_FOR_LOGGING GNUNET_NO + +/** + * How long until we fail the whole testcase? + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 240) + +/** + * How long until we give up on starting the peers? + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500) + +#define SECONDS_PER_PEER_START 120 + +#define DEFAULT_NUM_PEERS 4 + +#define MAX_OUTSTANDING_CONNECTIONS 100 + +static float fail_percentage = 0.05; + +static int ok; + +static unsigned long long num_peers; + +struct GNUNET_TIME_Relative connect_timeout; + +static unsigned long long connect_attempts; + +static unsigned int topology_connections; + +static unsigned int total_connections; + +static unsigned int failed_connections; + +static unsigned int total_server_connections; + +static unsigned int total_messages_received; + +static unsigned int expected_messages; + +static unsigned int expected_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *dotOutFileName; + +static struct GNUNET_TIME_Relative settle_time; + +static FILE *dotOutFile; + +static char *topology_string; + +static char *blacklist_transports; + +static int transmit_ready_scheduled; + +static int transmit_ready_failed; + +static int transmit_ready_called; + +static unsigned int modnum; + +static unsigned int dotnum; + +static enum GNUNET_TESTING_Topology topology; + +static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ + +static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ + +static enum GNUNET_TESTING_TopologyOption connect_topology_option = + GNUNET_TESTING_TOPOLOGY_OPTION_ALL; + +static double connect_topology_option_modifier = 0.0; + +static char *test_directory; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +struct TestMessageContext +{ + /* This is a linked list */ + struct TestMessageContext *next; + + /* Handle to the sending peer core */ + struct GNUNET_CORE_Handle *peer1handle; + + /* Handle to the receiving peer core */ + struct GNUNET_CORE_Handle *peer2handle; + + /* Handle to the sending peer daemon */ + struct GNUNET_TESTING_Daemon *peer1; + + /* Handle to the receiving peer daemon */ + struct GNUNET_TESTING_Daemon *peer2; + + /* Identifier for this message, so we don't disconnect other peers! */ + uint32_t uid; + + /* Has peer1 been notified already of a connection to peer2? */ + int peer1notified; + + /* Has the core of peer2 been connected already? */ + int peer2connected; + + /* Task for disconnecting cores, allow task to be cancelled on shutdown */ + GNUNET_SCHEDULER_TaskIdentifier disconnect_task; + +}; + +static struct TestMessageContext *test_messages; + +/** + * Check whether peers successfully shut down. + */ +static void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown of peers failed: %s!\n", + emsg); + if (ok == 0) + ok = 666; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); + } +} + + +#if DELAY_FOR_LOGGING +static void +gather_log_data () +{ + char *peer_number; + char *connect_number; + struct GNUNET_OS_Process *mem_process; + + GNUNET_asprintf (&peer_number, "%llu", num_peers); + GNUNET_asprintf (&connect_number, "%llu", expected_connections); + mem_process = + GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", + "totals.txt", peer_number, connect_number, NULL); + GNUNET_OS_process_wait (mem_process); + GNUNET_OS_process_destroy (mem_process); + mem_process = NULL; +} +#endif + + +static void +finish_testing () +{ + GNUNET_assert (pg != NULL); + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); + } + GNUNET_free (free_pos); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", + transmit_ready_scheduled, transmit_ready_failed, + transmit_ready_called); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } + ok = 0; +} + + +static void +disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + /* Disconnect from the respective cores */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", + GNUNET_i2s (&pos->peer1->id)); + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + /* Decrement total connections so new can be established */ + total_server_connections -= 2; +} + +#if DO_STATS +static void +stats_finished (void *cls, int result) +{ + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); +} + +/** + * Callback function to process statistic values. + * + * @param cls closure + * @param peer the peer the statistics belong to + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +stats_print (void *cls, const struct GNUNET_PeerIdentity *peer, + const char *subsystem, const char *name, uint64_t value, + int is_persistent) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s:%s -- %llu\n", GNUNET_i2s (peer), + subsystem, name, value); + return GNUNET_OK; +} +#endif + + +static void +topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + FILE *outfile = cls; + + if (first != NULL) + { + if (outfile != NULL) + { + FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); + FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); + } + topology_connections++; + } + else + { + FPRINTF (stderr, + "Finished iterating over topology, %d total connections!\n", + topology_connections); + if (outfile != NULL) + { + FPRINTF (outfile, "%s", "}\n"); + FCLOSE (outfile); +#if DO_STATS + GNUNET_TESTING_get_statistics (pg, &stats_finished, &stats_print, NULL); +#endif + GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + } +} + + +static int +process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + char *dotOutFileNameFinished; + FILE *dotOutFileFinished; + struct TestMessageContext *pos = cls; + struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; + + if (pos->uid != ntohl (msg->uid)) + return GNUNET_OK; + +#if PROGRESS_BARS + if ((total_messages_received) % modnum == 0) + { + if (total_messages_received == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) total_messages_received / expected_messages) * + 100)); + + } + else if (total_messages_received % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + + total_messages_received++; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), + ntohs (message->type)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total messages received %d, expected %d.\n", + total_messages_received, expected_messages); + + if (total_messages_received == expected_messages) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); +#endif + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); + dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); + GNUNET_free (dotOutFileNameFinished); + if (dotOutFileFinished != NULL) + { + FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); + } + topology_connections = 0; + GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); + //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + else + { + pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); + } + + return GNUNET_OK; +} + + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Ending with error: %s\n", msg); + struct TestMessageContext *pos; + struct TestMessageContext *free_pos; + + pos = test_messages; + while (pos != NULL) + { + if (pos->peer1handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer1handle); + pos->peer1handle = NULL; + } + if (pos->peer2handle != NULL) + { + GNUNET_CORE_disconnect (pos->peer2handle); + pos->peer2handle = NULL; + } + free_pos = pos; + pos = pos->next; + GNUNET_free (free_pos); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", + transmit_ready_scheduled, transmit_ready_failed, + transmit_ready_called); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total messages received %d, expected %d.\n", + total_messages_received, expected_messages); + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } +} + + +static size_t +transmit_ready (void *cls, size_t size, void *buf) +{ + struct GNUNET_TestMessage *m; + struct TestMessageContext *pos = cls; + + GNUNET_assert (buf != NULL); + m = (struct GNUNET_TestMessage *) buf; + m->header.type = htons (MTYPE); + m->header.size = htons (sizeof (struct GNUNET_TestMessage)); + m->uid = htonl (pos->uid); + transmit_ready_called++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", + GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, + transmit_ready_called); + return sizeof (struct GNUNET_TestMessage); +} + + +static struct GNUNET_CORE_MessageHandler no_handlers[] = { + {NULL, 0, 0} +}; + + +static struct GNUNET_CORE_MessageHandler handlers[] = { + {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, + {NULL, 0, 0} +}; + + +static void +init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct TestMessageContext *pos = cls; + + total_server_connections++; + + pos->peer2connected = GNUNET_YES; + if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", + GNUNET_i2s (my_identity), + GNUNET_h2s (&pos->peer1->id.hashPubKey)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, + TIMEOUT, &pos->peer2->id, + sizeof (struct GNUNET_TestMessage), + &transmit_ready, pos)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + transmit_ready_failed++; + } + else + { + transmit_ready_scheduled++; + } + } +} + + +/** + * Method called whenever a given peer connects. + * + * @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 +connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct TestMessageContext *pos = cls; + + if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) + { + pos->peer1notified = GNUNET_YES; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peer `%s' notified of connection to peer `%s'\n", + GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); + } + else + return; + + if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", + GNUNET_i2s (&pos->peer2->id), + GNUNET_h2s (&pos->peer1->id.hashPubKey)); + if (NULL == + GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, + TIMEOUT, &pos->peer2->id, + sizeof (struct GNUNET_TestMessage), + &transmit_ready, pos)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", + GNUNET_i2s (&pos->peer2->id)); + transmit_ready_failed++; + } + else + { + transmit_ready_scheduled++; + } + } +} + + +static void +init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct TestMessageContext *pos = cls; + + total_server_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Core connection to `%4s' established, setting up handles\n", + GNUNET_i2s (my_identity)); + /* + * Connect to the receiving peer + */ + pos->peer2handle = + GNUNET_CORE_connect (pos->peer2->cfg, pos, &init_notify_peer2, NULL, + NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, handlers); + +} + + +static void +send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TestMessageContext *pos = cls; + + if ((pos == test_messages) && (settle_time.rel_value > 0)) + { + topology_connections = 0; + GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); + } + if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) + return; + + if (die_task == GNUNET_SCHEDULER_NO_TASK) + { + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from send test messages (timeout)"); + } + + if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos); + return; /* Otherwise we'll double schedule messages here! */ + } + + /* + * Connect to the sending peer + */ + pos->peer1handle = + GNUNET_CORE_connect (pos->peer1->cfg, pos, &init_notify_peer1, + &connect_notify_peers, NULL, NULL, GNUNET_NO, NULL, + GNUNET_NO, no_handlers); + + GNUNET_assert (pos->peer1handle != NULL); + + if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) + { + GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); + } + else + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 1), + &send_test_messages, pos->next); + } +} + + +static void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct TestMessageContext *temp_context; + + if (emsg == NULL) + { +#if PROGRESS_BARS + if ((total_connections) % modnum == 0) + { + if (total_connections == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) total_connections / expected_connections) * + 100)); + + } + else if (total_connections % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + total_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", + first_daemon->shortname, second_daemon->shortname); + temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); + temp_context->peer1 = first_daemon; + temp_context->peer2 = second_daemon; + temp_context->next = test_messages; + temp_context->uid = total_connections; + temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; + test_messages = temp_context; + + expected_messages++; + if (dotOutFile != NULL) + FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, + second_daemon->shortname); + } + else + { + failed_connections++; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + } + + if (total_connections == expected_connections) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Calling send messages.\n", + total_connections); + modnum = expected_messages / 4; + dotnum = (expected_messages / 50) + 1; + if (modnum == 0) + modnum = 1; + if (dotnum == 0) + dotnum = 1; + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; +#if DELAY_FOR_LOGGING + FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &send_test_messages, test_messages); + gather_log_data (); +#else + if (settle_time.rel_value > 0) + { + GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); + } + GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, + test_messages); +#endif +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "Test message progress: ["); +#endif + + } + else if (total_connections + failed_connections == expected_connections) + { + if (failed_connections < + (unsigned int) (fail_percentage * total_connections)) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many failed connections)"); + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have %d total connections, %d failed connections, Want %d (at least %d)\n", + total_connections, failed_connections, expected_connections, + expected_connections - + (unsigned int) (fail_percentage * expected_connections)); + } +} + + +static void +topology_creation_finished (void *cls, const char *emsg) +{ + if (emsg == NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All topology connections created successfully!\n"); +} + + +static void +connect_topology () +{ + expected_connections = -1; + if ((pg != NULL) && (peers_left == 0)) + { + expected_connections = + GNUNET_TESTING_connect_topology (pg, connection_topology, + connect_topology_option, + connect_topology_option_modifier, + connect_timeout, connect_attempts, + &topology_creation_finished, NULL); +#if PROGRESS_BARS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", + expected_connections); +#endif + } + + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections < 1) + { + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + return; + } + + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &end_badly, + "from connect topology (timeout)"); + modnum = expected_connections / 4; + dotnum = (expected_connections / 50) + 1; + if (modnum == 0) + modnum = 1; + if (dotnum == 0) + dotnum = 1; +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "Peer connection progress: ["); +#endif +} + +static void +create_topology () +{ + peers_left = num_peers; /* Reset counter */ + if (GNUNET_TESTING_create_topology + (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) + { +#if PROGRESS_BARS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, now starting peers!\n"); + FPRINTF (stdout, "%s", "Daemon start progress ["); +#endif + GNUNET_TESTING_daemons_continue_startup (pg); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from create topology (bad return)"); + } + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &end_badly, + "from continue startup (timeout)"); +} + + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); +#if PROGRESS_BARS + if ((num_peers - peers_left) % modnum == 0) + { + if (num_peers - peers_left == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) (num_peers - peers_left) / num_peers) * 100)); + + } + else if ((num_peers - peers_left) % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + peers_left--; + if (peers_left == 0) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", num_peers); + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 8), &end_badly, + "from peers_started_callback"); +#if DELAY_FOR_LOGGING + FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); + gather_log_data (); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, 10), + &connect_topology, NULL); +#else + connect_topology (); +#endif + ok = 0; + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +void +hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, + num_peers, GNUNET_i2s (id)); +#if PROGRESS_BARS + if ((num_peers - peers_left) % modnum == 0) + { + if (num_peers - peers_left == 0) + FPRINTF (stdout, "%s", "0%%"); + else + FPRINTF (stdout, "%d%%", + (int) (((float) (num_peers - peers_left) / num_peers) * 100)); + + } + else if ((num_peers - peers_left) % dotnum == 0) + { + FPRINTF (stdout, "%s", "."); + } + fflush (stdout); +#endif + peers_left--; + if (peers_left == 0) + { +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "100%%]\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d hostkeys created, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, + "from create_topology"); + GNUNET_SCHEDULER_add_now (&create_topology, NULL); + ok = 0; + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *topology_str; + char *connect_topology_str; + char *blacklist_topology_str; + char *connect_topology_option_str; + char *connect_topology_option_modifier_string; + unsigned long long max_outstanding_connections; + + ok = 1; + + dotOutFile = FOPEN (dotOutFileName, "w"); + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "strict graph G {\n"); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", + &topology_str)) && + (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "TOPOLOGY"); + topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology", + &connect_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&connection_topology, + connect_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology `%s' given for section %s option %s\n", + connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); + } + GNUNET_free_non_null (connect_topology_str); + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option", + &connect_topology_option_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_option_get (&connect_topology_option, + connect_topology_option_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology option `%s' given for section %s option %s\n", + connect_topology_option_str, "TESTING", + "CONNECT_TOPOLOGY_OPTION"); + connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ + } + GNUNET_free_non_null (connect_topology_option_str); + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option_modifier", + &connect_topology_option_modifier_string)) + { + if (SSCANF + (connect_topology_option_modifier_string, "%lf", + &connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + connect_topology_option_modifier_string, + "connect_topology_option_modifier", "TESTING"); + } + GNUNET_free (connect_topology_option_modifier_string); + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_transports", + &blacklist_transports)) + blacklist_transports = NULL; + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_topology", + &blacklist_topology_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&blacklist_topology, + blacklist_topology_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); + } + GNUNET_free_non_null (topology_str); + GNUNET_free_non_null (blacklist_topology_str); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", + &settle_time)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "SETTLE_TIME"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", + &connect_timeout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "CONNECT_TIMEOUT"); + return; + } + + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", + &connect_attempts)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "connect_attempts"); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "max_outstanding_connections", + &max_outstanding_connections)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "max_outstanding_connections"); + return; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + main_cfg = cfg; + + peers_left = num_peers; + modnum = num_peers / 4; + dotnum = (num_peers / 50) + 1; + if (modnum == 0) + modnum = 1; + if (dotnum == 0) + dotnum = 1; +#if PROGRESS_BARS + FPRINTF (stdout, "%s", "Hostkey generation progress: ["); +#endif + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &end_badly, + "didn't generate all hostkeys within a reasonable amount of time!!!"); + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, + max_outstanding_connections, peers_left, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + SECONDS_PER_PEER_START * num_peers), + &hostkey_callback, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + + +static int +check () +{ + char *binary_name; + char *config_file_name; + + GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); + GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", + topology_string); + int ret; + + char *const argv[] = { binary_name, + "-c", + config_file_name, + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + binary_name, "nohelp", options, &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-testing-topology-%s': Failed with error code %d\n", + topology_string, ret); + } + GNUNET_free (binary_name); + GNUNET_free (config_file_name); + return ok; +} + + +int +main (int argc, char *argv[]) +{ + int ret; + char *binary_start_pos; + char *our_binary_name; + char *dotexe; + + binary_start_pos = strchr (argv[0], '/'); + GNUNET_assert (binary_start_pos != NULL); + topology_string = strstr (binary_start_pos, "_topology"); + GNUNET_assert (topology_string != NULL); + topology_string++; + topology_string = strstr (topology_string, "_"); + GNUNET_assert (topology_string != NULL); + topology_string++; + topology_string = GNUNET_strdup (topology_string); + if (NULL != (dotexe = strstr (topology_string, ".exe"))) + dotexe[0] = '\0'; + GNUNET_asprintf (&our_binary_name, "test-testing-topology_%s", + topology_string); + GNUNET_asprintf (&dotOutFileName, "topology_%s.dot", topology_string); + + GNUNET_log_setup (our_binary_name, + "WARNING", + NULL); + ret = check (); + GNUNET_free (topology_string); + + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + GNUNET_free (our_binary_name); + return ret; +} + +/* end of test_testing_topology.c */ diff --git a/src/testing_old/test_testing_topology_blacklist.c b/src/testing_old/test_testing_topology_blacklist.c new file mode 100644 index 000000000..c90f48d9b --- /dev/null +++ b/src/testing_old/test_testing_topology_blacklist.c @@ -0,0 +1,595 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_topology_blacklist.c + * @brief base testcase for testing transport level blacklisting + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + +#define VERBOSE GNUNET_NO + +/** + * How long until we fail the whole testcase? + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) + +/** + * How long until we give up on starting the peers? (Must be longer than the connect timeout!) + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define DEFAULT_NUM_PEERS 4 + +#define MAX_OUTSTANDING_CONNECTIONS 300 + +static int ok; + +struct GNUNET_TIME_Relative connect_timeout; + +static unsigned long long connect_attempts; + +static unsigned long long num_peers; + +static unsigned int total_connections; + +static unsigned int failed_connections; + +static unsigned int expected_connections; + +static unsigned int expected_failed_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *dotOutFileName; + +static FILE *dotOutFile; + +static char *blacklist_transports; + +static enum GNUNET_TESTING_Topology topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Overlay should allow all connections */ + +static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_RING; /* Blacklist underlay into a ring */ + +static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ + +static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Try to connect all possible OVERLAY connections */ + +static double connect_topology_option_modifier = 0.0; + +static char *test_directory; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); +#endif + if (ok == 0) + ok = 666; + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); +#endif + } +} + +static void +finish_testing () +{ + GNUNET_assert (pg != NULL); + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); +#endif + sleep (1); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); +#endif + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); +#endif + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } + + ok = 0; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "End badly was called (%s)... stopping daemons.\n", msg); + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "}"); + FCLOSE (dotOutFile); + } +} + + + +void +topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + if (emsg == NULL) + { + total_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n", + first_daemon->shortname, second_daemon->shortname); +#endif + if (dotOutFile != NULL) + FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, + second_daemon->shortname); + } + + else + { + failed_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); +#endif + } + + + if (total_connections == expected_connections) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number (that's bad)!\n", + total_connections); +#endif + + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (too many successful connections)"); + } + else if (total_connections + failed_connections == expected_connections) + { + if ((failed_connections == expected_failed_connections) && + (total_connections == + expected_connections - expected_failed_connections)) + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from topology_callback (wrong number of failed connections)"); + } + } + else + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Have %d total connections, %d failed connections, Want %d (failed) and %d (successful)\n", + total_connections, failed_connections, + expected_failed_connections, + expected_connections - expected_failed_connections); +#endif + } +} + +static void +connect_topology () +{ + expected_connections = -1; + if ((pg != NULL) && (peers_left == 0)) + { + expected_connections = + GNUNET_TESTING_connect_topology (pg, connection_topology, + connect_topology_option, + connect_topology_option_modifier, + connect_timeout, connect_attempts, + NULL, NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", + expected_connections); +#endif + } + + GNUNET_SCHEDULER_cancel (die_task); + if (expected_connections == GNUNET_SYSERR) + { + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from connect topology (bad return)"); + } + + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from connect topology (timeout)"); +} + +static void +create_topology () +{ + peers_left = num_peers; /* Reset counter */ + if (GNUNET_TESTING_create_topology + (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, now starting peers!\n"); +#endif + GNUNET_TESTING_daemons_continue_startup (pg); + } + else + { + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_now (&end_badly, + "from create topology (bad return)"); + } + GNUNET_SCHEDULER_cancel (die_task); + die_task = + GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, + "from continue startup (timeout)"); +} + + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "from peers_started_callback"); + connect_topology (); + ok = 0; + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +void +hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey created for peer `%s'\n", + GNUNET_i2s (id)); +#endif + peers_left--; + if (peers_left == 0) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d hostkeys created, now creating topology!\n", num_peers); +#endif + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "from hostkey_callback"); + GNUNET_SCHEDULER_add_now (&create_topology, NULL); + ok = 0; + } +} + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + unsigned long long topology_num; + unsigned long long connect_topology_num; + unsigned long long blacklist_topology_num; + unsigned long long connect_topology_option_num; + char *connect_topology_option_modifier_string; + + ok = 1; + + dotOutFile = FOPEN (dotOutFileName, "w"); + if (dotOutFile != NULL) + { + FPRINTF (dotOutFile, "%s", "strict graph G {\n"); + } + +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); +#endif + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + if (dotOutFile != NULL) + { + FCLOSE (dotOutFile); + } + return; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "topology", + &topology_num)) + topology = topology_num; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology", + &connect_topology_num)) + connection_topology = connect_topology_num; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "connect_topology_option", + &connect_topology_option_num)) + connect_topology_option = connect_topology_option_num; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "connect_topology_option_modifier", + &connect_topology_option_modifier_string)) + { + if (SSCANF + (connect_topology_option_modifier_string, "%lf", + &connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + connect_topology_option_modifier_string, + "connect_topology_option_modifier", "TESTING"); + GNUNET_free (connect_topology_option_modifier_string); + ok = 707; + if (dotOutFile != NULL) + { + FCLOSE (dotOutFile); + } + return; + } + GNUNET_free (connect_topology_option_modifier_string); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing", + "blacklist_transports", + &blacklist_transports)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No transports specified for blacklisting in blacklist testcase (this shouldn't happen!)\n"); + ok = 808; + if (dotOutFile != NULL) + { + FCLOSE (dotOutFile); + } + return; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", + "blacklist_topology", + &blacklist_topology_num)) + blacklist_topology = blacklist_topology_num; + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", + &connect_timeout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "CONNECT_TIMEOUT"); + return; + } + + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", + &connect_attempts)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing", "connect_attempts"); + return; + } + + main_cfg = cfg; + + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + peers_left = num_peers; + + /* For this specific test we only really want a CLIQUE topology as the + * overlay allowed topology, and a RING topology as the underlying connection + * allowed topology. So we will expect only num_peers * 2 connections to + * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. + */ + expected_connections = num_peers * (num_peers - 1); + expected_failed_connections = expected_connections - (num_peers * 2); + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, + TIMEOUT, &hostkey_callback, NULL, + &peers_started_callback, NULL, + &topology_callback, NULL, NULL); + +} + +static int +check () +{ + int ret; + + char *const argv[] = { "test-testing-topology-blacklist", + "-c", + "test_testing_data_topology_blacklist.conf", +#if VERBOSE + "-L", "DEBUG", +#endif + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-topology-blacklist", "nohelp", options, + &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-testing-topology-blacklist': Failed with error code %d\n", + ret); + } + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test_testing_topology_blacklist", +#if VERBOSE + "DEBUG", +#else + "WARNING", +#endif + NULL); + ret = check (); + + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (test_directory != NULL) + { + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + } + + return ret; +} + +/* end of test_testing_topology_blacklist.c */ diff --git a/src/testing_old/test_testing_topology_churn.c b/src/testing_old/test_testing_topology_churn.c new file mode 100644 index 000000000..9c0bbf27d --- /dev/null +++ b/src/testing_old/test_testing_topology_churn.c @@ -0,0 +1,322 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/test_testing_topology_churn.c + * @brief base testcase for testing simple churn functionality + */ +#include "platform.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + + +/** + * How long until we fail the whole testcase? + */ +#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) + +/** + * How long until we give up on starting the peers? (Must be longer than the connect timeout!) + */ +#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) + +#define DEFAULT_NUM_PEERS 4 + +static int ok; + +static unsigned long long num_peers; + +static unsigned int expected_connections; + +static unsigned int expected_failed_connections; + +static unsigned long long peers_left; + +static struct GNUNET_TESTING_PeerGroup *pg; + +const struct GNUNET_CONFIGURATION_Handle *main_cfg; + +GNUNET_SCHEDULER_TaskIdentifier die_task; + +static char *test_directory; + +#define MTYPE 12345 + +GNUNET_NETWORK_STRUCT_BEGIN + +struct GNUNET_TestMessage +{ + /** + * Header of the message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this message. + */ + uint32_t uid; +}; +GNUNET_NETWORK_STRUCT_END + +/** + * Check whether peers successfully shut down. + */ +void +shutdown_callback (void *cls, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); + if (ok == 0) + ok = 666; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); + } +} + +static void +finish_testing () +{ + GNUNET_assert (pg != NULL); + + if (die_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (die_task); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Called finish testing, stopping daemons.\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); + ok = 0; +} + +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + char *msg = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "End badly was called (%s)... stopping daemons.\n", msg); + + if (pg != NULL) + { + GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); + ok = 7331; /* Opposite of leet */ + } + else + ok = 401; /* Never got peers started */ + +} + +struct ChurnTestContext +{ + GNUNET_SCHEDULER_Task next_task; + +}; + +static struct ChurnTestContext churn_ctx; + +/** + * Churn callback, report on success or failure of churn operation. + * + * @param cls closure + * @param emsg NULL on success + */ +void +churn_callback (void *cls, const char *emsg) +{ + if (emsg == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully churned peers!\n", + emsg); + GNUNET_SCHEDULER_add_now (churn_ctx.next_task, NULL); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to churn peers with error `%s'\n", emsg); + GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); + } +} + + +static void +churn_peers_both () +{ + churn_ctx.next_task = &finish_testing; + GNUNET_TESTING_daemons_churn (pg, NULL, 1, 1, TIMEOUT, &churn_callback, NULL); +} + +static void +churn_peers_off_again () +{ + churn_ctx.next_task = &churn_peers_both; + GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); +} + +static void +churn_peers_on () +{ + churn_ctx.next_task = &churn_peers_off_again; + GNUNET_TESTING_daemons_churn (pg, NULL, 0, 2, TIMEOUT, &churn_callback, NULL); +} + +static void +churn_peers_off () +{ + churn_ctx.next_task = &churn_peers_on; + GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); +} + +static void +peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (num_peers - peers_left) + 1, num_peers); + peers_left--; + if (peers_left == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now testing churn!\n", num_peers); + GNUNET_SCHEDULER_cancel (die_task); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "from peers_started_callback"); + churn_peers_off (); + ok = 0; + } +} + + +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + ok = 1; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting daemons based on config file %s\n", cfgfile); + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", + &test_directory)) + { + ok = 404; + return; + } + + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", + &num_peers)) + num_peers = DEFAULT_NUM_PEERS; + + main_cfg = cfg; + + peers_left = num_peers; + GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); + + /* For this specific test we only really want a CLIQUE topology as the + * overlay allowed topology, and a RING topology as the underlying connection + * allowed topology. So we will expect only num_peers * 2 connections to + * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. + */ + expected_connections = num_peers * (num_peers - 1); + expected_failed_connections = expected_connections - (num_peers * 2); + + + /* Set up a task to end testing if peer start fails */ + die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, + "didn't start all daemons in reasonable amount of time!!!"); + + pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, + TIMEOUT, NULL, NULL, + &peers_started_callback, NULL, NULL, NULL, + NULL); + +} + +static int +check () +{ + int ret; + + char *const argv[] = { "test-testing-topology-churn", + "-c", + "test_testing_data_topology_churn.conf", + NULL + }; + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + ret = + GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, + "test-testing-topology-churn", "nohelp", options, + &run, &ok); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`test-testing-topology-churn': Failed with error code %d\n", + ret); + } + + return ok; +} + +int +main (int argc, char *argv[]) +{ + int ret; + + GNUNET_log_setup ("test_testing_topology_churn", + "WARNING", + NULL); + ret = check (); + + /** + * Need to remove base directory, subdirectories taken care + * of by the testing framework. + */ + if (test_directory != NULL) + { + if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to remove testing directory %s\n", test_directory); + } + } + + return ret; +} + +/* end of test_testing_topology_churn.c */ diff --git a/src/testing_old/testing.c b/src/testing_old/testing.c new file mode 100644 index 000000000..5456d56cb --- /dev/null +++ b/src/testing_old/testing.c @@ -0,0 +1,2204 @@ +/* + This file is part of GNUnet + (C) 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/testing.c + * @brief convenience API for writing testcases for GNUnet + * Many testcases need to start and stop gnunetd, + * and this library is supposed to make that easier + * for TESTCASES. Normal programs should always + * use functions from gnunet_{util,arm}_lib.h. This API is + * ONLY for writing testcases! + * @author Christian Grothoff + * + */ +#include "platform.h" +#include "gnunet_arm_service.h" +#include "gnunet_core_service.h" +#include "gnunet_constants.h" +#include "gnunet_testing_lib.h" +#include "gnunet_transport_service.h" +#include "gnunet_hello_lib.h" + +/** + * Hack to deal with initial HELLO's being often devoid of addresses. + * This hack causes 'process_hello' to ignore HELLOs without addresses. + * The correct implementation would continue with 'process_hello' until + * the connection could be established... + */ +#define EMPTY_HACK GNUNET_YES + +/** + * How long do we wait after starting gnunet-service-arm + * for the core service to be alive? + */ +#define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) + +/** + * How many times are we willing to try to wait for "scp" or + * "gnunet-service-arm" to complete (waitpid) before giving up? + */ +#define MAX_EXEC_WAIT_RUNS 250 + +static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; + +#if EMPTY_HACK +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; +} +#endif + +/** + * Receive the HELLO from one peer, give it to the other + * and ask them to connect. + * + * @param cls Closure (daemon whose hello is this). + * @param message HELLO message of peer + */ +static void +process_hello (void *cls, const struct GNUNET_MessageHeader *message) +{ + struct GNUNET_TESTING_Daemon *daemon = cls; + int msize; + +#if EMPTY_HACK + int empty; + + empty = GNUNET_YES; + GNUNET_assert (message != NULL); + GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *) message, + GNUNET_NO, &test_address, &empty); + if (GNUNET_YES == empty) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Skipping empty HELLO address of peer %s\n", + GNUNET_i2s (&daemon->id)); + return; + } +#endif + GNUNET_assert (daemon->phase == SP_GET_HELLO || + daemon->phase == SP_START_DONE); + daemon->cb = NULL; // FIXME: why??? (see fsm:SP_START_CORE, notify_daemon_started) + if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */ + GNUNET_SCHEDULER_cancel (daemon->task); + + if (daemon->server != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' from transport service of `%4s', disconnecting core!\n", + "HELLO", GNUNET_i2s (&daemon->id)); + GNUNET_CORE_disconnect (daemon->server); + daemon->server = NULL; + } + + msize = ntohs (message->size); + if (msize < 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "HELLO message of peer %s is of size 0\n", + GNUNET_i2s (&daemon->id)); + return; + } + if (daemon->ghh != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (daemon->ghh); + daemon->ghh = NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' from transport service of `%4s'\n", "HELLO", + GNUNET_i2s (&daemon->id)); + GNUNET_free_non_null (daemon->hello); + daemon->hello = GNUNET_malloc (msize); + memcpy (daemon->hello, message, msize); + + if (daemon->th != NULL) + { + GNUNET_TRANSPORT_disconnect (daemon->th); + daemon->th = NULL; + } + daemon->phase = SP_START_DONE; +} + + +/** + * Notify of a peer being up and running. Scheduled as a task + * so that variables which may need to be set are set before + * the connect callback can set up new operations. + * FIXME: what variables?????? where from???? + * + * @param cls the testing daemon + * @param tc task scheduler context + */ +static void +notify_daemon_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d = cls; + GNUNET_TESTING_NotifyDaemonRunning cb; + + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, &d->id, d->cfg, d, NULL); +} + + +/** + * Finite-state machine for starting GNUnet. + * + * @param cls our "struct GNUNET_TESTING_Daemon" + * @param tc unused + */ +static void +start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_Daemon *d = cls; + GNUNET_TESTING_NotifyDaemonRunning cb; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + char *dst; + int bytes_read; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %s FSM is in phase %u.\n", + GNUNET_i2s (&d->id), d->phase); + d->task = GNUNET_SCHEDULER_NO_TASK; + switch (d->phase) + { + case SP_COPYING: + /* confirm copying complete */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + _ + ("`scp' does not seem to terminate (timeout copying config).\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, _("`scp' did not complete cleanly.\n")); + return; + } + GNUNET_OS_process_destroy (d->proc_arm_copying); + d->proc_arm_copying = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully copied configuration file.\n"); + d->phase = SP_COPIED; + /* fall-through */ + case SP_COPIED: + /* Start create hostkey process if we don't already know the peer identity! */ + if (GNUNET_NO == d->have_hostkey) + { + GNUNET_assert (NULL == d->proc_arm_peerinfo); + d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES); + if (d->pipe_stdout == NULL) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? + _("Failed to create pipe for `gnunet-peerinfo' process.\n") : + _("Failed to create pipe for `ssh' process.\n")); + return; + } + if (NULL == d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting `%s', with command `%s %s %s %s'.\n", + "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile, + "-sq"); + d->proc_arm_peerinfo = + GNUNET_OS_start_process (GNUNET_YES, NULL, d->pipe_stdout, "gnunet-peerinfo", + "gnunet-peerinfo", "-c", d->cfgfile, "-sq", + NULL); + GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); + } + else + { + if (d->username != NULL) + GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); + else + dst = GNUNET_strdup (d->hostname); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting `%s', with command `%s %s %s %s %s %s'.\n", + "gnunet-peerinfo", "ssh", dst, "gnunet-peerinfo", "-c", + d->cfgfile, "-sq"); + if (d->ssh_port_str == NULL) + { + d->proc_arm_peerinfo = GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", + "-q", + dst, "gnunet-peerinfo", "-c", + d->cfgfile, "-sq", NULL); + } + else + { + d->proc_arm_peerinfo = + GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", "-p", + d->ssh_port_str, + "-q", + dst, "gnunet-peerinfo", "-c", d->cfgfile, + "-sq", NULL); + } + GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); + GNUNET_free (dst); + } + if (NULL == d->proc_arm_peerinfo) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start `%s' process to create hostkey.\n"), + (NULL == d->hostname) ? "gnunet-peerinfo" : "ssh"); + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("Failed to start `gnunet-peerinfo' process.\n") + : _("Failed to start `ssh' process.\n")); + GNUNET_DISK_pipe_close (d->pipe_stdout); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Started `%s', waiting for hostkey.\n", "gnunet-peerinfo"); + d->phase = SP_HOSTKEY_CREATE; + d->task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining + (d->max_timeout), + GNUNET_DISK_pipe_handle + (d->pipe_stdout, + GNUNET_DISK_PIPE_END_READ), + &start_fsm, d); + } + else /* Already have a hostkey! */ + { + if (d->hostkey_callback != NULL) + { + d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); + d->hostkey_callback = NULL; + d->phase = SP_HOSTKEY_CREATED; + } + else + d->phase = SP_TOPOLOGY_SETUP; + + /* wait some more */ + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); + } + break; + case SP_HOSTKEY_CREATE: + bytes_read = + GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle + (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ), + &d->hostkeybuf[d->hostkeybufpos], + sizeof (d->hostkeybuf) - d->hostkeybufpos); + if (bytes_read > 0) + d->hostkeybufpos += bytes_read; + + if ((d->hostkeybufpos < 104) && (bytes_read > 0)) + { + /* keep reading */ + d->task = + GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining + (d->max_timeout), + GNUNET_DISK_pipe_handle + (d->pipe_stdout, + GNUNET_DISK_PIPE_END_READ), + &start_fsm, d); + return; + } + d->hostkeybuf[103] = '\0'; + + if ((bytes_read < 0) || + (GNUNET_OK != + GNUNET_CRYPTO_hash_from_string (d->hostkeybuf, &d->id.hashPubKey))) + { + /* error */ + if (bytes_read < 0) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Error reading from gnunet-peerinfo: %s\n"), + STRERROR (errno)); + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Malformed output from gnunet-peerinfo!\n")); + cb = d->cb; + d->cb = NULL; + GNUNET_DISK_pipe_close (d->pipe_stdout); + d->pipe_stdout = NULL; + (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); + GNUNET_OS_process_destroy (d->proc_arm_peerinfo); + d->proc_arm_peerinfo = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, _("Failed to get hostkey!\n")); + return; + } + d->shortname = GNUNET_strdup (GNUNET_i2s (&d->id)); + GNUNET_DISK_pipe_close (d->pipe_stdout); + d->pipe_stdout = NULL; + (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); + GNUNET_OS_process_destroy (d->proc_arm_peerinfo); + d->proc_arm_peerinfo = NULL; + d->have_hostkey = GNUNET_YES; + if (d->hostkey_callback != NULL) + { + d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); + d->hostkey_callback = NULL; + d->phase = SP_HOSTKEY_CREATED; + } + else + { + d->phase = SP_TOPOLOGY_SETUP; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully got hostkey!\n"); + /* Fall through */ + case SP_HOSTKEY_CREATED: + /* wait for topology finished */ + if ((GNUNET_YES == d->dead) || + (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + _("`Failed while waiting for topology setup!\n")); + return; + } + + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + break; + case SP_TOPOLOGY_SETUP: /* Indicates topology setup has completed! */ + /* start GNUnet on remote host */ + if (NULL == d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting `%s', with command `%s %s %s %s'.\n", + "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, + "-s"); + d->proc_arm_start = + GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", + d->cfgfile, + "-s", "-q", "-T", + GNUNET_TIME_relative_to_string + (GNUNET_TIME_absolute_get_remaining + (d->max_timeout)), NULL); + } + else + { + if (d->username != NULL) + GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); + else + dst = GNUNET_strdup (d->hostname); + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Starting `%s', with command `%s %s %s %s %s %s %s'.\n", + "gnunet-arm", "ssh", dst, "gnunet-arm", "-c", d->cfgfile, + "-s", "-q"); + if (d->ssh_port_str == NULL) + { + d->proc_arm_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", + "-q", + dst, "gnunet-arm", + "-c", d->cfgfile, "-s", "-q", "-T", + GNUNET_TIME_relative_to_string + (GNUNET_TIME_absolute_get_remaining + (d->max_timeout)), NULL); + } + else + { + + d->proc_arm_start = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-p", + d->ssh_port_str, + "-q", + dst, "gnunet-arm", + "-c", d->cfgfile, "-s", "-q", "-T", + GNUNET_TIME_relative_to_string + (GNUNET_TIME_absolute_get_remaining + (d->max_timeout)), NULL); + } + GNUNET_free (dst); + } + if (NULL == d->proc_arm_start) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start `%s' process to start GNUnet.\n"), + (NULL == d->hostname) ? "gnunet-arm" : "ssh"); + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("Failed to start `gnunet-arm' process.\n") : + _("Failed to start `ssh' process.\n")); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Started `%s', waiting for `%s' to be up.\n", "gnunet-arm", + "gnunet-service-core"); + d->phase = SP_START_ARMING; + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + // FIXME: busy wait? + break; + case SP_START_ARMING: + if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_start, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : + _("`ssh' does not seem to terminate.\n")); + if (d->cfg != NULL) + { + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + } + if (d->cfgfile != NULL) + { + GNUNET_free (d->cfgfile); + d->cfgfile = NULL; + } + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_OS_process_destroy (d->proc_arm_start); + d->proc_arm_start = NULL; + d->username = NULL; + d->hostname = NULL; // Quick hack to avoid crashing (testing need to be + d->cfg = NULL; // overhauled anyway, and the error managing is + // GNUNET_free (d); // FIXME (could this leak) + // pretty broken anyway. + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + // FIXME: busy wait? + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully started `%s'.\n", + "gnunet-arm"); + GNUNET_OS_process_destroy (d->proc_arm_start); + d->proc_arm_start = NULL; + d->phase = SP_START_CORE; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling CORE_connect\n"); + /* Fall through */ + case SP_START_CORE: + if (d->server != NULL) + GNUNET_CORE_disconnect (d->server); + + d->th = GNUNET_TRANSPORT_connect (d->cfg, &d->id, d, NULL, NULL, NULL); + if (d->th == NULL) + { + if (GNUNET_YES == d->dead) + GNUNET_TESTING_daemon_stop (d, + GNUNET_TIME_absolute_get_remaining + (d->max_timeout), d->dead_cb, + d->dead_cb_cls, GNUNET_YES, GNUNET_NO); + else if (NULL != d->cb) + d->cb (d->cb_cls, &d->id, d->cfg, d, + _("Failed to connect to transport service!\n")); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected to transport service `%s', getting HELLO\n", + GNUNET_i2s (&d->id)); + d->ghh = GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d); + /* FIXME: store task ID somewhere! */ + GNUNET_SCHEDULER_add_now (¬ify_daemon_started, d); + /*cb = d->cb; + * d->cb = NULL; + * if (NULL != cb) + * cb (d->cb_cls, &d->id, d->cfg, d, NULL); */ + d->running = GNUNET_YES; + d->phase = SP_GET_HELLO; + break; + case SP_GET_HELLO: + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + if (d->server != NULL) + GNUNET_CORE_disconnect (d->server); + if (d->th != NULL) + GNUNET_TRANSPORT_disconnect (d->th); + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, _("Unable to get HELLO for peer!\n")); + GNUNET_CONFIGURATION_destroy (d->cfg); + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free (d); + return; + } + if (d->hello != NULL) + return; + GNUNET_assert (d->task == GNUNET_SCHEDULER_NO_TASK); + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_CONSTANTS_SERVICE_RETRY, 2), + &start_fsm, d); + break; + case SP_START_DONE: + GNUNET_break (0); + break; + case SP_SERVICE_START: + /* confirm gnunet-arm exited */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_start, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : + _("`ssh' does not seem to terminate.\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } +#if EXTRA_CHECKS + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + (NULL == + d->hostname) ? + _ + ("`gnunet-arm' terminated with non-zero exit status (or timed out)!\n") + : _("`ssh' does not seem to terminate.\n")); + return; + } +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service startup complete!\n"); + cb = d->cb; + d->cb = NULL; + d->phase = SP_START_DONE; + if (NULL != cb) + cb (d->cb_cls, &d->id, d->cfg, d, NULL); + GNUNET_OS_process_destroy (d->proc_arm_srv_start); + d->proc_arm_srv_start = NULL; + break; + case SP_SERVICE_SHUTDOWN_START: + /* confirm copying complete */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_stop, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } +#if EXTRA_CHECKS + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); + return; + } +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, NULL); + break; + case SP_SHUTDOWN_START: + /* confirm copying complete !??? */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_stop, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + if (d->cfg != NULL) + { + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + } + if (d->cfgfile != NULL) + { + GNUNET_free (d->cfgfile); + d->cfgfile = NULL; + } + GNUNET_free_non_null (d->hello); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free_non_null (d->shortname); + GNUNET_OS_process_destroy (d->proc_arm_stop); + d->proc_arm_stop = NULL; + GNUNET_free (d); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, + _ + ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hello); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + GNUNET_free_non_null (d->shortname); + GNUNET_OS_process_destroy (d->proc_arm_stop); + d->proc_arm_stop = NULL; + GNUNET_free (d); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n"); + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, NULL); + + /* state clean up and notifications */ + if (d->churn == GNUNET_NO) + { + GNUNET_CONFIGURATION_destroy (d->cfg); + d->cfg = NULL; + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + } + + GNUNET_free_non_null (d->hello); + d->hello = NULL; + GNUNET_free_non_null (d->shortname); + GNUNET_OS_process_destroy (d->proc_arm_stop); + d->proc_arm_stop = NULL; + d->shortname = NULL; + if (d->churn == GNUNET_NO) + GNUNET_free (d); + + break; + case SP_CONFIG_UPDATE: + /* confirm copying complete */ + if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) + { + if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) /* FIXME: config update should take timeout parameter! */ + { + cb = d->cb; + d->cb = NULL; + if (NULL != cb) + cb (d->cb_cls, NULL, d->cfg, d, + _("`scp' does not seem to terminate.\n")); + return; + } + /* wait some more */ + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + d); + return; + } + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + { + if (NULL != d->update_cb) + d->update_cb (d->update_cb_cls, _("`scp' did not complete cleanly.\n")); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully copied configuration file.\n"); + if (NULL != d->update_cb) + d->update_cb (d->update_cb_cls, NULL); + d->phase = SP_START_DONE; + break; + } +} + +/** + * Continues GNUnet daemon startup when user wanted to be notified + * once a hostkey was generated (for creating friends files, blacklists, + * etc.). + * + * @param daemon the daemon to finish starting + */ +void +GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon) +{ + GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED); + daemon->phase = SP_TOPOLOGY_SETUP; +} + +/** + * Check whether the given daemon is running. + * + * @param daemon the daemon to check + * + * @return GNUNET_YES if the daemon is up, GNUNET_NO if the + * daemon is down, GNUNET_SYSERR on error. + */ +int +GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon) +{ + if (daemon == NULL) + return GNUNET_SYSERR; + + if (daemon->running == GNUNET_YES) + return GNUNET_YES; + return GNUNET_NO; +} + + +/** + * Starts a GNUnet daemon service which has been previously stopped. + * + * @param d the daemon for which the service should be started + * @param service the name of the service to start + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the service starts + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d, + char *service, + struct GNUNET_TIME_Relative + timeout, + GNUNET_TESTING_NotifyDaemonRunning + cb, void *cb_cls) +{ + char *arg; + + d->cb = cb; + d->cb_cls = cb_cls; + + GNUNET_assert (d->running == GNUNET_YES); + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + + if (d->churned_services == NULL) + { + d->cb (d->cb_cls, &d->id, d->cfg, d, + "No service has been churned off yet!!"); + return; + } + d->phase = SP_SERVICE_START; + GNUNET_free (d->churned_services); + d->churned_services = NULL; + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", + "-q", + arg, "gnunet-arm", + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q\n", + arg, "gnunet-arm", d->cfgfile, service); + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + } + + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + +/** + * Starts a GNUnet daemon's service. + * + * @param d the daemon for which the service should be started + * @param service the name of the service to start + * @param timeout how long to wait for process for startup + * @param cb function called once gnunet-arm returns + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d, + const char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + char *arg; + + d->cb = cb; + d->cb_cls = cb_cls; + + GNUNET_assert (service != NULL); + GNUNET_assert (d->running == GNUNET_YES); + GNUNET_assert (d->phase == SP_START_DONE); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Starting service %s for peer `%4s'\n"), service, + GNUNET_i2s (&d->id)); + d->phase = SP_SERVICE_START; + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", + "-q", + arg, "gnunet-arm", + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q -T %s\n", + arg, "gnunet-arm", d->cfgfile, service, + GNUNET_TIME_relative_to_string (timeout)); + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", + "-c", d->cfgfile, "-i", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting gnunet-arm with command %s -c %s -i %s -q -T %s\n", + "gnunet-arm", d->cfgfile, service, + GNUNET_TIME_relative_to_string (timeout)); + } + + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + +/** + * Start a peer that has previously been stopped using the daemon_stop + * call (and files weren't deleted and the allow restart flag) + * + * @param daemon the daemon to start (has been previously stopped) + * @param timeout how long to wait for restart + * @param cb the callback for notification when the peer is running + * @param cb_cls closure for the callback + */ +void +GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + if (daemon->running == GNUNET_YES) + { + cb (cb_cls, &daemon->id, daemon->cfg, daemon, + "Daemon already running, can't restart!"); + return; + } + + daemon->cb = cb; + daemon->cb_cls = cb_cls; + daemon->phase = SP_TOPOLOGY_SETUP; + daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* FIXME: why add_continuation? */ + GNUNET_SCHEDULER_add_continuation (&start_fsm, daemon, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); +} + +/** + * Starts a GNUnet daemon. GNUnet must be installed on the target + * system and available in the PATH. The machine must furthermore be + * reachable via "ssh" (unless the hostname is "NULL") without the + * need to enter a password. + * + * @param cfg configuration to use + * @param timeout how long to wait starting up peers + * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO + * to really start the peer (default) + * @param hostname name of the machine where to run GNUnet + * (use NULL for localhost). + * @param ssh_username ssh username to use when connecting to hostname + * @param sshport port to pass to ssh process when connecting to hostname + * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) + * @param hostkey_callback function to call once the hostkey has been + * generated for this peer, but it hasn't yet been started + * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) + * @param hostkey_cls closure for hostkey callback + * @param cb function to call once peer is up, or failed to start + * @param cb_cls closure for cb + * @return handle to the daemon (actual start will be completed asynchronously) + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Relative timeout, int pretend, + const char *hostname, const char *ssh_username, + uint16_t sshport, const char *hostkey, + GNUNET_TESTING_NotifyHostkeyCreated + hostkey_callback, void *hostkey_cls, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + struct GNUNET_TESTING_Daemon *ret; + char *arg; + char *username; + char *servicehome; + char *baseservicehome; + char *slash; + char *hostkeyfile; + char *temp_file_name; + struct GNUNET_DISK_FileHandle *fn; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; + struct GNUNET_CRYPTO_RsaPrivateKey *private_key; + + ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon)); + ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname); + if (sshport != 0) + { + GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport); + } + else + ret->ssh_port_str = NULL; + + /* Find service home and base service home directories, create it if it doesn't exist */ + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", + "SERVICEHOME", + &servicehome)); + + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome)); + GNUNET_asprintf (&temp_file_name, "%s/gnunet-testing-config", servicehome); + ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name); + GNUNET_free (temp_file_name); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Setting up peer with configuration file `%s'.\n", ret->cfgfile); + if (NULL == ret->cfgfile) + { + GNUNET_free_non_null (ret->ssh_port_str); + GNUNET_free_non_null (ret->hostname); + GNUNET_free (ret); + return NULL; + } + ret->hostkey_callback = hostkey_callback; + ret->hostkey_cls = hostkey_cls; + ret->cb = cb; + ret->cb_cls = cb_cls; + ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + ret->cfg = GNUNET_CONFIGURATION_dup (cfg); + GNUNET_CONFIGURATION_set_value_string (ret->cfg, "PATHS", "DEFAULTCONFIG", + ret->cfgfile); + + if (hostkey != NULL) /* Get the peer identity from the hostkey */ + { + private_key = GNUNET_CRYPTO_rsa_decode_key (hostkey, HOSTKEYFILESIZE); + GNUNET_assert (private_key != NULL); + GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key); + GNUNET_CRYPTO_hash (&public_key, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &ret->id.hashPubKey); + ret->shortname = GNUNET_strdup (GNUNET_i2s (&ret->id)); + ret->have_hostkey = GNUNET_YES; + GNUNET_CRYPTO_rsa_key_free (private_key); + } + + /* Write hostkey to file, if we were given one */ + hostkeyfile = NULL; + if (hostkey != NULL) + { + GNUNET_asprintf (&hostkeyfile, "%s/.hostkey", servicehome); + fn = GNUNET_DISK_file_open (hostkeyfile, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + GNUNET_assert (fn != NULL); + GNUNET_assert (HOSTKEYFILESIZE == + GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE)); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn)); + } + + /* write configuration to temporary file */ + if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile)) + { + if (0 != UNLINK (ret->cfgfile)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + ret->cfgfile); + GNUNET_CONFIGURATION_destroy (ret->cfg); + GNUNET_free_non_null (ret->hostname); + GNUNET_free (ret->cfgfile); + GNUNET_free (ret); + return NULL; + } + if (ssh_username != NULL) + username = GNUNET_strdup (ssh_username); + if ((ssh_username == NULL) && + (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING_OLD", "USERNAME", + &username))) + { + if (NULL != getenv ("USER")) + username = GNUNET_strdup (getenv ("USER")); + else + username = NULL; + } + ret->username = username; + + if (GNUNET_NO == pretend) /* Copy files, enter finite state machine */ + { + /* copy directory to remote host */ + if (NULL != hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying configuration directory to host `%s'.\n", hostname); + baseservicehome = GNUNET_strdup (servicehome); + /* Remove trailing /'s */ + while (baseservicehome[strlen (baseservicehome) - 1] == '/') + baseservicehome[strlen (baseservicehome) - 1] = '\0'; + /* Find next directory /, jump one ahead */ + slash = strrchr (baseservicehome, '/'); + if (slash != NULL) + *(++slash) = '\0'; + + ret->phase = SP_COPYING; + if (NULL != username) + GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome); + else + GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome); + GNUNET_free (baseservicehome); + if (ret->ssh_port_str == NULL) + { + ret->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", + "-q", + servicehome, arg, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "copying directory with command scp -r %s %s\n", + servicehome, arg); + } + else + { + ret->proc_arm_copying = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", "-P", + ret->ssh_port_str, + "-q", + servicehome, arg, NULL); + } + GNUNET_free (arg); + if (NULL == ret->proc_arm_copying) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Could not start `%s' process to copy configuration directory.\n"), + "scp"); + if (0 != UNLINK (ret->cfgfile)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + ret->cfgfile); + GNUNET_CONFIGURATION_destroy (ret->cfg); + GNUNET_free_non_null (ret->hostname); + GNUNET_free_non_null (ret->username); + GNUNET_free (ret->cfgfile); + GNUNET_free (ret); + if ((hostkey != NULL) && (0 != UNLINK (hostkeyfile))) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", + hostkeyfile); + GNUNET_free_non_null (hostkeyfile); + GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome)); + GNUNET_free (servicehome); + return NULL; + } + + ret->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, + ret); + GNUNET_free_non_null (hostkeyfile); + GNUNET_free (servicehome); + return ret; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "No need to copy configuration file since we are running locally.\n"); + ret->phase = SP_COPIED; + /* FIXME: why add_cont? */ + GNUNET_SCHEDULER_add_continuation (&start_fsm, ret, + GNUNET_SCHEDULER_REASON_PREREQ_DONE); + } + GNUNET_free_non_null (hostkeyfile); + GNUNET_free (servicehome); + return ret; +} + + +/** + * Restart (stop and start) a GNUnet daemon. + * + * @param d the daemon that should be restarted + * @param cb function called once the daemon is (re)started + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls) +{ + char *arg; + char *del_arg; + + del_arg = NULL; + if (NULL != d->cb) + { + d->dead = GNUNET_YES; + return; + } + + d->cb = cb; + d->cb_cls = cb_cls; + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + /* state clean up and notifications */ + GNUNET_free_non_null (d->hello); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), + GNUNET_i2s (&d->id)); + d->phase = SP_START_ARMING; + + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", + "-q", + arg, "gnunet-arm", + "-c", d->cfgfile, "-e", "-r", NULL); + /* Use -r to restart arm and all services */ + + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", + "-c", d->cfgfile, "-e", "-r", NULL); + } + + GNUNET_free_non_null (del_arg); + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); + +} + + +/** + * Stops a GNUnet daemon. + * + * @param d the daemon that should be stopped + * @param service the name of the service to stop + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the daemon was stopped + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d, + const char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls) +{ + char *arg; + + d->dead_cb = cb; + d->dead_cb_cls = cb_cls; + + GNUNET_assert (d->running == GNUNET_YES); + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), + GNUNET_i2s (&d->id)); + if (d->churned_services != NULL) + { + d->dead_cb (d->dead_cb_cls, "A service has already been turned off!!"); + return; + } + d->phase = SP_SERVICE_SHUTDOWN_START; + d->churned_services = GNUNET_strdup (service); + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + /* Check if this is a local or remote process */ + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", + "-q", + arg, "gnunet-arm", + "-c", d->cfgfile, "-k", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n", + arg, "gnunet-arm", d->cfgfile, service); + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", + "-c", d->cfgfile, "-k", service, "-q", + "-T", + GNUNET_TIME_relative_to_string (timeout), + NULL); + } + + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + + +/** + * Forcefully terminate a process and clean up the child. + * + * @param proc handle to process to kill + */ +static void +kill_and_close_process (struct GNUNET_OS_Process *proc) +{ + (void) GNUNET_OS_process_kill (proc, SIGKILL); + GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); + GNUNET_OS_process_destroy (proc); +} + + +/** + * Stops a GNUnet daemon. + * + * @param d the daemon that should be stopped + * @param timeout how long to wait for process for shutdown to complete + * @param cb function called once the daemon was stopped + * @param cb_cls closure for cb + * @param delete_files GNUNET_YES to remove files, GNUNET_NO + * to leave them + * @param allow_restart GNUNET_YES to restart peer later (using this API) + * GNUNET_NO to kill off and clean up for good + */ +void +GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, + int delete_files, int allow_restart) +{ + char *arg; + char *del_arg; + + d->dead_cb = cb; + d->dead_cb_cls = cb_cls; + + if (NULL != d->cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Setting d->dead on peer `%4s'\n"), + GNUNET_i2s (&d->id)); + d->dead = GNUNET_YES; + return; + } + if (NULL != d->proc_arm_start) + { + kill_and_close_process (d->proc_arm_start); + d->proc_arm_start = NULL; + } + if (NULL != d->proc_arm_srv_start) + { + kill_and_close_process (d->proc_arm_srv_start); + d->proc_arm_srv_start = NULL; + } + if (NULL != d->proc_arm_srv_stop) + { + kill_and_close_process (d->proc_arm_srv_stop); + d->proc_arm_srv_stop = NULL; + } + if (NULL != d->proc_arm_copying) + { + kill_and_close_process (d->proc_arm_copying); + d->proc_arm_copying = NULL; + } + if (NULL != d->proc_arm_peerinfo) + { + kill_and_close_process (d->proc_arm_peerinfo); + d->proc_arm_peerinfo = NULL; + } + if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES)) + { + /* Peer has already been stopped in churn context! + * Free what was left from churning! */ + GNUNET_assert (d->cfg != NULL); + GNUNET_CONFIGURATION_destroy (d->cfg); + if (delete_files == GNUNET_YES) + { + if (0 != UNLINK (d->cfgfile)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink"); + } + } + GNUNET_free (d->cfgfile); + GNUNET_free_non_null (d->hostname); + GNUNET_free_non_null (d->username); + if (NULL != d->dead_cb) + d->dead_cb (d->dead_cb_cls, NULL); + /* FIXME: this should be an assert and the test below + should not be required, but testing is broken... */ + GNUNET_break (NULL == d->proc_arm_stop); + if (NULL == d->proc_arm_stop) + GNUNET_free (d); + return; + } + + del_arg = NULL; + if (delete_files == GNUNET_YES) + { + GNUNET_asprintf (&del_arg, "-d"); + } + + if (d->phase == SP_CONFIG_UPDATE) + { + GNUNET_SCHEDULER_cancel (d->task); + d->phase = SP_START_DONE; + } + /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop? + if (d->server != NULL) + { + GNUNET_CORE_disconnect (d->server); + d->server = NULL; + } + */ + /* shutdown ARM process (will terminate others) */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminating peer `%4s'\n" , + GNUNET_i2s (&d->id)); + d->phase = SP_SHUTDOWN_START; + d->running = GNUNET_NO; + if (allow_restart == GNUNET_YES) + d->churn = GNUNET_YES; + if (d->th != NULL) + { + GNUNET_TRANSPORT_get_hello_cancel (d->ghh); + d->ghh = NULL; + GNUNET_TRANSPORT_disconnect (d->th); + d->th = NULL; + } + /* Check if this is a local or remote process */ + + + if (NULL != d->hostname) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' on host `%s'.\n", + d->cfgfile, d->hostname); + if (d->username != NULL) + GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); + else + arg = GNUNET_strdup (d->hostname); + + d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", + "-q", + arg, "gnunet-arm", + "-c", d->cfgfile, "-e", "-q", "-T", + GNUNET_TIME_relative_to_string (timeout), + del_arg, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n", + arg, "gnunet-arm", d->cfgfile, del_arg); + /* Use -e to end arm, and -d to remove temp files */ + GNUNET_free (arg); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); + d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "gnunet-arm", "gnunet-arm", + "-c", d->cfgfile, "-e", "-q", "-T", + GNUNET_TIME_relative_to_string (timeout), + del_arg, NULL); + GNUNET_assert (NULL != d->proc_arm_stop); + } + + GNUNET_free_non_null (del_arg); + d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (GNUNET_SCHEDULER_NO_TASK != d->task) + GNUNET_SCHEDULER_cancel(d->task); + d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); +} + + +/** + * Changes the configuration of a GNUnet daemon. + * + * @param d the daemon that should be modified + * @param cfg the new configuration for the daemon + * @param cb function called once the configuration was changed + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, + struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls) +{ + char *arg; + + if (d->phase != SP_START_DONE) + { + if (NULL != cb) + cb (cb_cls, + _ + ("Peer not yet running, can not change configuration at this point.")); + return; + } + + /* 1) write configuration to temporary file */ + if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile)) + { + if (NULL != cb) + cb (cb_cls, _("Failed to write new configuration to disk.")); + return; + } + + /* 2) copy file to remote host (if necessary) */ + if (NULL == d->hostname) + { + /* signal success */ + if (NULL != cb) + cb (cb_cls, NULL); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying updated configuration file to remote host `%s'.\n", + d->hostname); + d->phase = SP_CONFIG_UPDATE; + if (NULL != d->username) + GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile); + else + GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile); + d->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", + "-q", + d->cfgfile, arg, NULL); + GNUNET_free (arg); + if (NULL == d->proc_arm_copying) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not start `%s' process to copy configuration file.\n"), + "scp"); + if (NULL != cb) + cb (cb_cls, _("Failed to copy new configuration to remote machine.")); + d->phase = SP_START_DONE; + return; + } + d->update_cb = cb; + d->update_cb_cls = cb_cls; + d->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); +} + + +/** + * Data kept for each pair of peers that we try + * to connect. + */ +struct GNUNET_TESTING_ConnectContext +{ + /** + * Testing handle to the first daemon. + */ + struct GNUNET_TESTING_Daemon *d1; + + /** + * Handle to core of first daemon (to check connect) + */ + struct GNUNET_CORE_Handle *d1core; + + /** + * Have we actually connected to the core of the first daemon yet? + */ + int d1core_ready; + + /** + * Testing handle to the second daemon. + */ + struct GNUNET_TESTING_Daemon *d2; + + /** + * Transport handle to the first daemon (to offer the HELLO of the second daemon to). + */ + struct GNUNET_TRANSPORT_Handle *d1th; + + /** + * Function to call once we are done (or have timed out). + */ + GNUNET_TESTING_NotifyConnection cb; + + /** + * Closure for "nb". + */ + void *cb_cls; + + /** + * The relative timeout from whence this connect attempt was + * started. Allows for reconnect attempts. + */ + struct GNUNET_TIME_Relative relative_timeout; + + /** + * Maximum number of connect attempts, will retry connection + * this number of times on failures. + */ + unsigned int connect_attempts; + + /** + * Hello timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier hello_send_task; + + /** + * Connect timeout task + */ + GNUNET_SCHEDULER_TaskIdentifier timeout_task; + + /** + * When should this operation be complete (or we must trigger + * a timeout). + */ + struct GNUNET_TIME_Relative timeout_hello; + + /** + * Was the connection attempt successful? + */ + int connected; + + /** + * When connecting, do we need to send the HELLO? + */ + int send_hello; + + /** + * The distance between the two connected peers + */ + uint32_t distance; +}; + + +/** Forward declaration **/ +static void +reattempt_daemons_connect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Notify callback about success or failure of the attempt + * to connect the two peers + * + * @param cls our "struct GNUNET_TESTING_ConnectContext" (freed) + * @param tc reason tells us if we succeeded or failed + */ +static void +notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + } + + if (ctx->d1th != NULL) + GNUNET_TRANSPORT_disconnect (ctx->d1th); + ctx->d1th = NULL; + if (ctx->d1core != NULL) + GNUNET_CORE_disconnect (ctx->d1core); + ctx->d1core = NULL; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + GNUNET_free (ctx); + return; + } + + if (ctx->connected == GNUNET_YES) + { + if (ctx->cb != NULL) + { + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->distance, + ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL); + } + } + else if (ctx->connect_attempts > 0) + { + ctx->d1core_ready = GNUNET_NO; + ctx->timeout_task = + GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx); + return; + } + else + { + if (ctx->cb != NULL) + { + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, _("Peers failed to connect")); + } + } + GNUNET_free (ctx); +} + + +/** + * Success, connection is up. Signal client our success. + * + * @param cls our "struct GNUNET_TESTING_ConnectContext" + * @param peer identity of the peer that has connected + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * + */ +static void +connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", + ctx->d1->shortname, GNUNET_i2s (peer)); + if (0 != memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))) + return; + ctx->connected = GNUNET_YES; + ctx->distance = 0; /* FIXME: distance */ + if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_SCHEDULER_cancel (ctx->timeout_task); + ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); +} + + +static void +send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + struct GNUNET_MessageHeader *hello; + + ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL) && + (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)) && + (ctx->d1->phase == SP_START_DONE) && (ctx->d2->phase == SP_START_DONE)) + { + hello = GNUNET_HELLO_get_header (ctx->d2->hello); + GNUNET_assert (hello != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n", + ctx->d2->shortname, ctx->d1->shortname); + GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL); + GNUNET_assert (ctx->d1core != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending connect request to TRANSPORT of %s for peer %s\n", + GNUNET_i2s (&ctx->d1->id), + GNUNET_h2s (&ctx->d2->id.hashPubKey)); + GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); + ctx->timeout_hello = + GNUNET_TIME_relative_add (ctx->timeout_hello, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 500)); + } + ctx->hello_send_task = + GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello, &send_hello, ctx); +} + +/** + * Notify of a successful connection to the core service. + * + * @param cls a ConnectContext + * @param server handle to the core service + * @param my_identity the peer identity of this peer + */ +void +core_init_notify (void *cls, struct GNUNET_CORE_Handle *server, + const struct GNUNET_PeerIdentity *my_identity) +{ + struct GNUNET_TESTING_ConnectContext *connect_ctx = cls; + + connect_ctx->d1core_ready = GNUNET_YES; + + if (connect_ctx->send_hello == GNUNET_NO) + { + GNUNET_TRANSPORT_try_connect (connect_ctx->d1th, &connect_ctx->d2->id); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending connect request to TRANSPORT of %s for peer %s\n", + connect_ctx->d1->shortname, connect_ctx->d2->shortname); + } +} + + +/** + * Try to connect again some peers that failed in an earlier attempt. This will + * be tried as many times as connection_attempts in the configuration file. + * + * @param cls Closure (connection context between the two peers). + * @param tc TaskContext. + */ +static void +reattempt_daemons_connect (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "re-attempting connect of peer %s to peer %s\n", + ctx->d1->shortname, ctx->d2->shortname); + ctx->connect_attempts--; + GNUNET_assert (ctx->d1core == NULL); + ctx->d1core_ready = GNUNET_NO; + ctx->d1core = + GNUNET_CORE_connect (ctx->d1->cfg, ctx, &core_init_notify, + &connect_notify, NULL, NULL, GNUNET_NO, NULL, + GNUNET_NO, no_handlers); + if (ctx->d1core == NULL) + { + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to core service of first peer!\n")); + GNUNET_free (ctx); + return; + } + + /* Don't know reason for initial connect failure, update the HELLO for the second peer */ + if (NULL != ctx->d2->hello) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "updating %s's HELLO\n", + ctx->d2->shortname); + GNUNET_free (ctx->d2->hello); + ctx->d2->hello = NULL; + if (NULL != ctx->d2->th) + { + GNUNET_TRANSPORT_get_hello_cancel (ctx->d2->ghh); + ctx->d2->ghh = NULL; + GNUNET_TRANSPORT_disconnect (ctx->d2->th); + } + ctx->d2->th = + GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, + NULL); + GNUNET_assert (ctx->d2->th != NULL); + ctx->d2->ghh = + GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "didn't have %s's HELLO\n", + ctx->d2->shortname); + } + + if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "didn't have %s's HELLO, trying to get it now\n", + ctx->d2->shortname); + ctx->d2->th = + GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, + NULL); + if (NULL == ctx->d2->th) + { + GNUNET_CORE_disconnect (ctx->d1core); + GNUNET_free (ctx); + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to transport service!\n")); + return; + } + ctx->d2->ghh = + GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); + } + else + { + if (NULL == ctx->d2->hello) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "didn't have %s's HELLO but th wasn't NULL, not trying!!\n", + ctx->d2->shortname); + } + } + + if (ctx->send_hello == GNUNET_YES) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %s's HELLO to %s\n", + ctx->d1->shortname, ctx->d2->shortname); + ctx->d1th = + GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, + NULL, NULL); + if (ctx->d1th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + GNUNET_free (ctx); + if (NULL != ctx->cb) + ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, + ctx->d2->cfg, ctx->d1, ctx->d2, + _("Failed to connect to transport service!\n")); + return; + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to reconnect %s to %s\n", + ctx->d1->shortname, ctx->d2->shortname); + GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); + } + ctx->timeout_task = + GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, + ¬ify_connect_result, ctx); +} + +/** + * Iterator for currently known peers, to ensure + * that we don't try to send duplicate connect + * requests to core. + * + * @param cls our "struct GNUNET_TESTING_ConnectContext" + * @param peer identity of the peer that has connected, + * NULL when iteration has finished + * @param atsi performance information + * @param atsi_count number of records in 'atsi' + * + */ +static void +core_initial_iteration (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct GNUNET_TESTING_ConnectContext *ctx = cls; + + if ((peer != NULL) && + (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))) + { + ctx->connected = GNUNET_YES; + ctx->distance = 0; /* FIXME: distance */ + return; + } + if (peer != NULL) + return; /* ignore other peers */ + /* peer == NULL: End of iteration over peers */ + + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->timeout_task); + if (ctx->connected == GNUNET_YES) + { + ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + + /* Peer not already connected, need to schedule connect request! */ + if (ctx->d1core == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Peers are NOT connected, connecting to core!\n"); + ctx->d1core = + GNUNET_CORE_connect (ctx->d1->cfg, ctx, &core_init_notify, + &connect_notify, NULL, NULL, GNUNET_NO, NULL, + GNUNET_NO, no_handlers); + } + + if (ctx->d1core == NULL) + { + ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + + if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) /* Do not yet have the second peer's hello, set up a task to get it */ + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Don't have d2's HELLO, trying to get it!\n"); + ctx->d2->th = + GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, + NULL); + if (ctx->d2->th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + ctx->d1core = NULL; + ctx->timeout_task = + GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + ctx->d2->ghh = + GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); + } + + if (ctx->send_hello == GNUNET_YES) + { + ctx->d1th = + GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, + NULL, NULL); + if (ctx->d1th == NULL) + { + GNUNET_CORE_disconnect (ctx->d1core); + ctx->d1core = NULL; + ctx->timeout_task = + GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); + return; + } + GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); + ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); + } + + ctx->timeout_task = + GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, + ¬ify_connect_result, ctx); + +} + + +/** + * Establish a connection between two GNUnet daemons. The daemons + * must both be running and not be stopped until either the + * 'cb' callback is called OR the connection request has been + * explicitly cancelled. + * + * @param d1 handle for the first daemon + * @param d2 handle for the second daemon + * @param timeout how long is the connection attempt + * allowed to take? + * @param max_connect_attempts how many times should we try to reconnect + * (within timeout) + * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume + * the HELLO has already been exchanged + * @param cb function to call at the end + * @param cb_cls closure for cb + * @return handle to cancel the request + */ +struct GNUNET_TESTING_ConnectContext * +GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, + struct GNUNET_TESTING_Daemon *d2, + struct GNUNET_TIME_Relative timeout, + unsigned int max_connect_attempts, + int send_hello, + GNUNET_TESTING_NotifyConnection cb, + void *cb_cls) +{ + struct GNUNET_TESTING_ConnectContext *ctx; + + if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO)) + { + if (NULL != cb) + cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2, + _("Peers are not fully running yet, can not connect!\n")); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n"); + return NULL; + } + + ctx = GNUNET_malloc (sizeof (struct GNUNET_TESTING_ConnectContext)); + ctx->d1 = d1; + ctx->d2 = d2; + ctx->timeout_hello = + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500); + ctx->relative_timeout = + GNUNET_TIME_relative_divide (timeout, max_connect_attempts); + ctx->cb = cb; + ctx->cb_cls = cb_cls; + ctx->connect_attempts = max_connect_attempts; + ctx->connected = GNUNET_NO; + ctx->send_hello = send_hello; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n", + d1->shortname, d2->shortname); + /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */ + GNUNET_assert (NULL != + GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, + &core_initial_iteration, ctx)); + return ctx; +} + + +/** + * Cancel an attempt to connect two daemons. + * + * @param cc connect context + */ +void +GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext *cc) +{ + if (GNUNET_SCHEDULER_NO_TASK != cc->timeout_task) + { + GNUNET_SCHEDULER_cancel (cc->timeout_task); + cc->timeout_task = GNUNET_SCHEDULER_NO_TASK; + } + if (GNUNET_SCHEDULER_NO_TASK != cc->hello_send_task) + { + GNUNET_SCHEDULER_cancel (cc->hello_send_task); + cc->hello_send_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != cc->d1core) + { + GNUNET_CORE_disconnect (cc->d1core); + cc->d1core = NULL; + } + if (NULL != cc->d1th) + { + GNUNET_TRANSPORT_disconnect (cc->d1th); + cc->d1th = NULL; + } + GNUNET_free (cc); +} + + +/* end of testing.c */ diff --git a/src/testing_old/testing.conf b/src/testing_old/testing.conf new file mode 100644 index 000000000..7e25f8c13 --- /dev/null +++ b/src/testing_old/testing.conf @@ -0,0 +1,11 @@ +[TESTING] +# How long before failing a connection? +CONNECT_TIMEOUT = 30 s +# How many connect attempts should we make? +CONNECT_ATTEMPTS = 3 +# How many connections can happen simultaneously? +MAX_OUTSTANDING_CONNECTIONS = 50 + +# Should we clean up the files on peer group shutdown? +DELETE_FILES = YES + diff --git a/src/testing_old/testing_group.c b/src/testing_old/testing_group.c new file mode 100644 index 000000000..3ba7c5cce --- /dev/null +++ b/src/testing_old/testing_group.c @@ -0,0 +1,7038 @@ +/* + This file is part of GNUnet + (C) 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 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 testing/testing_group.c + * @brief convenience API for writing testcases for GNUnet + * @author Nathan Evans + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" + +#define USE_START_HELPER GNUNET_YES + +#define OLD 1 + +/* Before connecting peers, send all of the HELLOs */ +#define USE_SEND_HELLOS GNUNET_NO + +#define TOPOLOGY_HACK GNUNET_YES + + +/** + * Lowest port used for GNUnet testing. Should be high enough to not + * conflict with other applications running on the hosts but be low + * enough to not conflict with client-ports (typically starting around + * 32k). + */ +#define LOW_PORT 12000 + +/** + * Highest port used for GNUnet testing. Should be low enough to not + * conflict with the port range for "local" ports (client apps; see + * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). + */ +#define HIGH_PORT 56000 + +/* Maximum time to delay connect attempt */ +#define MAX_CONNECT_DELAY 300 + +/** + * Which list of peers do we need to modify? + */ +enum PeerLists +{ + /** Modify allowed peers */ + ALLOWED, + + /** Modify connect peers */ + CONNECT, + + /** Modify blacklist peers */ + BLACKLIST, + + /** Modify workingset peers */ + WORKING_SET +}; + +/** + * Prototype of a function called whenever two peers would be connected + * in a certain topology. + */ +typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct + GNUNET_TESTING_PeerGroup + * pg, + unsigned int first, + unsigned int second, + enum PeerLists list, + unsigned int check); + +/** + * Context for handling churning a peer group + */ +struct ChurnContext +{ + /** + * The peergroup we are dealing with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Name of the service to churn on/off, NULL + * to churn entire peer. + */ + char *service; + + /** + * Callback used to notify of churning finished + */ + GNUNET_TESTING_NotifyCompletion cb; + + /** + * Closure for callback + */ + void *cb_cls; + + /** + * Number of peers that still need to be started + */ + unsigned int num_to_start; + + /** + * Number of peers that still need to be stopped + */ + unsigned int num_to_stop; + + /** + * Number of peers that failed to start + */ + unsigned int num_failed_start; + + /** + * Number of peers that failed to stop + */ + unsigned int num_failed_stop; +}; + +struct RestartContext +{ + /** + * The group of peers being restarted + */ + struct GNUNET_TESTING_PeerGroup *peer_group; + + /** + * How many peers have been restarted thus far + */ + unsigned int peers_restarted; + + /** + * How many peers got an error when restarting + */ + unsigned int peers_restart_failed; + + /** + * The function to call once all peers have been restarted + */ + GNUNET_TESTING_NotifyCompletion callback; + + /** + * Closure for callback function + */ + void *callback_cls; + +}; + +struct SendHelloContext +{ + /** + * Global handle to the peer group. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * The data about this specific peer. + */ + struct PeerData *peer; + + /** + * The next HELLO that needs sent to this peer. + */ + struct PeerConnection *peer_pos; + + /** + * Are we connected to CORE yet? + */ + unsigned int core_ready; + + /** + * How many attempts should we make for failed connections? + */ + unsigned int connect_attempts; + + /** + * Task for scheduling core connect requests to be sent. + */ + GNUNET_SCHEDULER_TaskIdentifier core_connect_task; +}; + +struct ShutdownContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + /** + * Total peers to wait for + */ + unsigned int total_peers; + + /** + * Number of peers successfully shut down + */ + unsigned int peers_down; + + /** + * Number of peers failed to shut down + */ + unsigned int peers_failed; + + /** + * Number of peers we have started shutting + * down. If too many, wait on them. + */ + unsigned int outstanding; + + /** + * Timeout for shutdown. + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Callback to call when all peers either + * shutdown or failed to shutdown + */ + GNUNET_TESTING_NotifyCompletion cb; + + /** + * Closure for cb + */ + void *cb_cls; + + /** + * Should we delete all of the files from the peers? + */ + int delete_files; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerShutdownContext +{ + /** + * Pointer to the high level shutdown context. + */ + struct ShutdownContext *shutdown_ctx; + + /** + * The daemon handle for the peer to shut down. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerRestartContext +{ + /** + * Pointer to the high level restart context. + */ + struct ChurnRestartContext *churn_restart_ctx; + + /** + * The daemon handle for the peer to shut down. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct ServiceStartContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + unsigned int remaining; + GNUNET_TESTING_NotifyCompletion cb; + unsigned int outstanding; + char *service; + struct GNUNET_TIME_Relative timeout; + void *cb_cls; +}; + +/** + * Individual shutdown context for a particular peer. + */ +struct PeerServiceStartContext +{ + /** + * Pointer to the high level start context. + */ + struct ServiceStartContext *start_ctx; + + /** + * The daemon handle for the peer to start the service on. + */ + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct CreateTopologyContext +{ + + /** + * Function to call with number of connections + */ + GNUNET_TESTING_NotifyConnections cont; + + /** + * Closure for connection notification + */ + void *cls; +}; + +enum States +{ + /** Waiting to read number of peers */ + NUM_PEERS, + + /** Should find next peer index */ + PEER_INDEX, + + /** Should find colon */ + COLON, + + /** Should read other peer index, space, or endline */ + OTHER_PEER_INDEX +}; + +#if OLD +struct PeerConnection +{ + /** + * Doubly Linked list + */ + struct PeerConnection *prev; + + /* + * Doubly Linked list + */ + struct PeerConnection *next; + + /* + * Index of daemon in pg->peers + */ + uint32_t index; + +}; +#endif + +struct InternalStartContext +{ + /** + * Pointer to peerdata + */ + struct PeerData *peer; + + /** + * Timeout for peer startup + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Client callback for hostkey notification + */ + GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; + + /** + * Closure for hostkey_callback + */ + void *hostkey_cls; + + /** + * Client callback for peer start notification + */ + GNUNET_TESTING_NotifyDaemonRunning start_cb; + + /** + * Closure for cb + */ + void *start_cb_cls; + + /** + * Hostname, where to start the peer + */ + const char *hostname; + + /** + * Username to use when connecting to the + * host via ssh. + */ + const char *username; + + /** + * Pointer to starting memory location of a hostkey + */ + const char *hostkey; + + /** + * Port to use for ssh. + */ + uint16_t sshport; + +}; + +struct ChurnRestartContext +{ + /** + * PeerGroup that we are working with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Number of restarts currently in flight. + */ + unsigned int outstanding; + + /** + * Handle to the underlying churn context. + */ + struct ChurnContext *churn_ctx; + + /** + * How long to allow the operation to take. + */ + struct GNUNET_TIME_Relative timeout; +}; + +struct OutstandingSSH +{ + struct OutstandingSSH *next; + + struct OutstandingSSH *prev; + + /** + * Number of current ssh connections. + */ + uint32_t outstanding; + + /** + * The hostname of this peer. + */ + const char *hostname; +}; + +/** + * Data we keep per peer. + */ +struct PeerData +{ + /** + * (Initial) configuration of the host. + * (initial because clients could change + * it and we would not know about those + * updates). + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Handle for controlling the daemon. + */ + struct GNUNET_TESTING_Daemon *daemon; + + /** + * The peergroup this peer belongs to. + */ + struct GNUNET_TESTING_PeerGroup *pg; + +#if OLD + /** + * Linked list of allowed peer connections. + */ + struct PeerConnection *allowed_peers_head; + + /** + * Linked list of allowed peer connections. + */ + struct PeerConnection *allowed_peers_tail; + + /** + * Linked list of blacklisted peer connections. + */ + struct PeerConnection *blacklisted_peers_head; + + /** + * Linked list of blacklisted peer connections. + */ + struct PeerConnection *blacklisted_peers_tail; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_head; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_tail; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_working_set_head; + + /** + * Linked list of connect peer connections. + */ + struct PeerConnection *connect_peers_working_set_tail; + +#else + /** + * Hash map of allowed peer connections (F2F created topology) + */ + struct GNUNET_CONTAINER_MultiHashMap *allowed_peers; + + /** + * Hash map of blacklisted peers + */ + struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers; + + /** + * Hash map of peer connections + */ + struct GNUNET_CONTAINER_MultiHashMap *connect_peers; + + /** + * Temporary hash map of peer connections + */ + struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set; +#endif + + /** + * Temporary variable for topology creation, should be reset before + * creating any topology so the count is valid once finished. + */ + int num_connections; + + /** + * Context to keep track of peers being started, to + * stagger hostkey generation and peer startup. + */ + struct InternalStartContext internal_context; + + /** + * Task ID for the queued internal_continue_startup task + */ + GNUNET_SCHEDULER_TaskIdentifier startup_task; + +}; + +/** + * Linked list of per-host data. + */ +struct HostData +{ + /** + * Name of the host. + */ + char *hostname; + + /** + * SSH username to use when connecting to this host. + */ + char *username; + + /** + * SSH port to use when connecting to this host. + */ + uint16_t sshport; + + /** + * Lowest port that we have not yet used + * for GNUnet. + */ + uint16_t minport; +}; + +struct TopologyIterateContext +{ + /** + * The peergroup we are working with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Callback for notifying of two connected peers. + */ + GNUNET_TESTING_NotifyTopology topology_cb; + + /** + * Closure for topology_cb + */ + void *cls; + + /** + * Number of peers currently connected to. + */ + unsigned int connected; + + /** + * Number of peers we have finished iterating. + */ + unsigned int completed; + + /** + * Number of peers total. + */ + unsigned int total; +}; + +struct StatsIterateContext +{ + /** + * The peergroup that we are dealing with. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * Continuation to call once all stats information has been retrieved. + */ + GNUNET_STATISTICS_Callback cont; + + /** + * Proc function to call on each value received. + */ + GNUNET_TESTING_STATISTICS_Iterator proc; + + /** + * Closure for topology_cb + */ + void *cls; + + /** + * Number of peers currently connected to. + */ + unsigned int connected; + + /** + * Number of peers we have finished iterating. + */ + unsigned int completed; + + /** + * Number of peers total. + */ + unsigned int total; +}; + +struct CoreContext +{ + void *iter_context; + struct GNUNET_TESTING_Daemon *daemon; +}; + +struct StatsCoreContext +{ + void *iter_context; + struct GNUNET_TESTING_Daemon *daemon; + /** + * Handle to the statistics service. + */ + struct GNUNET_STATISTICS_Handle *stats_handle; + + /** + * Handle for getting statistics. + */ + struct GNUNET_STATISTICS_GetHandle *stats_get_handle; +}; + +struct ConnectTopologyContext +{ + /** + * How many connections are left to create. + */ + unsigned int remaining_connections; + + /** + * Handle to group of peers. + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * How long to try this connection before timing out. + */ + struct GNUNET_TIME_Relative connect_timeout; + + /** + * How many times to retry connecting the two peers. + */ + unsigned int connect_attempts; + + /** + * Temp value set for each iteration. + */ + //struct PeerData *first; + + /** + * Notification that all peers are connected. + */ + GNUNET_TESTING_NotifyCompletion notify_connections_done; + + /** + * Closure for notify. + */ + void *notify_cls; +}; + +struct ConnectContext; + +/** + * Handle to a group of GNUnet peers. + */ +struct GNUNET_TESTING_PeerGroup +{ + /** + * Configuration template. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + struct ConnectContext *cc_head; + + struct ConnectContext *cc_tail; + + /** + * Function to call on each started daemon. + */ + //GNUNET_TESTING_NotifyDaemonRunning cb; + + /** + * Closure for cb. + */ + //void *cb_cls; + + /* + * Function to call on each topology connection created + */ + GNUNET_TESTING_NotifyConnection notify_connection; + + /* + * Callback for notify_connection + */ + void *notify_connection_cls; + + /** + * Array of information about hosts. + */ + struct HostData *hosts; + + /** + * Number of hosts (size of HostData) + */ + unsigned int num_hosts; + + /** + * Array of "total" peers. + */ + struct PeerData *peers; + + /** + * Number of peers in this group. + */ + unsigned int total; + + /** + * At what time should we fail the peer startup process? + */ + struct GNUNET_TIME_Absolute max_timeout; + + /** + * How many peers are being started right now? + */ + unsigned int starting; + + /** + * How many peers have already been started? + */ + unsigned int started; + + /** + * Number of possible connections to peers + * at a time. + */ + unsigned int max_outstanding_connections; + + /** + * Number of ssh connections to peers (max). + */ + unsigned int max_concurrent_ssh; + + /** + * Number of connects we are waiting on, allows us to rate limit + * connect attempts. + */ + unsigned int outstanding_connects; + + /** + * Number of HELLOs we have yet to send. + */ + unsigned int remaining_hellos; + + /** + * How many connects have already been scheduled? + */ + unsigned int total_connects_scheduled; + + /** + * Hostkeys loaded from a file. + */ + char *hostkey_data; + + /** + * Head of DLL to keep track of the number of outstanding + * ssh connections per peer. + */ + struct OutstandingSSH *ssh_head; + + /** + * Tail of DLL to keep track of the number of outstanding + * ssh connections per peer. + */ + struct OutstandingSSH *ssh_tail; + + /** + * Stop scheduling peers connecting. + */ + unsigned int stop_connects; + + /** + * Connection context for peer group. + */ + struct ConnectTopologyContext ct_ctx; +}; + +struct UpdateContext +{ + /** + * The altered configuration. + */ + struct GNUNET_CONFIGURATION_Handle *ret; + + /** + * The original configuration to alter. + */ + const struct GNUNET_CONFIGURATION_Handle *orig; + + /** + * The hostname that this peer will run on. + */ + const char *hostname; + + /** + * The next possible port to assign. + */ + unsigned int nport; + + /** + * Unique number for unix domain sockets. + */ + unsigned int upnum; + + /** + * Unique number for this peer/host to offset + * things that are grouped by host. + */ + unsigned int fdnum; +}; + +struct ConnectContext +{ + + struct ConnectContext *next; + + struct ConnectContext *prev; + + /** + * Index of peer to connect second to. + */ + uint32_t first_index; + + /** + * Index of peer to connect first to. + */ + uint32_t second_index; + + /** + * Task associated with the attempt to connect. + */ + GNUNET_SCHEDULER_TaskIdentifier task; + + /** + * Context in 'testing.c', to cancel connection attempt. + */ + struct GNUNET_TESTING_ConnectContext *cc; + + /** + * Higher level topology connection context. + */ + struct ConnectTopologyContext *ct_ctx; + + /** + * Whether this connection has been accounted for in the schedule_connect call. + */ + int counted; +}; + +struct UnblacklistContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; +}; + +struct RandomContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Random percentage to use + */ + double percentage; +}; + +struct MinimumContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Number of conns per peer + */ + unsigned int num_to_add; + + /** + * Permuted array of all possible connections. Only add the Nth + * peer if it's in the Nth position. + */ + unsigned int *pg_array; + + /** + * What number is the current element we are iterating over? + */ + unsigned int current; +}; + +struct DFSContext +{ + /** + * The peergroup + */ + struct GNUNET_TESTING_PeerGroup *pg; + + /** + * uid of the first peer + */ + uint32_t first_uid; + + /** + * uid of the second peer + */ + uint32_t second_uid; + + /** + * Peer data for first peer. + */ + struct PeerData *first; + + /** + * Which peer has been chosen as the one to add? + */ + unsigned int chosen; + + /** + * What number is the current element we are iterating over? + */ + unsigned int current; +}; + +/** + * Simple struct to keep track of progress, and print a + * nice little percentage meter for long running tasks. + */ +struct ProgressMeter +{ + unsigned int total; + + unsigned int modnum; + + unsigned int dotnum; + + unsigned int completed; + + int print; + + char *startup_string; +}; + +#if !OLD +/** + * Convert unique ID to hash code. + * + * @param uid unique ID to convert + * @param hash set to uid (extended with zeros) + */ +static void +hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) +{ + memset (hash, 0, sizeof (GNUNET_HashCode)); + *((uint32_t *) hash) = uid; +} + +/** + * Convert hash code to unique ID. + * + * @param uid unique ID to convert + * @param hash set to uid (extended with zeros) + */ +static void +uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid) +{ + memcpy (uid, hash, sizeof (uint32_t)); +} +#endif + +#if USE_SEND_HELLOS +static struct GNUNET_CORE_MessageHandler no_handlers[] = { + {NULL, 0, 0} +}; +#endif + +/** + * Create a meter to keep track of the progress of some task. + * + * @param total the total number of items to complete + * @param start_string a string to prefix the meter with (if printing) + * @param print GNUNET_YES to print the meter, GNUNET_NO to count + * internally only + * + * @return the progress meter + */ +static struct ProgressMeter * +create_meter (unsigned int total, char *start_string, int print) +{ + struct ProgressMeter *ret; + + ret = GNUNET_malloc (sizeof (struct ProgressMeter)); + ret->print = print; + ret->total = total; + ret->modnum = total / 4; + if (ret->modnum == 0) /* Divide by zero check */ + ret->modnum = 1; + ret->dotnum = (total / 50) + 1; + if (start_string != NULL) + ret->startup_string = GNUNET_strdup (start_string); + else + ret->startup_string = GNUNET_strdup (""); + + return ret; +} + +/** + * Update progress meter (increment by one). + * + * @param meter the meter to update and print info for + * + * @return GNUNET_YES if called the total requested, + * GNUNET_NO if more items expected + */ +static int +update_meter (struct ProgressMeter *meter) +{ + if (meter->print == GNUNET_YES) + { + if (meter->completed % meter->modnum == 0) + { + if (meter->completed == 0) + { + FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); + } + else + FPRINTF (stdout, "%d%%", + (int) (((float) meter->completed / meter->total) * 100)); + } + else if (meter->completed % meter->dotnum == 0) + FPRINTF (stdout, "%s", "."); + + if (meter->completed + 1 == meter->total) + FPRINTF (stdout, "%d%%]\n", 100); + fflush (stdout); + } + meter->completed++; + + if (meter->completed == meter->total) + return GNUNET_YES; + if (meter->completed > meter->total) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Progress meter overflow!!\n"); + return GNUNET_NO; +} + +/** + * Reset progress meter. + * + * @param meter the meter to reset + * + * @return GNUNET_YES if meter reset, + * GNUNET_SYSERR on error + */ +static int +reset_meter (struct ProgressMeter *meter) +{ + if (meter == NULL) + return GNUNET_SYSERR; + + meter->completed = 0; + return GNUNET_YES; +} + +/** + * Release resources for meter + * + * @param meter the meter to free + */ +static void +free_meter (struct ProgressMeter *meter) +{ + GNUNET_free_non_null (meter->startup_string); + GNUNET_free (meter); +} + +/** + * 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_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, + const char *topology_string) +{ + /** + * Strings representing topologies in enum + */ + static const char *topology_strings[] = { + /** + * A clique (everyone connected to everyone else). + */ + "CLIQUE", + + /** + * Small-world network (2d torus plus random links). + */ + "SMALL_WORLD", + + /** + * Small-world network (ring plus random links). + */ + "SMALL_WORLD_RING", + + /** + * Ring topology. + */ + "RING", + + /** + * 2-d torus. + */ + "2D_TORUS", + + /** + * Random graph. + */ + "ERDOS_RENYI", + + /** + * Certain percentage of peers are unable to communicate directly + * replicating NAT conditions + */ + "INTERNAT", + + /** + * Scale free topology. + */ + "SCALE_FREE", + + /** + * Straight line topology. + */ + "LINE", + + /** + * All peers are disconnected. + */ + "NONE", + + /** + * Read the topology from a file. + */ + "FROM_FILE", + + NULL + }; + + int curr = 0; + + if (topology_string == NULL) + return GNUNET_NO; + while (topology_strings[curr] != NULL) + { + if (strcasecmp (topology_strings[curr], topology_string) == 0) + { + *topology = curr; + return GNUNET_YES; + } + curr++; + } + *topology = GNUNET_TESTING_TOPOLOGY_NONE; + return GNUNET_NO; +} + +/** + * Get connect topology option from string input. + * + * @param topology_option where to write the retrieved topology + * @param topology_string The string to attempt to + * get a configuration value from + * @return GNUNET_YES if string matched a known + * topology option, GNUNET_NO if not + */ +int +GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption + *topology_option, + const char *topology_string) +{ + /** + * Options for connecting a topology as strings. + */ + static const char *topology_option_strings[] = { + /** + * Try to connect all peers specified in the topology. + */ + "CONNECT_ALL", + + /** + * Choose a random subset of connections to create. + */ + "CONNECT_RANDOM_SUBSET", + + /** + * Create at least X connections for each peer. + */ + "CONNECT_MINIMUM", + + /** + * Using a depth first search, create one connection + * per peer. If any are missed (graph disconnected) + * start over at those peers until all have at least one + * connection. + */ + "CONNECT_DFS", + + /** + * Find the N closest peers to each allowed peer in the + * topology and make sure a connection to those peers + * exists in the connect topology. + */ + "CONNECT_CLOSEST", + + /** + * No options specified. + */ + "CONNECT_NONE", + + NULL + }; + int curr = 0; + + if (topology_string == NULL) + return GNUNET_NO; + while (NULL != topology_option_strings[curr]) + { + if (strcasecmp (topology_option_strings[curr], topology_string) == 0) + { + *topology_option = curr; + return GNUNET_YES; + } + curr++; + } + *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE; + return GNUNET_NO; +} + +/** + * Function to iterate over options. Copies + * the options to the target configuration, + * updating PORT values as needed. + * + * @param cls closure + * @param section name of the section + * @param option name of the option + * @param value value of the option + */ +static void +update_config (void *cls, const char *section, const char *option, + const char *value) +{ + struct UpdateContext *ctx = cls; + unsigned int ival; + char cval[12]; + char uval[128]; + char *single_variable; + char *per_host_variable; + unsigned long long num_per_host; + + GNUNET_asprintf (&single_variable, "single_%s_per_host", section); + GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); + + if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival))) + { + if ((ival != 0) && + (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing_old", + single_variable))) + { + GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++); + value = cval; + } + else if ((ival != 0) && + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing_old", + single_variable)) && + GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing_old", + per_host_variable, + &num_per_host)) + { + GNUNET_snprintf (cval, sizeof (cval), "%u", + ival + ctx->fdnum % num_per_host); + value = cval; + } + + /* FIXME: REMOVE FOREVER HACK HACK HACK */ + if (0 == strcasecmp (section, "transport-tcp")) + GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, + "ADVERTISED_PORT", value); + } + + if (0 == strcmp (option, "UNIXPATH")) + { + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing_old", + single_variable)) + { + GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, + ctx->upnum++); + value = uval; + } + else if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing_old", + per_host_variable, + &num_per_host)) && + (num_per_host > 0)) + + { + GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, + ctx->fdnum % num_per_host); + value = uval; + } + } + + if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL)) + { + value = ctx->hostname; + } + GNUNET_free (single_variable); + GNUNET_free (per_host_variable); + GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value); +} + +/** + * Create a new configuration using the given configuration + * as a template; however, each PORT in the existing cfg + * must be renumbered by incrementing "*port". If we run + * out of "*port" numbers, return NULL. + * + * @param cfg template configuration + * @param off the current peer offset + * @param port port numbers to use, update to reflect + * port numbers that were used + * @param upnum number to make unix domain socket names unique + * @param hostname hostname of the controlling host, to allow control connections from + * @param fdnum number used to offset the unix domain socket for grouped processes + * (such as statistics or peerinfo, which can be shared among others) + * + * @return new configuration, NULL on error + */ +struct GNUNET_CONFIGURATION_Handle * +GNUNET_TESTING_create_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, + uint16_t * port, uint32_t * upnum, const char *hostname, + uint32_t * fdnum) +{ + struct UpdateContext uc; + uint16_t orig; + char *control_host; + char *allowed_hosts; + unsigned long long skew_variance; + unsigned long long skew_offset; + long long actual_offset; + + orig = *port; + uc.nport = *port; + uc.upnum = *upnum; + uc.fdnum = *fdnum; + uc.ret = GNUNET_CONFIGURATION_create (); + uc.hostname = hostname; + uc.orig = cfg; + + GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc); + if (uc.nport >= HIGH_PORT) + { + *port = orig; + GNUNET_CONFIGURATION_destroy (uc.ret); + return NULL; + } + + if ((GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, "testing_old", "skew_variance", + &skew_variance)) && + (skew_variance > 0)) + { + skew_offset = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + skew_variance + 1); + actual_offset = + skew_offset - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + skew_variance + 1); + /* Min is -skew_variance, Max is skew_variance */ + skew_offset = skew_variance + actual_offset; /* Normal distribution around 0 */ + GNUNET_CONFIGURATION_set_value_number (uc.ret, "testing_old", "skew_offset", + skew_offset); + } + + if (GNUNET_CONFIGURATION_get_value_string + (cfg, "testing_old", "control_host", &control_host) == GNUNET_OK) + { + if (hostname != NULL) + GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1; %s;", control_host, + hostname); + else + GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", control_host); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM", + allowed_hosts); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "ACCEPT_FROM", + allowed_hosts); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "ACCEPT_FROM", + allowed_hosts); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM", + allowed_hosts); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "ACCEPT_FROM", + allowed_hosts); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH", ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH", ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", + ""); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "UNIXPATH", ""); + + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", + "USE_LOCALADDR", "YES"); + GNUNET_free_non_null (control_host); + GNUNET_free (allowed_hosts); + } + + /* arm needs to know to allow connections from the host on which it is running, + * otherwise gnunet-arm is unable to connect to it in some instances */ + if (hostname != NULL) + { + GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", + hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", + hostname); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "disablev6", "BINDTO", + "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "arm", "ACCEPT_FROM", + allowed_hosts); + GNUNET_free (allowed_hosts); + } + else + { + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", + "USE_LOCALADDR", "YES"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", + "127.0.0.1"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", + "127.0.0.1"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", + "127.0.0.1"); + GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "disablev6", + "YES"); + } + + *port = (uint16_t) uc.nport; + *upnum = uc.upnum; + uc.fdnum++; + *fdnum = uc.fdnum; + return uc.ret; +} + +/* + * Remove entries from the peer connection list + * + * @param pg the peer group we are working with + * @param first index of the first peer + * @param second index of the second peer + * @param list the peer list to use + * @param check UNUSED + * + * @return the number of connections added (can be 0, 1 or 2) + * + */ +static unsigned int +remove_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, + unsigned int second, enum PeerLists list, + unsigned int check) +{ + int removed; + +#if OLD + struct PeerConnection **first_list; + struct PeerConnection **second_list; + struct PeerConnection *first_iter; + struct PeerConnection *second_iter; + struct PeerConnection **first_tail; + struct PeerConnection **second_tail; + +#else + GNUNET_HashCode hash_first; + GNUNET_HashCode hash_second; + + hash_from_uid (first, &hash_first); + hash_from_uid (second, &hash_second); +#endif + + removed = 0; +#if OLD + switch (list) + { + case ALLOWED: + first_list = &pg->peers[first].allowed_peers_head; + second_list = &pg->peers[second].allowed_peers_head; + first_tail = &pg->peers[first].allowed_peers_tail; + second_tail = &pg->peers[second].allowed_peers_tail; + break; + case CONNECT: + first_list = &pg->peers[first].connect_peers_head; + second_list = &pg->peers[second].connect_peers_head; + first_tail = &pg->peers[first].connect_peers_tail; + second_tail = &pg->peers[second].connect_peers_tail; + break; + case BLACKLIST: + first_list = &pg->peers[first].blacklisted_peers_head; + second_list = &pg->peers[second].blacklisted_peers_head; + first_tail = &pg->peers[first].blacklisted_peers_tail; + second_tail = &pg->peers[second].blacklisted_peers_tail; + break; + case WORKING_SET: + first_list = &pg->peers[first].connect_peers_working_set_head; + second_list = &pg->peers[second].connect_peers_working_set_head; + first_tail = &pg->peers[first].connect_peers_working_set_tail; + second_tail = &pg->peers[second].connect_peers_working_set_tail; + break; + default: + GNUNET_break (0); + return 0; + } + + first_iter = *first_list; + while (first_iter != NULL) + { + if (first_iter->index == second) + { + GNUNET_CONTAINER_DLL_remove (*first_list, *first_tail, first_iter); + GNUNET_free (first_iter); + removed++; + break; + } + first_iter = first_iter->next; + } + + second_iter = *second_list; + while (second_iter != NULL) + { + if (second_iter->index == first) + { + GNUNET_CONTAINER_DLL_remove (*second_list, *second_tail, second_iter); + GNUNET_free (second_iter); + removed++; + break; + } + second_iter = second_iter->next; + } +#else + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (pg-> + peers[first].blacklisted_peers, + &hash_second)) + { + GNUNET_CONTAINER_multihashmap_remove_all (pg-> + peers[first].blacklisted_peers, + &hash_second); + } + + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (pg-> + peers[second].blacklisted_peers, + &hash_first)) + { + GNUNET_CONTAINER_multihashmap_remove_all (pg-> + peers[second].blacklisted_peers, + &hash_first); + } +#endif + + return removed; +} + +/** + * Add entries to the some list + * + * @param pg the peer group we are working with + * @param first index of the first peer + * @param second index of the second peer + * @param list the list type that we should modify + * @param check GNUNET_YES to check lists before adding + * GNUNET_NO to force add + * + * @return the number of connections added (can be 0, 1 or 2) + * + */ +static unsigned int +add_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, + unsigned int second, enum PeerLists list, unsigned int check) +{ + int added; + int add_first; + int add_second; + + struct PeerConnection **first_list; + struct PeerConnection **second_list; + struct PeerConnection *first_iter; + struct PeerConnection *second_iter; + struct PeerConnection *new_first; + struct PeerConnection *new_second; + struct PeerConnection **first_tail; + struct PeerConnection **second_tail; + + switch (list) + { + case ALLOWED: + first_list = &pg->peers[first].allowed_peers_head; + second_list = &pg->peers[second].allowed_peers_head; + first_tail = &pg->peers[first].allowed_peers_tail; + second_tail = &pg->peers[second].allowed_peers_tail; + break; + case CONNECT: + first_list = &pg->peers[first].connect_peers_head; + second_list = &pg->peers[second].connect_peers_head; + first_tail = &pg->peers[first].connect_peers_tail; + second_tail = &pg->peers[second].connect_peers_tail; + break; + case BLACKLIST: + first_list = &pg->peers[first].blacklisted_peers_head; + second_list = &pg->peers[second].blacklisted_peers_head; + first_tail = &pg->peers[first].blacklisted_peers_tail; + second_tail = &pg->peers[second].blacklisted_peers_tail; + break; + case WORKING_SET: + first_list = &pg->peers[first].connect_peers_working_set_head; + second_list = &pg->peers[second].connect_peers_working_set_head; + first_tail = &pg->peers[first].connect_peers_working_set_tail; + second_tail = &pg->peers[second].connect_peers_working_set_tail; + break; + default: + GNUNET_break (0); + return 0; + } + + add_first = GNUNET_YES; + add_second = GNUNET_YES; + + if (check == GNUNET_YES) + { + first_iter = *first_list; + while (first_iter != NULL) + { + if (first_iter->index == second) + { + add_first = GNUNET_NO; + break; + } + first_iter = first_iter->next; + } + + second_iter = *second_list; + while (second_iter != NULL) + { + if (second_iter->index == first) + { + add_second = GNUNET_NO; + break; + } + second_iter = second_iter->next; + } + } + + added = 0; + if (add_first) + { + new_first = GNUNET_malloc (sizeof (struct PeerConnection)); + new_first->index = second; + GNUNET_CONTAINER_DLL_insert (*first_list, *first_tail, new_first); + pg->peers[first].num_connections++; + added++; + } + + if (add_second) + { + new_second = GNUNET_malloc (sizeof (struct PeerConnection)); + new_second->index = first; + GNUNET_CONTAINER_DLL_insert (*second_list, *second_tail, new_second); + pg->peers[second].num_connections++; + added++; + } + + return added; +} + +/** + * Scale free network construction as described in: + * + * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999. + * + * Start with a network of "one" peer, then progressively add + * peers up to the total number. At each step, iterate over + * all possible peers and connect new peer based on number of + * existing connections of the target peer. + * + * @param pg the peer group we are dealing with + * @param proc the connection processor to use + * @param list the peer list to use + * + * @return the number of connections created + */ +static unsigned int +create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + + unsigned int total_connections; + unsigned int outer_count; + unsigned int i; + unsigned int previous_total_connections; + double random; + double probability; + + GNUNET_assert (pg->total > 1); + + /* Add a connection between the first two nodes */ + total_connections = proc (pg, 0, 1, list, GNUNET_YES); + + for (outer_count = 1; outer_count < pg->total; outer_count++) + { + previous_total_connections = total_connections; + for (i = 0; i < outer_count; i++) + { + probability = + pg->peers[i].num_connections / (double) previous_total_connections; + random = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Considering connecting peer %d to peer %d\n", outer_count, + i); + if (random < probability) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, i); + total_connections += proc (pg, outer_count, i, list, GNUNET_YES); + } + } + } + + return total_connections; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. Creates a small world topology + * according to the rewired ring construction. The basic + * behavior is that a ring topology is created, but with some + * probability instead of connecting a peer to the next + * neighbor in the ring a connection will be created to a peer + * selected uniformly at random. We use the TESTING + * PERCENTAGE option to specify what number of + * connections each peer should have. Default is 2, + * which makes the ring, any given number is multiplied by + * the log of the network size; i.e. a PERCENTAGE of 2 makes + * each peer have on average 2logn connections. The additional + * connections are made at increasing distance around the ring + * from the original peer, or to random peers based on the re- + * wiring probability. The TESTING + * PROBABILITY option is used as the probability that a given + * connection is rewired. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_small_world_ring (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int i, j; + int nodeToConnect; + unsigned int natLog; + unsigned int randomPeer; + double random, logNModifier, probability; + unsigned int smallWorldConnections; + int connsPerPeer; + char *p_string; + int max; + int min; + unsigned int useAnd; + int connect_attempts; + + logNModifier = 0.5; /* FIXME: default value? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING_OLD", "PERCENTAGE", + &p_string)) + { + if (SSCANF (p_string, "%lf", &logNModifier) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "LOGNMODIFIER", "TESTING_OLD"); + GNUNET_free (p_string); + } + probability = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING_OLD", "PROBABILITY", + &p_string)) + { + if (SSCANF (p_string, "%lf", &probability) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING_OLD"); + GNUNET_free (p_string); + } + natLog = log (pg->total); + connsPerPeer = ceil (natLog * logNModifier); + + if (connsPerPeer % 2 == 1) + connsPerPeer += 1; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Target is %d connections per peer.", + connsPerPeer); + + smallWorldConnections = 0; + connect_attempts = 0; + for (i = 0; i < pg->total; i++) + { + useAnd = 0; + max = i + connsPerPeer / 2; + min = i - connsPerPeer / 2; + + if (max > pg->total - 1) + { + max = max - pg->total; + useAnd = 1; + } + + if (min < 0) + { + min = pg->total - 1 + min; + useAnd = 1; + } + + for (j = 0; j < connsPerPeer / 2; j++) + { + random = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX) / ((double) UINT64_MAX)); + if (random < probability) + { + /* Connect to uniformly selected random peer */ + randomPeer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + while ((((randomPeer < max) && (randomPeer > min)) && (useAnd == 0)) || + (((randomPeer > min) || (randomPeer < max)) && (useAnd == 1))) + { + randomPeer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + } + smallWorldConnections += proc (pg, i, randomPeer, list, GNUNET_YES); + } + else + { + nodeToConnect = i + j + 1; + if (nodeToConnect > pg->total - 1) + { + nodeToConnect = nodeToConnect - pg->total; + } + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + } + } + + } + + connect_attempts += smallWorldConnections; + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int outer_count, inner_count; + unsigned int cutoff; + int connect_attempts; + double nat_percentage; + char *p_string; + + nat_percentage = 0.6; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING_OLD", "PERCENTAGE", + &p_string)) + { + if (SSCANF (p_string, "%lf", &nat_percentage) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING_OLD"); + GNUNET_free (p_string); + } + + cutoff = (unsigned int) (nat_percentage * pg->total); + connect_attempts = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + if ((outer_count > cutoff) || (inner_count > cutoff)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, inner_count); + connect_attempts += + proc (pg, outer_count, inner_count, list, GNUNET_YES); + } + } + } + return connect_attempts; +} + +#if TOPOLOGY_HACK +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_nated_internet_copy (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int outer_count, inner_count; + unsigned int cutoff; + int connect_attempts; + double nat_percentage; + char *p_string; + unsigned int count; + struct ProgressMeter *conn_meter; + + nat_percentage = 0.6; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING_OLD", "PERCENTAGE", + &p_string)) + { + if (SSCANF (p_string, "%lf", &nat_percentage) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING_OLD"); + GNUNET_free (p_string); + } + + cutoff = (unsigned int) (nat_percentage * pg->total); + count = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + if ((outer_count > cutoff) || (inner_count > cutoff)) + { + count++; + } + } + } + conn_meter = create_meter (count, "NAT COPY", GNUNET_YES); + connect_attempts = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + if ((outer_count > cutoff) || (inner_count > cutoff)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, inner_count); + connect_attempts += + proc (pg, outer_count, inner_count, list, GNUNET_YES); + add_connections (pg, outer_count, inner_count, ALLOWED, GNUNET_NO); + update_meter (conn_meter); + } + } + } + free_meter (conn_meter); + + return connect_attempts; +} +#endif + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_small_world (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + unsigned int i, j, k; + unsigned int square; + unsigned int rows; + unsigned int cols; + unsigned int toggle = 1; + unsigned int nodeToConnect; + unsigned int natLog; + unsigned int node1Row; + unsigned int node1Col; + unsigned int node2Row; + unsigned int node2Col; + unsigned int distance; + double probability, random, percentage; + unsigned int smallWorldConnections; + unsigned int small_world_it; + char *p_string; + int connect_attempts; + + square = floor (sqrt (pg->total)); + rows = square; + cols = square; + + percentage = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING_OLD", "PERCENTAGE", + &p_string)) + { + if (SSCANF (p_string, "%lf", &percentage) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PERCENTAGE", "TESTING_OLD"); + GNUNET_free (p_string); + } + if (percentage < 0.0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': got %f, needed value greater than 0\n"), + "PERCENTAGE", "TESTING_OLD", percentage); + percentage = 0.5; + } + probability = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING_OLD", "PROBABILITY", + &p_string)) + { + if (SSCANF (p_string, "%lf", &probability) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PROBABILITY", "TESTING_OLD"); + GNUNET_free (p_string); + } + if (square * square != pg->total) + { + while (rows * cols < pg->total) + { + if (toggle % 2 == 0) + rows++; + else + cols++; + + toggle++; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting nodes in 2d torus topology: %u rows %u columns\n", + rows, cols); + connect_attempts = 0; + /* Rows and columns are all sorted out, now iterate over all nodes and connect each + * to the node to its right and above. Once this is over, we'll have our torus! + * Special case for the last node (if the rows and columns are not equal), connect + * to the first in the row to maintain topology. + */ + for (i = 0; i < pg->total; i++) + { + /* First connect to the node to the right */ + if (((i + 1) % cols != 0) && (i + 1 != pg->total)) + nodeToConnect = i + 1; + else if (i + 1 == pg->total) + nodeToConnect = rows * cols - cols; + else + nodeToConnect = i - cols + 1; + + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + + if (i < cols) + { + nodeToConnect = (rows * cols) - cols + i; + if (nodeToConnect >= pg->total) + nodeToConnect -= cols; + } + else + nodeToConnect = i - cols; + + if (nodeToConnect < pg->total) + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + } + natLog = log (pg->total); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "natural log of %d is %d, will run %d iterations\n", pg->total, + natLog, (int) (natLog * percentage)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total connections added thus far: %u!\n", connect_attempts); + smallWorldConnections = 0; + small_world_it = (unsigned int) (natLog * percentage); + if (small_world_it < 1) + small_world_it = 1; + GNUNET_assert (small_world_it > 0 && small_world_it < (unsigned int) -1); + for (i = 0; i < small_world_it; i++) + { + for (j = 0; j < pg->total; j++) + { + /* Determine the row and column of node at position j on the 2d torus */ + node1Row = j / cols; + node1Col = j - (node1Row * cols); + for (k = 0; k < pg->total; k++) + { + /* Determine the row and column of node at position k on the 2d torus */ + node2Row = k / cols; + node2Col = k - (node2Row * cols); + /* Simple Cartesian distance */ + distance = abs (node1Row - node2Row) + abs (node1Col - node2Col); + if (distance > 1) + { + /* Calculate probability as 1 over the square of the distance */ + probability = 1.0 / (distance * distance); + /* Choose a random value between 0 and 1 */ + random = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + /* If random < probability, then connect the two nodes */ + if (random < probability) + smallWorldConnections += proc (pg, j, k, list, GNUNET_YES); + + } + } + } + } + connect_attempts += smallWorldConnections; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Total connections added for small world: %d!\n", + smallWorldConnections); + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, + enum PeerLists list) +{ + double temp_rand; + unsigned int outer_count; + unsigned int inner_count; + int connect_attempts; + double probability; + char *p_string; + + probability = 0.5; /* FIXME: default percentage? */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING_OLD", "PROBABILITY", + &p_string)) + { + if (SSCANF (p_string, "%lf", &probability) != 1) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + p_string, "PROBABILITY", "TESTING_OLD"); + GNUNET_free (p_string); + } + connect_attempts = 0; + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + temp_rand = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "rand is %f probability is %f\n", + temp_rand, probability); + if (temp_rand < probability) + { + connect_attempts += + proc (pg, outer_count, inner_count, list, GNUNET_YES); + } + } + } + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. This particular function creates + * the connections for a 2d-torus, plus additional "closest" + * connections per peer. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + unsigned int i; + unsigned int square; + unsigned int rows; + unsigned int cols; + unsigned int toggle = 1; + unsigned int nodeToConnect; + int connect_attempts; + + connect_attempts = 0; + + square = floor (sqrt (pg->total)); + rows = square; + cols = square; + + if (square * square != pg->total) + { + while (rows * cols < pg->total) + { + if (toggle % 2 == 0) + rows++; + else + cols++; + + toggle++; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting nodes in 2d torus topology: %u rows %u columns\n", + rows, cols); + /* Rows and columns are all sorted out, now iterate over all nodes and connect each + * to the node to its right and above. Once this is over, we'll have our torus! + * Special case for the last node (if the rows and columns are not equal), connect + * to the first in the row to maintain topology. + */ + for (i = 0; i < pg->total; i++) + { + /* First connect to the node to the right */ + if (((i + 1) % cols != 0) && (i + 1 != pg->total)) + nodeToConnect = i + 1; + else if (i + 1 == pg->total) + nodeToConnect = rows * cols - cols; + else + nodeToConnect = i - cols + 1; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, + nodeToConnect); + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + + /* Second connect to the node immediately above */ + if (i < cols) + { + nodeToConnect = (rows * cols) - cols + i; + if (nodeToConnect >= pg->total) + nodeToConnect -= cols; + } + else + nodeToConnect = i - cols; + + if (nodeToConnect < pg->total) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, + nodeToConnect); + connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); + } + + } + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * @param check does the connection processor need to check before + * performing an action on the list? + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_clique (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list, + unsigned int check) +{ + unsigned int outer_count; + unsigned int inner_count; + int connect_attempts; + struct ProgressMeter *conn_meter; + + connect_attempts = 0; + + conn_meter = + create_meter ((((pg->total * pg->total) + pg->total) / 2) - pg->total, + "Create Clique ", GNUNET_NO); + for (outer_count = 0; outer_count < pg->total - 1; outer_count++) + { + for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + outer_count, inner_count); + connect_attempts += proc (pg, outer_count, inner_count, list, check); + update_meter (conn_meter); + } + } + reset_meter (conn_meter); + free_meter (conn_meter); + return connect_attempts; +} + +#if !OLD +/** + * Iterator over hash map entries. + * + * @param cls closure the peer group + * @param key the key stored in the hashmap is the + * index of the peer to connect to + * @param value value in the hash map, handle to the peer daemon + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +unblacklist_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct UnblacklistContext *un_ctx = cls; + uint32_t second_pos; + + uid_from_hash (key, &second_pos); + + unblacklist_connections (un_ctx->pg, un_ctx->first_uid, second_pos); + + return GNUNET_YES; +} +#endif + +#if !OLD +/** + * Create a blacklist topology based on the allowed topology + * which disallows any connections not in the allowed topology + * at the transport level. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to allow + * up connections between two peers + * + * @return the number of connections that were set up + * + */ +static unsigned int +copy_allowed (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc) +{ + unsigned int count; + unsigned int total; + struct PeerConnection *iter; + +#if !OLD + struct UnblacklistContext un_ctx; + + un_ctx.pg = pg; +#endif + total = 0; + for (count = 0; count < pg->total - 1; count++) + { +#if OLD + iter = pg->peers[count].allowed_peers_head; + while (iter != NULL) + { + remove_connections (pg, count, iter->index, BLACKLIST, GNUNET_YES); + //unblacklist_connections(pg, count, iter->index); + iter = iter->next; + } +#else + un_ctx.first_uid = count; + total += + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[count].allowed_peers, + &unblacklist_iterator, &un_ctx); +#endif + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unblacklisted %u peers\n", total); + return total; +} +#endif + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list which list should be modified + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_line (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + unsigned int count; + unsigned int connect_attempts; + + connect_attempts = 0; + /* Connect each peer to the next highest numbered peer */ + for (count = 0; count < pg->total - 1; count++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + count, count + 1); + connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); + } + + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param filename the file to read topology information from + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_from_file (struct GNUNET_TESTING_PeerGroup *pg, char *filename, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + int connect_attempts; + unsigned int first_peer_index; + unsigned int second_peer_index; + struct stat frstat; + int count; + char *data; + const char *buf; + unsigned int total_peers; + enum States curr_state; + + connect_attempts = 0; + if (GNUNET_OK != GNUNET_DISK_file_test (filename)) + GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ); + + if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not open file `%s' specified for topology!", filename); + return connect_attempts; + } + + data = GNUNET_malloc_large (frstat.st_size); + GNUNET_assert (data != NULL); + if (frstat.st_size != GNUNET_DISK_fn_read (filename, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not read file %s specified for host list, ending test!", + filename); + GNUNET_free (data); + return connect_attempts; + } + + buf = data; + count = 0; + first_peer_index = 0; + /* First line should contain a single integer, specifying the number of peers */ + /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */ + curr_state = NUM_PEERS; + while (count < frstat.st_size - 1) + { + if ((buf[count] == '\n') || (buf[count] == ' ')) + { + count++; + continue; + } + + switch (curr_state) + { + case NUM_PEERS: + errno = 0; + total_peers = strtoul (&buf[count], NULL, 10); + if (errno != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to read number of peers from topology file!\n"); + GNUNET_free (data); + return connect_attempts; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u total peers in topology\n", + total_peers); + GNUNET_assert (total_peers == pg->total); + curr_state = PEER_INDEX; + while ((buf[count] != '\n') && (count < frstat.st_size - 1)) + count++; + count++; + break; + case PEER_INDEX: + errno = 0; + first_peer_index = strtoul (&buf[count], NULL, 10); + if (errno != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to read peer index from topology file!\n"); + GNUNET_free (data); + return connect_attempts; + } + while ((buf[count] != ':') && (count < frstat.st_size - 1)) + count++; + count++; + curr_state = OTHER_PEER_INDEX; + break; + case COLON: + if (1 == sscanf (&buf[count], ":")) + curr_state = OTHER_PEER_INDEX; + count++; + break; + case OTHER_PEER_INDEX: + errno = 0; + second_peer_index = strtoul (&buf[count], NULL, 10); + if (errno != 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to peer index from topology file!\n"); + GNUNET_free (data); + return connect_attempts; + } + /* Assume file is written with first peer 1, but array index is 0 */ + connect_attempts += + proc (pg, first_peer_index - 1, second_peer_index - 1, list, + GNUNET_YES); + while ((buf[count] != '\n') && (buf[count] != ',') && + (count < frstat.st_size - 1)) + count++; + if (buf[count] == '\n') + { + curr_state = PEER_INDEX; + } + else if (buf[count] != ',') + { + curr_state = OTHER_PEER_INDEX; + } + count++; + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Found bad data in topology file while in state %d!\n", + curr_state); + GNUNET_break (0); + GNUNET_free (data); + return connect_attempts; + } + } + GNUNET_free (data); + return connect_attempts; +} + +/** + * Create a topology given a peer group (set of running peers) + * and a connection processor. + * + * @param pg the peergroup to create the topology on + * @param proc the connection processor to call to actually set + * up connections between two peers + * @param list the peer list to use + * + * @return the number of connections that were set up + * + */ +static unsigned int +create_ring (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ + unsigned int count; + int connect_attempts; + + connect_attempts = 0; + + /* Connect each peer to the next highest numbered peer */ + for (count = 0; count < pg->total - 1; count++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", + count, count + 1); + connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); + } + + /* Connect the last peer to the first peer */ + connect_attempts += proc (pg, pg->total - 1, 0, list, GNUNET_YES); + + return connect_attempts; +} + +#if !OLD +/** + * Iterator for writing friends of a peer to a file. + * + * @param cls closure, an open writable file handle + * @param key the key the daemon was stored under + * @param value the GNUNET_TESTING_Daemon that needs to be written. + * + * @return GNUNET_YES to continue iteration + * + * TODO: Could replace friend_file_iterator and blacklist_file_iterator + * with a single file_iterator that takes a closure which contains + * the prefix to write before the peer. Then this could be used + * for blacklisting multiple transports and writing the friend + * file. I'm sure *someone* will complain loudly about other + * things that negate these functions even existing so no point in + * "fixing" now. + */ +static int +friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + FILE *temp_friend_handle = cls; + struct GNUNET_TESTING_Daemon *peer = value; + struct GNUNET_PeerIdentity *temppeer; + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + + temppeer = &peer->id; + GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); + FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); + + return GNUNET_YES; +} + +struct BlacklistContext +{ + /* + * The (open) file handle to write to + */ + FILE *temp_file_handle; + + /* + * The transport that this peer will be blacklisted on. + */ + char *transport; +}; + +/** + * Iterator for writing blacklist data to appropriate files. + * + * @param cls closure, an open writable file handle + * @param key the key the daemon was stored under + * @param value the GNUNET_TESTING_Daemon that needs to be written. + * + * @return GNUNET_YES to continue iteration + */ +static int +blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct BlacklistContext *blacklist_ctx = cls; + struct GNUNET_TESTING_Daemon *peer = value; + struct GNUNET_PeerIdentity *temppeer; + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + + temppeer = &peer->id; + GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", + blacklist_ctx->transport, (char *) &peer_enc); + FPRINTF (blacklist_ctx->temp_file_handle, "%s:%s\n", blacklist_ctx->transport, + (char *) &peer_enc); + + return GNUNET_YES; +} +#endif + +/* + * Create the friend files based on the PeerConnection's + * of each peer in the peer group, and copy the files + * to the appropriate place + * + * @param pg the peer group we are dealing with + */ +static int +create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg) +{ + FILE *temp_friend_handle; + unsigned int pg_iter; + char *temp_service_path; + struct GNUNET_OS_Process **procarr; + char *arg; + char *mytemp; + +#if NOT_STUPID + enum GNUNET_OS_ProcessStatusType type; + unsigned long return_code; + int count; + int max_wait = 10; +#endif + int ret; + + ret = GNUNET_OK; +#if OLD + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + struct PeerConnection *conn_iter; +#endif + procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + mytemp = GNUNET_DISK_mktemp ("friends"); + GNUNET_assert (mytemp != NULL); + temp_friend_handle = FOPEN (mytemp, "wt"); + GNUNET_assert (temp_friend_handle != NULL); +#if OLD + conn_iter = pg->peers[pg_iter].allowed_peers_head; + while (conn_iter != NULL) + { + GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> + id.hashPubKey, &peer_enc); + FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); + conn_iter = conn_iter->next; + } +#else + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, + &friend_file_iterator, + temp_friend_handle); +#endif + FCLOSE (temp_friend_handle); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, + "PATHS", "SERVICEHOME", + &temp_service_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), + "SERVICEHOME", "PATHS"); + if (UNLINK (mytemp) != 0) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); + GNUNET_free (mytemp); + break; + } + + if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ + { + GNUNET_asprintf (&arg, "%s/friends", temp_service_path); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying file with RENAME(%s,%s)\n", mytemp, arg); + RENAME (mytemp, arg); + procarr[pg_iter] = NULL; + GNUNET_free (arg); + } + else /* Remote, scp the file to the correct place */ + { + if (NULL != pg->peers[pg_iter].daemon->username) + GNUNET_asprintf (&arg, "%s@%s:%s/friends", + pg->peers[pg_iter].daemon->username, + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + else + GNUNET_asprintf (&arg, "%s:%s/friends", + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + procarr[pg_iter] = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); + GNUNET_assert (procarr[pg_iter] != NULL); + ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */ + GNUNET_OS_process_destroy (procarr[pg_iter]); + if (ret != GNUNET_OK) + { + /* FIXME: free contents of 'procarr' array */ + GNUNET_free (procarr); + GNUNET_free (temp_service_path); + GNUNET_free (mytemp); + GNUNET_free (arg); + return ret; + } + procarr[pg_iter] = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying file with command scp %s %s\n", mytemp, arg); + GNUNET_free (arg); + } + GNUNET_free (temp_service_path); + GNUNET_free (mytemp); + } + +#if NOT_STUPID + count = 0; + ret = GNUNET_SYSERR; + while ((count < max_wait) && (ret != GNUNET_OK)) + { + ret = GNUNET_OK; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking copy status of file %d\n", + pg_iter); + if (procarr[pg_iter] != NULL) /* Check for already completed! */ + { + if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != + GNUNET_OK) + { + ret = GNUNET_SYSERR; + } + else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) + { + ret = GNUNET_SYSERR; + } + else + { + GNUNET_OS_process_destroy (procarr[pg_iter]); + procarr[pg_iter] = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); + } + } + } + count++; + if (ret == GNUNET_SYSERR) + { + /* FIXME: why sleep here? -CG */ + sleep (1); + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished copying all friend files!\n"); +#endif + GNUNET_free (procarr); + return ret; +} + +/* + * Create the blacklist files based on the PeerConnection's + * of each peer in the peer group, and copy the files + * to the appropriate place. + * + * @param pg the peer group we are dealing with + * @param transports space delimited list of transports to blacklist + */ +static int +create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, + const char *transports) +{ + FILE *temp_file_handle; + unsigned int pg_iter; + char *temp_service_path; + struct GNUNET_OS_Process **procarr; + char *arg; + char *mytemp; + enum GNUNET_OS_ProcessStatusType type; + unsigned long return_code; + int count; + int ret; + int max_wait = 10; + int transport_len; + unsigned int i; + char *pos; + char *temp_transports; + +#if OLD + struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; + struct PeerConnection *conn_iter; +#else + static struct BlacklistContext blacklist_ctx; +#endif + + procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + mytemp = GNUNET_DISK_mktemp ("blacklist"); + GNUNET_assert (mytemp != NULL); + temp_file_handle = FOPEN (mytemp, "wt"); + GNUNET_assert (temp_file_handle != NULL); + temp_transports = GNUNET_strdup (transports); +#if !OLD + blacklist_ctx.temp_file_handle = temp_file_handle; +#endif + transport_len = strlen (temp_transports) + 1; + pos = NULL; + + for (i = 0; i < transport_len; i++) + { + if ((temp_transports[i] == ' ') && (pos == NULL)) + continue; /* At start of string (whitespace) */ + else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */ + { + temp_transports[i] = '\0'; +#if OLD + conn_iter = pg->peers[pg_iter].blacklisted_peers_head; + while (conn_iter != NULL) + { + GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> + id.hashPubKey, &peer_enc); + FPRINTF (temp_file_handle, "%s:%s\n", pos, (char *) &peer_enc); + conn_iter = conn_iter->next; + } +#else + blacklist_ctx.transport = pos; + (void) GNUNET_CONTAINER_multihashmap_iterate (pg-> + peers + [pg_iter].blacklisted_peers, + &blacklist_file_iterator, + &blacklist_ctx); +#endif + pos = NULL; + } /* At beginning of actual string */ + else if (pos == NULL) + { + pos = &temp_transports[i]; + } + } + + GNUNET_free (temp_transports); + FCLOSE (temp_file_handle); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, + "PATHS", "SERVICEHOME", + &temp_service_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), + "SERVICEHOME", "PATHS"); + if (UNLINK (mytemp) != 0) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); + GNUNET_free (mytemp); + break; + } + + if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ + { + GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path); + RENAME (mytemp, arg); + procarr[pg_iter] = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying file with RENAME (%s,%s)\n", mytemp, arg); + GNUNET_free (arg); + } + else /* Remote, scp the file to the correct place */ + { + if (NULL != pg->peers[pg_iter].daemon->username) + GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", + pg->peers[pg_iter].daemon->username, + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + else + GNUNET_asprintf (&arg, "%s:%s/blacklist", + pg->peers[pg_iter].daemon->hostname, + temp_service_path); + procarr[pg_iter] = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); + GNUNET_assert (procarr[pg_iter] != NULL); + GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: add scheduled blacklist file copy that parallelizes file copying! */ + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Copying file with command scp %s %s\n", mytemp, arg); + GNUNET_free (arg); + } + GNUNET_free (temp_service_path); + GNUNET_free (mytemp); + } + + count = 0; + ret = GNUNET_SYSERR; + while ((count < max_wait) && (ret != GNUNET_OK)) + { + ret = GNUNET_OK; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking copy status of file %d\n", pg_iter); + if (procarr[pg_iter] != NULL) /* Check for already completed! */ + { + if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != + GNUNET_OK) + { + ret = GNUNET_SYSERR; + } + else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) + { + ret = GNUNET_SYSERR; + } + else + { + GNUNET_OS_process_destroy (procarr[pg_iter]); + procarr[pg_iter] = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); + } + } + } + count++; + if (ret == GNUNET_SYSERR) + { + /* FIXME: why sleep here? -CG */ + sleep (1); + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished copying all blacklist files!\n"); + GNUNET_free (procarr); + return ret; +} + +/* Forward Declaration */ +static void +schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Choose a random peer's next connection to create, and + * call schedule_connect to set up the connect task. + * + * @param pg the peer group to connect + */ +static void +preschedule_connect (struct GNUNET_TESTING_PeerGroup *pg) +{ + struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx; + struct PeerConnection *connection_iter; + struct ConnectContext *connect_context; + uint32_t random_peer; + + if (ct_ctx->remaining_connections == 0) + return; + random_peer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + while (pg->peers[random_peer].connect_peers_head == NULL) + random_peer = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); + + connection_iter = pg->peers[random_peer].connect_peers_head; + connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); + connect_context->first_index = random_peer; + connect_context->second_index = connection_iter->index; + connect_context->ct_ctx = ct_ctx; + connect_context->task = + GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); + GNUNET_CONTAINER_DLL_insert (pg->cc_head, pg->cc_tail, connect_context); + GNUNET_CONTAINER_DLL_remove (pg->peers[random_peer].connect_peers_head, + pg->peers[random_peer].connect_peers_tail, + connection_iter); + GNUNET_free (connection_iter); + ct_ctx->remaining_connections--; +} + +#if USE_SEND_HELLOS +/* Forward declaration */ +static void +schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); + +/** + * Close connections and free the hello context. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + + if (send_hello_context->peer->daemon->server != NULL) + { + GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); + send_hello_context->peer->daemon->server = NULL; + } + if (send_hello_context->peer->daemon->th != NULL) + { + GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); + send_hello_context->peer->daemon->th = NULL; + } + if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK) + { + GNUNET_SCHEDULER_cancel (send_hello_context->core_connect_task); + send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; + } + send_hello_context->pg->outstanding_connects--; + GNUNET_free (send_hello_context); +} + +/** + * For peers that haven't yet connected, notify + * the caller that they have failed (timeout). + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +notify_remaining_connections_failed (void *cls, + const struct GNUNET_SCHEDULER_TaskContext + *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + struct PeerConnection *connection; + + GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); + send_hello_context->peer->daemon->server = NULL; + + connection = send_hello_context->peer->connect_peers_head; + + while (connection != NULL) + { + if (pg->notify_connection != NULL) + { + pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, 0, /* FIXME */ + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon, + pg->peers[connection->index].daemon, + "Peers failed to connect (timeout)"); + } + GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, + send_hello_context->peer->connect_peers_tail, + connection); + GNUNET_free (connection); + connection = connection->next; + } + GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); +#if BAD + other_peer = &pg->peers[connection->index]; +#endif +} + +/** + * For peers that haven't yet connected, send + * CORE connect requests. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +send_core_connect_requests (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct PeerConnection *conn; + + GNUNET_assert (send_hello_context->peer->daemon->server != NULL); + + send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; + + send_hello_context->connect_attempts++; + if (send_hello_context->connect_attempts < + send_hello_context->pg->ct_ctx.connect_attempts) + { + conn = send_hello_context->peer->connect_peers_head; + while (conn != NULL) + { + GNUNET_TRANSPORT_try_connect (send_hello_context->peer->daemon->th, + &send_hello_context->pg->peers[conn-> + index].daemon-> + id); + conn = conn->next; + } + send_hello_context->core_connect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide + (send_hello_context->pg-> + ct_ctx.connect_timeout, + send_hello_context->pg-> + ct_ctx.connect_attempts), + &send_core_connect_requests, + send_hello_context); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Timeout before all connections created, marking rest as failed!\n"); + GNUNET_SCHEDULER_add_now (¬ify_remaining_connections_failed, + send_hello_context); + } + +} + +/** + * Success, connection is up. Signal client our success. + * + * @param cls our "struct SendHelloContext" + * @param peer identity of the peer that has connected + * @param atsi performance information + * + * FIXME: remove peers from BOTH lists, call notify twice, should + * double the speed of connections as long as the list iteration + * doesn't take too long! + */ +static void +core_connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi) +{ + struct SendHelloContext *send_hello_context = cls; + struct PeerConnection *connection; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + +#if BAD + struct PeerData *other_peer; +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", + ctx->d1->shortname, GNUNET_i2s (peer)); + if (0 == + memcmp (&send_hello_context->peer->daemon->id, peer, + sizeof (struct GNUNET_PeerIdentity))) + return; + + connection = send_hello_context->peer->connect_peers_head; +#if BAD + other_peer = NULL; +#endif + + while ((connection != NULL) && + (0 != + memcmp (&pg->peers[connection->index].daemon->id, peer, + sizeof (struct GNUNET_PeerIdentity)))) + { + connection = connection->next; + } + + if (connection == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected peer %s to %s, not in list (no problem(?))\n", + GNUNET_i2s (peer), send_hello_context->peer->daemon->shortname); + } + else + { +#if BAD + other_peer = &pg->peers[connection->index]; +#endif + if (pg->notify_connection != NULL) + { + pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, peer, 0, /* FIXME */ + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon, + pg->peers[connection->index].daemon, NULL); + } + GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, + send_hello_context->peer->connect_peers_tail, + connection); + GNUNET_free (connection); + } + +#if BAD + /* Notify of reverse connection and remove from other peers list of outstanding */ + if (other_peer != NULL) + { + connection = other_peer->connect_peers_head; + while ((connection != NULL) && + (0 != + memcmp (&send_hello_context->peer->daemon->id, + &pg->peers[connection->index].daemon->id, + sizeof (struct GNUNET_PeerIdentity)))) + { + connection = connection->next; + } + if (connection != NULL) + { + if (pg->notify_connection != NULL) + { + pg->notify_connection (pg->notify_connection_cls, peer, &send_hello_context->peer->daemon->id, 0, /* FIXME */ + pg->peers[connection->index].daemon->cfg, + send_hello_context->peer->daemon->cfg, + pg->peers[connection->index].daemon, + send_hello_context->peer->daemon, NULL); + } + + GNUNET_CONTAINER_DLL_remove (other_peer->connect_peers_head, + other_peer->connect_peers_tail, connection); + GNUNET_free (connection); + } + } +#endif + + if (send_hello_context->peer->connect_peers_head == NULL) + { + GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); + } +} + +/** + * Notify of a successful connection to the core service. + * + * @param cls a struct SendHelloContext * + * @param server handle to the core service + * @param my_identity the peer identity of this peer + */ +void +core_init (void *cls, struct GNUNET_CORE_Handle *server, + struct GNUNET_PeerIdentity *my_identity) +{ + struct SendHelloContext *send_hello_context = cls; + + send_hello_context->core_ready = GNUNET_YES; +} + +/** + * Function called once a hello has been sent + * to the transport, move on to the next one + * or go away forever. + * + * @param cls the 'struct SendHelloContext *' + * @param tc scheduler context + */ +static void +hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + + //unsigned int pg_iter; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + GNUNET_free (send_hello_context); + return; + } + + send_hello_context->pg->remaining_hellos--; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent HELLO, have %d remaining!\n", + send_hello_context->pg->remaining_hellos); + if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */ + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All hellos for this peer sent, disconnecting transport!\n"); + GNUNET_assert (send_hello_context->peer->daemon->th != NULL); + GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); + send_hello_context->peer->daemon->th = NULL; + GNUNET_assert (send_hello_context->peer->daemon->server == NULL); + send_hello_context->peer->daemon->server = + GNUNET_CORE_connect (send_hello_context->peer->cfg, 1, + send_hello_context, &core_init, + &core_connect_notify, NULL, NULL, NULL, GNUNET_NO, + NULL, GNUNET_NO, no_handlers); + + send_hello_context->core_connect_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide + (send_hello_context->pg-> + ct_ctx.connect_timeout, + send_hello_context->pg-> + ct_ctx.connect_attempts), + &send_core_connect_requests, + send_hello_context); + } + else + GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); +} + +/** + * Connect to a peer, give it all the HELLO's of those peers + * we will later ask it to connect to. + * + * @param ct_ctx the overall connection context + */ +static void +schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct SendHelloContext *send_hello_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + GNUNET_free (send_hello_context); + return; + } + + GNUNET_assert (send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */ + + if (((send_hello_context->peer->daemon->th == NULL) && + (pg->outstanding_connects > pg->max_outstanding_connections)) || + (pg->stop_connects == GNUNET_YES)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Delaying connect, we have too many outstanding connections!\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_send_hellos, send_hello_context); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating connection, outstanding_connections is %d\n", + outstanding_connects); + if (send_hello_context->peer->daemon->th == NULL) + { + pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */ + send_hello_context->peer->daemon->th = + GNUNET_TRANSPORT_connect (send_hello_context->peer->cfg, NULL, + send_hello_context, NULL, NULL, NULL); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Offering HELLO of peer %s to peer %s\n", + send_hello_context->peer->daemon->shortname, + pg->peers[send_hello_context->peer_pos->index]. + daemon->shortname); + GNUNET_TRANSPORT_offer_hello (send_hello_context->peer->daemon->th, + (const struct GNUNET_MessageHeader *) + pg->peers[send_hello_context->peer_pos-> + index].daemon->hello, + &hello_sent_callback, send_hello_context); + send_hello_context->peer_pos = send_hello_context->peer_pos->next; + GNUNET_assert (send_hello_context->peer->daemon->th != NULL); + } +} +#endif + +/** + * Internal notification of a connection, kept so that we can ensure some connections + * happen instead of flooding all testing daemons with requests to connect. + */ +static void +internal_connect_notify (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct ConnectContext *connect_ctx = cls; + struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx; + struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; + struct PeerConnection *connection; + + GNUNET_assert (NULL != connect_ctx->cc); + connect_ctx->cc = NULL; + GNUNET_assert (0 < pg->outstanding_connects); + pg->outstanding_connects--; + GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, connect_ctx); + /* + * Check whether the inverse connection has been scheduled yet, + * if not, we can remove it from the other peers list and avoid + * even trying to connect them again! + */ + connection = pg->peers[connect_ctx->second_index].connect_peers_head; +#if BAD + other_peer = NULL; +#endif + + while ((connection != NULL) && + (0 != + memcmp (first, &pg->peers[connection->index].daemon->id, + sizeof (struct GNUNET_PeerIdentity)))) + connection = connection->next; + + if (connection != NULL) /* Can safely remove! */ + { + GNUNET_assert (0 < ct_ctx->remaining_connections); + ct_ctx->remaining_connections--; + if (pg->notify_connection != NULL) /* Notify of reverse connection */ + pg->notify_connection (pg->notify_connection_cls, second, first, distance, + second_cfg, first_cfg, second_daemon, first_daemon, + emsg); + + GNUNET_CONTAINER_DLL_remove (pg-> + peers[connect_ctx-> + second_index].connect_peers_head, + pg->peers[connect_ctx-> + second_index].connect_peers_tail, + connection); + GNUNET_free (connection); + } + + if (ct_ctx->remaining_connections == 0) + { + if (ct_ctx->notify_connections_done != NULL) + { + ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); + ct_ctx->notify_connections_done = NULL; + } + } + else + preschedule_connect (pg); + + if (pg->notify_connection != NULL) + pg->notify_connection (pg->notify_connection_cls, first, second, distance, + first_cfg, second_cfg, first_daemon, second_daemon, + emsg); + GNUNET_free (connect_ctx); +} + +/** + * Either delay a connection (because there are too many outstanding) + * or schedule it for right now. + * + * @param cls a connection context + * @param tc the task runtime context + */ +static void +schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct ConnectContext *connect_context = cls; + struct GNUNET_TESTING_PeerGroup *pg = connect_context->ct_ctx->pg; + + connect_context->task = GNUNET_SCHEDULER_NO_TASK; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + if ((pg->outstanding_connects > pg->max_outstanding_connections) || + (pg->stop_connects == GNUNET_YES)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Delaying connect, we have too many outstanding connections!\n"); + connect_context->task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_connect, connect_context); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating connection, outstanding_connections is %d (max %d)\n", + pg->outstanding_connects, pg->max_outstanding_connections); + pg->outstanding_connects++; + pg->total_connects_scheduled++; + GNUNET_assert (NULL == connect_context->cc); + connect_context->cc = + GNUNET_TESTING_daemons_connect (pg-> + peers[connect_context-> + first_index].daemon, + pg->peers[connect_context-> + second_index].daemon, + connect_context->ct_ctx->connect_timeout, + connect_context->ct_ctx->connect_attempts, +#if USE_SEND_HELLOS + GNUNET_NO, +#else + GNUNET_YES, +#endif + &internal_connect_notify, + connect_context); + +} + +#if !OLD +/** + * Iterator for actually scheduling connections to be created + * between two peers. + * + * @param cls closure, a GNUNET_TESTING_Daemon + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct ConnectTopologyContext *ct_ctx = cls; + struct PeerData *first = ct_ctx->first; + struct GNUNET_TESTING_Daemon *second = value; + struct ConnectContext *connect_context; + + connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); + connect_context->first = first->daemon; + connect_context->second = second; + connect_context->ct_ctx = ct_ctx; + connect_context->task = + GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); + GNUNET_CONTAINER_DLL_insert (ct_ctx->pg->cc_head, ct_ctx->pg->cc_tail, + connect_context); + return GNUNET_YES; +} +#endif + +#if !OLD +/** + * Iterator for copying all entries in the allowed hashmap to the + * connect hashmap. + * + * @param cls closure, a GNUNET_TESTING_Daemon + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct PeerData *first = cls; + + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key, + value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + + return GNUNET_YES; +} +#endif + +/** + * Make the peers to connect the same as those that are allowed to be + * connected. + * + * @param pg the peer group + */ +static int +copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int pg_iter; + int ret; + int total; + +#if OLD + struct PeerConnection *iter; +#endif + total = 0; + ret = 0; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + iter = pg->peers[pg_iter].allowed_peers_head; + while (iter != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating connection between %d and %d\n", pg_iter, + iter->index); + total += add_connections (pg, pg_iter, iter->index, CONNECT, GNUNET_YES); + //total += add_actual_connections(pg, pg_iter, iter->index); + iter = iter->next; + } +#else + ret = + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, + ©_topology_iterator, + &pg->peers[pg_iter]); +#endif + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + + total = total + ret; + } + + return total; +} + +/** + * Connect the topology as specified by the PeerConnection's + * of each peer in the peer group + * + * @param pg the peer group we are dealing with + * @param connect_timeout how long try connecting two peers + * @param connect_attempts how many times (max) to attempt + * @param notify_callback callback to notify when finished + * @param notify_cls closure for notify callback + * + * @return the number of connections that will be attempted + */ +static int +connect_topology (struct GNUNET_TESTING_PeerGroup *pg, + struct GNUNET_TIME_Relative connect_timeout, + unsigned int connect_attempts, + GNUNET_TESTING_NotifyCompletion notify_callback, + void *notify_cls) +{ + unsigned int pg_iter; + unsigned int total; + +#if OLD + struct PeerConnection *connection_iter; +#endif +#if USE_SEND_HELLOS + struct SendHelloContext *send_hello_context; +#endif + + total = 0; + pg->ct_ctx.notify_connections_done = notify_callback; + pg->ct_ctx.notify_cls = notify_cls; + pg->ct_ctx.pg = pg; + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + connection_iter = pg->peers[pg_iter].connect_peers_head; + while (connection_iter != NULL) + { + connection_iter = connection_iter->next; + total++; + } +#else + total += + GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers); +#endif + } + + if (total == 0) + return total; + + pg->ct_ctx.connect_timeout = connect_timeout; + pg->ct_ctx.connect_attempts = connect_attempts; + pg->ct_ctx.remaining_connections = total; + +#if USE_SEND_HELLOS + /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */ + pg->remaining_hellos = total; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + send_hello_context = GNUNET_malloc (sizeof (struct SendHelloContext)); + send_hello_context->peer = &pg->peers[pg_iter]; + send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head; + send_hello_context->pg = pg; + GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); + } +#else + for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) + { + preschedule_connect (pg); + } +#endif + return total; + +} + +/** + * Takes a peer group and creates a topology based on the + * one specified. Creates a topology means generates friend + * files for the peers so they can only connect to those allowed + * by the topology. This will only have an effect once peers + * are started if the FRIENDS_ONLY option is set in the base + * config. Also takes an optional restrict topology which + * disallows connections based on particular transports + * UNLESS they are specified in the restricted topology. + * + * @param pg the peer group struct representing the running peers + * @param topology which topology to connect the peers in + * @param restrict_topology disallow restrict_transports transport + * connections to peers NOT in this topology + * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions + * @param restrict_transports space delimited list of transports to blacklist + * to create restricted topology + * + * @return the maximum number of connections were all allowed peers + * connected to each other + */ +unsigned int +GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, + enum GNUNET_TESTING_Topology topology, + enum GNUNET_TESTING_Topology restrict_topology, + const char *restrict_transports) +{ + int ret; + + unsigned int num_connections; + int unblacklisted_connections; + char *filename; + struct PeerConnection *conn_iter; + struct PeerConnection *temp_conn; + unsigned int off; + +#if !OLD + unsigned int i; + + for (i = 0; i < pg->total; i++) + { + pg->peers[i].allowed_peers = GNUNET_CONTAINER_multihashmap_create (100); + pg->peers[i].connect_peers = GNUNET_CONTAINER_multihashmap_create (100); + pg->peers[i].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create (100); + pg->peers[i].pg = pg; + } +#endif + + switch (topology) + { + case GNUNET_TESTING_TOPOLOGY_CLIQUE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating clique topology\n"); + num_connections = create_clique (pg, &add_connections, ALLOWED, GNUNET_NO); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating small world (ring) topology\n"); + num_connections = create_small_world_ring (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating small world (2d-torus) topology\n"); + num_connections = create_small_world (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring topology\n"); + num_connections = create_ring (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_2D_TORUS: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating 2d torus topology\n"); + num_connections = create_2d_torus (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Erdos-Renyi topology\n"); + num_connections = create_erdos_renyi (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_INTERNAT: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating InterNAT topology\n"); + num_connections = create_nated_internet (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Scale Free topology\n"); + num_connections = create_scale_free (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_LINE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating straight line topology\n"); + num_connections = create_line (pg, &add_connections, ALLOWED); + break; + case GNUNET_TESTING_TOPOLOGY_FROM_FILE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating topology from file!\n"); + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing_old", + "topology_file", &filename)) + num_connections = + create_from_file (pg, filename, &add_connections, ALLOWED); + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!\n"); + num_connections = 0; + } + break; + case GNUNET_TESTING_TOPOLOGY_NONE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _ + ("Creating no allowed topology (all peers can connect at core level)\n")); + num_connections = pg->total * pg->total; /* Clique is allowed! */ + break; + default: + num_connections = 0; + break; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING_OLD", "F2F")) + { + ret = create_and_copy_friend_files (pg); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed during friend file copying!\n"); + return GNUNET_SYSERR; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Friend files created/copied successfully!\n"); + } + } + + /* Use the create clique method to initially set all connections as blacklisted. */ + if ((restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE) && + (restrict_topology != GNUNET_TESTING_TOPOLOGY_FROM_FILE)) + create_clique (pg, &add_connections, BLACKLIST, GNUNET_NO); + else + return num_connections; + + unblacklisted_connections = 0; + /* Un-blacklist connections as per the topology specified */ + switch (restrict_topology) + { + case GNUNET_TESTING_TOPOLOGY_CLIQUE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but clique topology\n"); + unblacklisted_connections = + create_clique (pg, &remove_connections, BLACKLIST, GNUNET_NO); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but small world (ring) topology\n"); + unblacklisted_connections = + create_small_world_ring (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but small world (2d-torus) topology\n"); + unblacklisted_connections = + create_small_world (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but ring topology\n"); + unblacklisted_connections = + create_ring (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_2D_TORUS: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but 2d torus topology\n"); + unblacklisted_connections = + create_2d_torus (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but Erdos-Renyi topology\n"); + unblacklisted_connections = + create_erdos_renyi (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_INTERNAT: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but InterNAT topology\n"); + +#if TOPOLOGY_HACK + for (off = 0; off < pg->total; off++) + { + conn_iter = pg->peers[off].allowed_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].allowed_peers_head = NULL; + pg->peers[off].allowed_peers_tail = NULL; + + conn_iter = pg->peers[off].connect_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].connect_peers_head = NULL; + pg->peers[off].connect_peers_tail = NULL; + } + unblacklisted_connections = + create_nated_internet_copy (pg, &remove_connections, BLACKLIST); +#else + unblacklisted_connections = + create_nated_internet (pg, &remove_connections, BLACKLIST); +#endif + + break; + case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but Scale Free topology\n"); + unblacklisted_connections = + create_scale_free (pg, &remove_connections, BLACKLIST); + break; + case GNUNET_TESTING_TOPOLOGY_LINE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklisting all but straight line topology\n"); + unblacklisted_connections = + create_line (pg, &remove_connections, BLACKLIST); + default: + break; + } + + if ((unblacklisted_connections > 0) && (restrict_transports != NULL)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating blacklist with `%s'\n", + restrict_transports); + ret = create_and_copy_blacklist_files (pg, restrict_transports); + if (ret != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed during blacklist file copying!\n"); + return 0; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Blacklist files created/copied successfully!\n"); + } + } + return num_connections; +} + +#if !OLD +/** + * Iterator for choosing random peers to connect. + * + * @param cls closure, a RandomContext + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct RandomContext *random_ctx = cls; + double random_number; + uint32_t second_pos; + GNUNET_HashCode first_hash; + + random_number = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + if (random_number < random_ctx->percentage) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (random_ctx-> + first->connect_peers_working_set, + key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + } + + /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */ + uid_from_hash (key, &second_pos); + hash_from_uid (random_ctx->first_uid, &first_hash); + GNUNET_assert (random_ctx->pg->total > second_pos); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (random_ctx-> + pg->peers + [second_pos].connect_peers, + &first_hash, + random_ctx-> + first->daemon)); + + return GNUNET_YES; +} + +/** + * Iterator for adding at least X peers to a peers connection set. + * + * @param cls closure, MinimumContext + * @param key the key the second Daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct MinimumContext *min_ctx = cls; + uint32_t second_pos; + GNUNET_HashCode first_hash; + unsigned int i; + + if (GNUNET_CONTAINER_multihashmap_size + (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add) + { + for (i = 0; i < min_ctx->num_to_add; i++) + { + if (min_ctx->pg_array[i] == min_ctx->current) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (min_ctx-> + first->connect_peers_working_set, + key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + uid_from_hash (key, &second_pos); + hash_from_uid (min_ctx->first_uid, &first_hash); + GNUNET_assert (min_ctx->pg->total > second_pos); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (min_ctx-> + pg->peers + [second_pos].connect_peers_working_set, + &first_hash, + min_ctx->first-> + daemon, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */ + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (min_ctx-> + pg->peers + [second_pos].connect_peers, + &first_hash, + min_ctx-> + first->daemon)); + } + } + min_ctx->current++; + return GNUNET_YES; + } + else + return GNUNET_NO; /* We can stop iterating, we have enough peers! */ + +} + +/** + * Iterator for adding peers to a connection set based on a depth first search. + * + * @param cls closure, MinimumContext + * @param key the key the second daemon was stored under + * @param value the GNUNET_TESTING_Daemon that the first is to connect to + * + * @return GNUNET_YES to continue iteration + */ +static int +dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct DFSContext *dfs_ctx = cls; + GNUNET_HashCode first_hash; + + if (dfs_ctx->current == dfs_ctx->chosen) + { + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> + first->connect_peers_working_set, + key, value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + uid_from_hash (key, &dfs_ctx->second_uid); + hash_from_uid (dfs_ctx->first_uid, &first_hash); + GNUNET_assert (GNUNET_OK == + GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> + pg->peers[dfs_ctx-> + second_uid].connect_peers_working_set, + &first_hash, + dfs_ctx->first->daemon, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (dfs_ctx-> + pg->peers + [dfs_ctx->second_uid].connect_peers, + &first_hash, + dfs_ctx-> + first->daemon)); + /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */ + return GNUNET_NO; /* We have found our peer, don't iterate more */ + } + + dfs_ctx->current++; + return GNUNET_YES; +} +#endif + +/** + * From the set of connections possible, choose percentage percent of connections + * to actually connect. + * + * @param pg the peergroup we are dealing with + * @param percentage what percent of total connections to make + */ +void +choose_random_connections (struct GNUNET_TESTING_PeerGroup *pg, + double percentage) +{ + uint32_t pg_iter; + +#if OLD + struct PeerConnection *conn_iter; + double random_number; +#else + struct RandomContext random_ctx; +#endif + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + conn_iter = pg->peers[pg_iter].connect_peers_head; + while (conn_iter != NULL) + { + random_number = + ((double) + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT64_MAX)) / ((double) UINT64_MAX); + if (random_number < percentage) + { + add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, + GNUNET_YES); + } + conn_iter = conn_iter->next; + } +#else + random_ctx.first_uid = pg_iter; + random_ctx.first = &pg->peers[pg_iter]; + random_ctx.percentage = percentage; + random_ctx.pg = pg; + pg->peers[pg_iter].connect_peers_working_set = + GNUNET_CONTAINER_multihashmap_create (pg->total); + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, + &random_connect_iterator, + &random_ctx); + /* Now remove the old connections */ + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); + /* And replace with the random set */ + pg->peers[pg_iter].connect_peers = + pg->peers[pg_iter].connect_peers_working_set; +#endif + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + conn_iter = pg->peers[pg_iter].connect_peers_head; + while (pg->peers[pg_iter].connect_peers_head != NULL) + remove_connections (pg, pg_iter, + pg->peers[pg_iter].connect_peers_head->index, CONNECT, + GNUNET_YES); + + pg->peers[pg_iter].connect_peers_head = + pg->peers[pg_iter].connect_peers_working_set_head; + pg->peers[pg_iter].connect_peers_tail = + pg->peers[pg_iter].connect_peers_working_set_tail; + pg->peers[pg_iter].connect_peers_working_set_head = NULL; + pg->peers[pg_iter].connect_peers_working_set_tail = NULL; + } +} + +/** + * Count the number of connections in a linked list of connections. + * + * @param conn_list the connection list to get the count of + * + * @return the number of elements in the list + */ +static unsigned int +count_connections (struct PeerConnection *conn_list) +{ + struct PeerConnection *iter; + unsigned int count; + + count = 0; + iter = conn_list; + while (iter != NULL) + { + iter = iter->next; + count++; + } + return count; +} + +static unsigned int +count_workingset_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int count; + unsigned int pg_iter; + +#if OLD + struct PeerConnection *conn_iter; +#endif + count = 0; + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + conn_iter = pg->peers[pg_iter].connect_peers_working_set_head; + while (conn_iter != NULL) + { + count++; + conn_iter = conn_iter->next; + } +#else + count += + GNUNET_CONTAINER_multihashmap_size (pg-> + peers + [pg_iter].connect_peers_working_set); +#endif + } + + return count; +} + +static unsigned int +count_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int count; + unsigned int pg_iter; + +#if OLD + struct PeerConnection *conn_iter; +#endif + + count = 0; + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { +#if OLD + conn_iter = pg->peers[pg_iter].allowed_peers_head; + while (conn_iter != NULL) + { + count++; + conn_iter = conn_iter->next; + } +#else + count += + GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].allowed_peers); +#endif + } + + return count; +} + +/** + * From the set of connections possible, choose at least num connections per + * peer. + * + * @param pg the peergroup we are dealing with + * @param num how many connections at least should each peer have (if possible)? + */ +static void +choose_minimum (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) +{ +#if !OLD + struct MinimumContext minimum_ctx; +#else + struct PeerConnection *conn_iter; + unsigned int temp_list_size; + unsigned int i; + unsigned int count; + uint32_t random; /* Random list entry to connect peer to */ +#endif + uint32_t pg_iter; + +#if OLD + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + temp_list_size = count_connections (pg->peers[pg_iter].connect_peers_head); + if (temp_list_size == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peer %d has 0 connections!?!?\n", + pg_iter); + break; + } + for (i = 0; i < num; i++) + { + random = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_list_size); + conn_iter = pg->peers[pg_iter].connect_peers_head; + for (count = 0; count < random; count++) + conn_iter = conn_iter->next; + /* We now have a random connection, connect it! */ + GNUNET_assert (conn_iter != NULL); + add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, GNUNET_YES); + } + } +#else + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + pg->peers[pg_iter].connect_peers_working_set = + GNUNET_CONTAINER_multihashmap_create (num); + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + minimum_ctx.first_uid = pg_iter; + minimum_ctx.pg_array = + GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, + GNUNET_CONTAINER_multihashmap_size + (pg->peers[pg_iter].connect_peers)); + minimum_ctx.first = &pg->peers[pg_iter]; + minimum_ctx.pg = pg; + minimum_ctx.num_to_add = num; + minimum_ctx.current = 0; + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, + &minimum_connect_iterator, + &minimum_ctx); + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + /* Remove the "old" connections */ + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); + /* And replace with the working set */ + pg->peers[pg_iter].connect_peers = + pg->peers[pg_iter].connect_peers_working_set; + } +#endif + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + while (pg->peers[pg_iter].connect_peers_head != NULL) + { + conn_iter = pg->peers[pg_iter].connect_peers_head; + GNUNET_CONTAINER_DLL_remove (pg->peers[pg_iter].connect_peers_head, + pg->peers[pg_iter].connect_peers_tail, + conn_iter); + GNUNET_free (conn_iter); + /*remove_connections(pg, pg_iter, pg->peers[pg_iter].connect_peers_head->index, CONNECT, GNUNET_YES); */ + } + + pg->peers[pg_iter].connect_peers_head = + pg->peers[pg_iter].connect_peers_working_set_head; + pg->peers[pg_iter].connect_peers_tail = + pg->peers[pg_iter].connect_peers_working_set_tail; + pg->peers[pg_iter].connect_peers_working_set_head = NULL; + pg->peers[pg_iter].connect_peers_working_set_tail = NULL; + } +} + +#if !OLD +struct FindClosestContext +{ + /** + * The currently known closest peer. + */ + struct GNUNET_TESTING_Daemon *closest; + + /** + * The info for the peer we are adding connections for. + */ + struct PeerData *curr_peer; + + /** + * The distance (bits) between the current + * peer and the currently known closest. + */ + unsigned int closest_dist; + + /** + * The offset of the closest known peer in + * the peer group. + */ + unsigned int closest_num; +}; + +/** + * Iterator over hash map entries of the allowed + * peer connections. Find the closest, not already + * connected peer and return it. + * + * @param cls closure (struct FindClosestContext) + * @param key current key code (hash of offset in pg) + * @param value value in the hash map - a GNUNET_TESTING_Daemon + * @return GNUNET_YES if we should continue to + * iterate, + * GNUNET_NO if not. + */ +static int +find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value) +{ + struct FindClosestContext *closest_ctx = cls; + struct GNUNET_TESTING_Daemon *daemon = value; + + if (((closest_ctx->closest == NULL) || + (GNUNET_CRYPTO_hash_matching_bits + (&daemon->id.hashPubKey, + &closest_ctx->curr_peer->daemon->id.hashPubKey) > + closest_ctx->closest_dist)) && + (GNUNET_YES != + GNUNET_CONTAINER_multihashmap_contains (closest_ctx-> + curr_peer->connect_peers, key))) + { + closest_ctx->closest_dist = + GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey, + &closest_ctx->curr_peer->daemon-> + id.hashPubKey); + closest_ctx->closest = daemon; + uid_from_hash (key, &closest_ctx->closest_num); + } + return GNUNET_YES; +} + +/** + * From the set of connections possible, choose at num connections per + * peer based on depth which are closest out of those allowed. Guaranteed + * to add num peers to connect to, provided there are that many peers + * in the underlay topology to connect to. + * + * @param pg the peergroup we are dealing with + * @param num how many connections at least should each peer have (if possible)? + * @param proc processor to actually add the connections + * @param list the peer list to use + */ +void +add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num, + GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) +{ +#if OLD + +#else + struct FindClosestContext closest_ctx; +#endif + uint32_t pg_iter; + uint32_t i; + + for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */ + { + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + closest_ctx.curr_peer = &pg->peers[pg_iter]; + closest_ctx.closest = NULL; + closest_ctx.closest_dist = 0; + closest_ctx.closest_num = 0; + GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, + &find_closest_peers, &closest_ctx); + if (closest_ctx.closest != NULL) + { + GNUNET_assert (closest_ctx.closest_num < pg->total); + proc (pg, pg_iter, closest_ctx.closest_num, list); + } + } + } +} +#endif + +/** + * From the set of connections possible, choose at least num connections per + * peer based on depth first traversal of peer connections. If DFS leaves + * peers unconnected, ensure those peers get connections. + * + * @param pg the peergroup we are dealing with + * @param num how many connections at least should each peer have (if possible)? + */ +void +perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) +{ + uint32_t pg_iter; + uint32_t dfs_count; + uint32_t starting_peer; + uint32_t least_connections; + uint32_t random_connection; + +#if OLD + unsigned int temp_count; + struct PeerConnection *peer_iter; +#else + struct DFSContext dfs_ctx; + GNUNET_HashCode second_hash; +#endif + +#if OLD + starting_peer = 0; + dfs_count = 0; + while ((count_workingset_connections (pg) < num * pg->total) && + (count_allowed_connections (pg) > 0)) + { + if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ + { + least_connections = -1; /* Set to very high number */ + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + temp_count = + count_connections (pg-> + peers[pg_iter].connect_peers_working_set_head); + if (temp_count < least_connections) + { + starting_peer = pg_iter; + least_connections = temp_count; + } + } + } + + temp_count = + count_connections (pg->peers[starting_peer].connect_peers_head); + if (temp_count == 0) + continue; /* FIXME: infinite loop? */ + + random_connection = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_count); + temp_count = 0; + peer_iter = pg->peers[starting_peer].connect_peers_head; + while (temp_count < random_connection) + { + peer_iter = peer_iter->next; + temp_count++; + } + GNUNET_assert (peer_iter != NULL); + add_connections (pg, starting_peer, peer_iter->index, WORKING_SET, + GNUNET_NO); + remove_connections (pg, starting_peer, peer_iter->index, CONNECT, + GNUNET_YES); + starting_peer = peer_iter->index; + dfs_count++; + } + +#else + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + pg->peers[pg_iter].connect_peers_working_set = + GNUNET_CONTAINER_multihashmap_create (num); + } + + starting_peer = 0; + dfs_count = 0; + while ((count_workingset_connections (pg) < num * pg->total) && + (count_allowed_connections (pg) > 0)) + { + if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ + { + least_connections = -1; /* Set to very high number */ + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + if (GNUNET_CONTAINER_multihashmap_size + (pg->peers[pg_iter].connect_peers_working_set) < least_connections) + { + starting_peer = pg_iter; + least_connections = + GNUNET_CONTAINER_multihashmap_size (pg-> + peers + [pg_iter].connect_peers_working_set); + } + } + } + + if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */ + { + dfs_count = 0; + continue; + } + + /* Choose a random peer from the chosen peers set of connections to add */ + dfs_ctx.chosen = + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + GNUNET_CONTAINER_multihashmap_size (pg->peers + [starting_peer].connect_peers)); + dfs_ctx.first_uid = starting_peer; + dfs_ctx.first = &pg->peers[starting_peer]; + dfs_ctx.pg = pg; + dfs_ctx.current = 0; + + GNUNET_CONTAINER_multihashmap_iterate (pg-> + peers[starting_peer].connect_peers, + &dfs_connect_iterator, &dfs_ctx); + /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */ + hash_from_uid (dfs_ctx.second_uid, &second_hash); + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (pg->peers + [starting_peer].connect_peers, + &second_hash, + pg-> + peers + [dfs_ctx.second_uid].daemon)); + starting_peer = dfs_ctx.second_uid; + } + + for (pg_iter = 0; pg_iter < pg->total; pg_iter++) + { + /* Remove the "old" connections */ + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); + /* And replace with the working set */ + pg->peers[pg_iter].connect_peers = + pg->peers[pg_iter].connect_peers_working_set; + } +#endif +} + +/** + * Internal callback for topology information for a particular peer. + */ +static void +internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_ATS_Information *atsi, + unsigned int atsi_count) +{ + struct CoreContext *core_ctx = cls; + struct TopologyIterateContext *iter_ctx = core_ctx->iter_context; + + if (peer == NULL) /* Either finished, or something went wrong */ + { + iter_ctx->completed++; + iter_ctx->connected--; + /* One core context allocated per iteration, must free! */ + GNUNET_free (core_ctx); + } + else + { + iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id, peer, NULL); + } + + if (iter_ctx->completed == iter_ctx->total) + { + iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL); + /* Once all are done, free the iteration context */ + GNUNET_free (iter_ctx); + } +} + +/** + * Check running topology iteration tasks, if below max start a new one, otherwise + * schedule for some time in the future. + */ +static void +schedule_get_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct CoreContext *core_context = cls; + struct TopologyIterateContext *topology_context = + (struct TopologyIterateContext *) core_context->iter_context; + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + if (topology_context->connected > + topology_context->pg->max_outstanding_connections) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Delaying connect, we have too many outstanding connections!\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_get_topology, core_context); + } + else + { + topology_context->connected++; + + if (GNUNET_OK != + GNUNET_CORE_iterate_peers (core_context->daemon->cfg, + &internal_topology_callback, core_context)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n"); + internal_topology_callback (core_context, NULL, NULL, 0); + } + } +} + +/** + * Iterate over all (running) peers in the peer group, retrieve + * all connections that each currently has. + */ +void +GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_NotifyTopology cb, void *cls) +{ + struct TopologyIterateContext *topology_context; + struct CoreContext *core_ctx; + unsigned int i; + unsigned int total_count; + + /* Allocate a single topology iteration context */ + topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext)); + topology_context->topology_cb = cb; + topology_context->cls = cls; + topology_context->pg = pg; + total_count = 0; + for (i = 0; i < pg->total; i++) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + /* Allocate one core context per core we need to connect to */ + core_ctx = GNUNET_malloc (sizeof (struct CoreContext)); + core_ctx->daemon = pg->peers[i].daemon; + /* Set back pointer to topology iteration context */ + core_ctx->iter_context = topology_context; + GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx); + total_count++; + } + } + if (total_count == 0) + { + cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!"); + GNUNET_free (topology_context); + } + else + topology_context->total = total_count; + return; +} + +/** + * Callback function to process statistic values. + * This handler is here only really to insert a peer + * identity (or daemon) so the statistics can be uniquely + * tied to a single running peer. + * + * @param cls closure + * @param subsystem name of subsystem that created the statistic + * @param name the name of the datum + * @param value the current value + * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not + * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + */ +static int +internal_stats_callback (void *cls, const char *subsystem, const char *name, + uint64_t value, int is_persistent) +{ + struct StatsCoreContext *core_context = cls; + struct StatsIterateContext *stats_context = + (struct StatsIterateContext *) core_context->iter_context; + + return stats_context->proc (stats_context->cls, &core_context->daemon->id, + subsystem, name, value, is_persistent); +} + + +/** + * We don't need the statistics handle anymore, destroy it. + * + * @param cls Closure (the statistics handle to destroy) + * @param tc Task Context + */ +static void +internal_destroy_statistics (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_STATISTICS_Handle *h = cls; + + GNUNET_STATISTICS_destroy (h, GNUNET_NO); +} + + +/** + * Internal continuation call for statistics iteration. + * + * @param cls closure, the CoreContext for this iteration + * @param success whether or not the statistics iterations + * was canceled or not (we don't care) + */ +static void +internal_stats_cont (void *cls, int success) +{ + struct StatsCoreContext *core_context = cls; + struct StatsIterateContext *stats_context = + (struct StatsIterateContext *) core_context->iter_context; + + stats_context->connected--; + stats_context->completed++; + + if (stats_context->completed == stats_context->total) + { + stats_context->cont (stats_context->cls, GNUNET_YES); + GNUNET_free (stats_context); + } + + if (core_context->stats_handle != NULL) + /* Cannot destroy handle inside the continuation */ + GNUNET_SCHEDULER_add_now (&internal_destroy_statistics, + core_context->stats_handle); + + GNUNET_free (core_context); +} + +/** + * Check running topology iteration tasks, if below max start a new one, otherwise + * schedule for some time in the future. + */ +static void +schedule_get_statistics (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct StatsCoreContext *core_context = cls; + struct StatsIterateContext *stats_context = + (struct StatsIterateContext *) core_context->iter_context; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + return; + + if (stats_context->connected > stats_context->pg->max_outstanding_connections) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Delaying connect, we have too many outstanding connections!\n"); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_get_statistics, core_context); + } + else + { + stats_context->connected++; + core_context->stats_handle = + GNUNET_STATISTICS_create ("testing_old", core_context->daemon->cfg); + if (core_context->stats_handle == NULL) + { + internal_stats_cont (core_context, GNUNET_NO); + return; + } + + core_context->stats_get_handle = + GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL, + GNUNET_TIME_UNIT_FOREVER_REL, + &internal_stats_cont, &internal_stats_callback, + core_context); + if (core_context->stats_get_handle == NULL) + internal_stats_cont (core_context, GNUNET_NO); + + } +} + +struct DuplicateStats +{ + /** + * Next item in the list + */ + struct DuplicateStats *next; + + /** + * Nasty string, concatenation of relevant information. + */ + char *unique_string; +}; + +/** + * Check whether the combination of port/host/unix domain socket + * already exists in the list of peers being checked for statistics. + * + * @param pg the peergroup in question + * @param specific_peer the peer we're concerned with + * @param stats_list the list to return to the caller + * + * @return GNUNET_YES if the statistics instance has been seen already, + * GNUNET_NO if not (and we may have added it to the list) + */ +static int +stats_check_existing (struct GNUNET_TESTING_PeerGroup *pg, + struct PeerData *specific_peer, + struct DuplicateStats **stats_list) +{ + struct DuplicateStats *pos; + char *unix_domain_socket; + unsigned long long port; + char *to_match; + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing_old", + "single_statistics_per_host")) + return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */ + + pos = *stats_list; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg, "statistics", + "unixpath", &unix_domain_socket)) + return GNUNET_NO; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics", + "port", &port)) + { + GNUNET_free (unix_domain_socket); + return GNUNET_NO; + } + + if (specific_peer->daemon->hostname != NULL) + GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname, + unix_domain_socket, port); + else + GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port); + + while (pos != NULL) + { + if (0 == strcmp (to_match, pos->unique_string)) + { + GNUNET_free (unix_domain_socket); + GNUNET_free (to_match); + return GNUNET_YES; + } + pos = pos->next; + } + pos = GNUNET_malloc (sizeof (struct DuplicateStats)); + pos->unique_string = to_match; + pos->next = *stats_list; + *stats_list = pos; + GNUNET_free (unix_domain_socket); + return GNUNET_NO; +} + +/** + * Iterate over all (running) peers in the peer group, retrieve + * all statistics from each. + * + * @param pg the peergroup to iterate statistics of + * @param cont continuation to call once all stats have been retrieved + * @param proc processing function for each statistic from each peer + * @param cls closure to pass to proc + * + */ +void +GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_STATISTICS_Callback cont, + GNUNET_TESTING_STATISTICS_Iterator proc, + void *cls) +{ + struct StatsIterateContext *stats_context; + struct StatsCoreContext *core_ctx; + unsigned int i; + unsigned int total_count; + struct DuplicateStats *stats_list; + struct DuplicateStats *pos; + + stats_list = NULL; + + /* Allocate a single stats iteration context */ + stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext)); + stats_context->cont = cont; + stats_context->proc = proc; + stats_context->cls = cls; + stats_context->pg = pg; + total_count = 0; + + for (i = 0; i < pg->total; i++) + { + if ((pg->peers[i].daemon->running == GNUNET_YES) && + (GNUNET_NO == stats_check_existing (pg, &pg->peers[i], &stats_list))) + { + /* Allocate one core context per core we need to connect to */ + core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext)); + core_ctx->daemon = pg->peers[i].daemon; + /* Set back pointer to topology iteration context */ + core_ctx->iter_context = stats_context; + GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx); + total_count++; + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Retrieving stats from %u total instances.\n", total_count); + if (0 != total_count) + stats_context->total = total_count; + else + GNUNET_free (stats_context); + if (stats_list != NULL) + { + pos = stats_list; + while (pos != NULL) + { + GNUNET_free (pos->unique_string); + stats_list = pos->next; + GNUNET_free (pos); + pos = stats_list->next; + } + } + return; +} + +/** + * Stop the connection process temporarily. + * + * @param pg the peer group to stop connecting + */ +void +GNUNET_TESTING_stop_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + pg->stop_connects = GNUNET_YES; +} + +/** + * Resume the connection process temporarily. + * + * @param pg the peer group to resume connecting + */ +void +GNUNET_TESTING_resume_connections (struct GNUNET_TESTING_PeerGroup *pg) +{ + pg->stop_connects = GNUNET_NO; +} + +/** + * There are many ways to connect peers that are supported by this function. + * To connect peers in the same topology that was created via the + * GNUNET_TESTING_create_topology, the topology variable must be set to + * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, + * a new instance of that topology will be generated and attempted to be + * connected. This could result in some connections being impossible, + * because some topologies are non-deterministic. + * + * @param pg the peer group struct representing the running peers + * @param topology which topology to connect the peers in + * @param options options for connecting the topology + * @param option_modifier modifier for options that take a parameter + * @param connect_timeout how long to wait before giving up on connecting + * two peers + * @param connect_attempts how many times to attempt to connect two peers + * over the connect_timeout duration + * @param notify_callback notification to be called once all connections completed + * @param notify_cls closure for notification callback + * + * @return the number of connections that will be attempted, GNUNET_SYSERR on error + */ +int +GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, + enum GNUNET_TESTING_Topology topology, + enum GNUNET_TESTING_TopologyOption options, + double option_modifier, + struct GNUNET_TIME_Relative connect_timeout, + unsigned int connect_attempts, + GNUNET_TESTING_NotifyCompletion + notify_callback, void *notify_cls) +{ + switch (topology) + { + case GNUNET_TESTING_TOPOLOGY_CLIQUE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating clique CONNECT topology\n"); + create_clique (pg, &add_connections, CONNECT, GNUNET_NO); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating small world (ring) CONNECT topology\n"); + create_small_world_ring (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating small world (2d-torus) CONNECT topology\n"); + create_small_world (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_RING: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring CONNECT topology\n"); + create_ring (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_2D_TORUS: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating 2d torus CONNECT topology\n"); + create_2d_torus (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating Erdos-Renyi CONNECT topology\n"); + create_erdos_renyi (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_INTERNAT: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating InterNAT CONNECT topology\n"); + create_nated_internet (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating Scale Free CONNECT topology\n"); + create_scale_free (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_LINE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating straight line CONNECT topology\n"); + create_line (pg, &add_connections, CONNECT); + break; + case GNUNET_TESTING_TOPOLOGY_NONE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating no CONNECT topology\n"); + copy_allowed_topology (pg); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Unknown topology specification, can't connect peers!\n")); + return GNUNET_SYSERR; + } + + switch (options) + { + case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting random subset (%'.2f percent) of possible peers\n", + 100 * option_modifier); + choose_random_connections (pg, option_modifier); + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting a minimum of %u peers each (if possible)\n", + (unsigned int) option_modifier); + choose_minimum (pg, (unsigned int) option_modifier); + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Using DFS to connect a minimum of %u peers each (if possible)\n", + (unsigned int) option_modifier); +#if FIXME + perform_dfs (pg, (int) option_modifier); +#endif + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finding additional %u closest peers each (if possible)\n", + (unsigned int) option_modifier); +#if FIXME + add_closest (pg, (unsigned int) option_modifier, &add_connections, CONNECT); +#endif + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_NONE: + break; + case GNUNET_TESTING_TOPOLOGY_OPTION_ALL: + break; + default: + break; + } + + return connect_topology (pg, connect_timeout, connect_attempts, + notify_callback, notify_cls); +} + +/** + * Lookup and return the number of SSH connections to a host. + * + * @param hostname the hostname to lookup in the list + * @param pg the peergroup that the host belongs to + * + * @return the number of current ssh connections to the host + */ +static unsigned int +count_outstanding_at_host (const char *hostname, + struct GNUNET_TESTING_PeerGroup *pg) +{ + struct OutstandingSSH *pos; + + pos = pg->ssh_head; + while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) + pos = pos->next; + GNUNET_assert (pos != NULL); + return pos->outstanding; +} + +/** + * Increment the number of SSH connections to a host by one. + * + * @param hostname the hostname to lookup in the list + * @param pg the peergroup that the host belongs to + * + */ +static void +increment_outstanding_at_host (const char *hostname, + struct GNUNET_TESTING_PeerGroup *pg) +{ + struct OutstandingSSH *pos; + + pos = pg->ssh_head; + while ((NULL != pos) && (strcmp (pos->hostname, hostname) != 0)) + pos = pos->next; + GNUNET_assert (NULL != pos); + pos->outstanding++; +} + +/** + * Decrement the number of SSH connections to a host by one. + * + * @param hostname the hostname to lookup in the list + * @param pg the peergroup that the host belongs to + * + */ +static void +decrement_outstanding_at_host (const char *hostname, + struct GNUNET_TESTING_PeerGroup *pg) +{ + struct OutstandingSSH *pos; + + pos = pg->ssh_head; + while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) + pos = pos->next; + GNUNET_assert (pos != NULL); + pos->outstanding--; +} + +/** + * Callback that is called whenever a hostkey is generated + * for a peer. Call the real callback and decrement the + * starting counter for the peergroup. + * + * @param cls closure + * @param id identifier for the daemon, NULL on error + * @param d handle for the daemon + * @param emsg error message (NULL on success) + */ +static void +internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct InternalStartContext *internal_context = cls; + + internal_context->peer->pg->starting--; + internal_context->peer->pg->started++; + if (internal_context->hostname != NULL) + decrement_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + if (internal_context->hostkey_callback != NULL) + internal_context->hostkey_callback (internal_context->hostkey_cls, id, d, + emsg); + else if (internal_context->peer->pg->started == + internal_context->peer->pg->total) + { + internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */ + GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg); + } +} + +/** + * Callback that is called whenever a peer has finished starting. + * Call the real callback and decrement the starting counter + * for the peergroup. + * + * @param cls closure + * @param id identifier for the daemon, NULL on error + * @param cfg config + * @param d handle for the daemon + * @param emsg error message (NULL on success) + */ +static void +internal_startup_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct InternalStartContext *internal_context = cls; + + internal_context->peer->pg->starting--; + if (internal_context->hostname != NULL) + decrement_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + if (internal_context->start_cb != NULL) + internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d, + emsg); +} + + +/** + * Calls GNUNET_TESTING_daemon_continue_startup to set the daemon's state + * from HOSTKEY_CREATED to TOPOLOGY_SETUP. Makes sure not to saturate a host + * with requests delaying them when needed. + * + * @param cls closure: internal context of the daemon. + * @param tc TaskContext + */ +static void +internal_continue_startup (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InternalStartContext *internal_context = cls; + + internal_context->peer->startup_task = GNUNET_SCHEDULER_NO_TASK; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + return; + } + + if ((internal_context->peer->pg->starting < + internal_context->peer->pg->max_concurrent_ssh) || + ((internal_context->hostname != NULL) && + (count_outstanding_at_host + (internal_context->hostname, + internal_context->peer->pg) < + internal_context->peer->pg->max_concurrent_ssh))) + { + if (internal_context->hostname != NULL) + increment_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + internal_context->peer->pg->starting++; + GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon); + } + else + { + internal_context->peer->startup_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &internal_continue_startup, + internal_context); + } +} + +/** + * Callback for informing us about a successful + * or unsuccessful churn start call. + * + * @param cls a ChurnContext + * @param id the peer identity of the started peer + * @param cfg the handle to the configuration of the peer + * @param d handle to the daemon for the peer + * @param emsg NULL on success, non-NULL on failure + * + */ +void +churn_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct ChurnRestartContext *startup_ctx = cls; + struct ChurnContext *churn_ctx = startup_ctx->churn_ctx; + + unsigned int total_left; + char *error_message; + + error_message = NULL; + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Churn stop callback failed with error `%s'\n", emsg); + churn_ctx->num_failed_start++; + } + else + { + churn_ctx->num_to_start--; + } + + total_left = + (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + + (churn_ctx->num_to_start - churn_ctx->num_failed_start); + + if (total_left == 0) + { + if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) + GNUNET_asprintf (&error_message, + "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", + churn_ctx->num_failed_start, churn_ctx->num_failed_stop); + churn_ctx->cb (churn_ctx->cb_cls, error_message); + GNUNET_free_non_null (error_message); + GNUNET_free (churn_ctx); + GNUNET_free (startup_ctx); + } +} + +static void +schedule_churn_restart (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerRestartContext *peer_restart_ctx = cls; + struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx; + + if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_churn_restart, peer_restart_ctx); + else + { + if (startup_ctx->churn_ctx->service != NULL) + GNUNET_TESTING_daemon_start_stopped_service (peer_restart_ctx->daemon, + startup_ctx-> + churn_ctx->service, + startup_ctx->timeout, + &churn_start_callback, + startup_ctx); + else + GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon, + startup_ctx->timeout, + &churn_start_callback, startup_ctx); + GNUNET_free (peer_restart_ctx); + } +} + +/** + * Callback for informing us about a successful + * or unsuccessful churn start call. + * + * @param cls a struct ServiceStartContext *startup_ctx + * @param id the peer identity of the started peer + * @param cfg the handle to the configuration of the peer + * @param d handle to the daemon for the peer + * @param emsg NULL on success, non-NULL on failure + * + */ +void +service_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct ServiceStartContext *startup_ctx = (struct ServiceStartContext *) cls; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Service start failed with error `%s'\n", emsg); + } + + startup_ctx->outstanding--; + startup_ctx->remaining--; + + if (startup_ctx->remaining == 0) + { + startup_ctx->cb (startup_ctx->cb_cls, NULL); + GNUNET_free (startup_ctx->service); + GNUNET_free (startup_ctx); + } +} + +static void +schedule_service_start (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerServiceStartContext *peer_ctx = cls; + struct ServiceStartContext *startup_ctx = peer_ctx->start_ctx; + + if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_service_start, peer_ctx); + else + { + + GNUNET_TESTING_daemon_start_service (peer_ctx->daemon, startup_ctx->service, + startup_ctx->timeout, + &service_start_callback, startup_ctx); + GNUNET_free (peer_ctx); + } +} + + +static void +internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InternalStartContext *internal_context = cls; + + if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) + { + return; + } + + if ((internal_context->peer->pg->starting < + internal_context->peer->pg->max_concurrent_ssh) || + ((internal_context->hostname != NULL) && + (count_outstanding_at_host + (internal_context->hostname, + internal_context->peer->pg) < + internal_context->peer->pg->max_concurrent_ssh))) + { + if (internal_context->hostname != NULL) + increment_outstanding_at_host (internal_context->hostname, + internal_context->peer->pg); + internal_context->peer->pg->starting++; + internal_context->peer->daemon = + GNUNET_TESTING_daemon_start (internal_context->peer->cfg, + internal_context->timeout, GNUNET_NO, + internal_context->hostname, + internal_context->username, + internal_context->sshport, + internal_context->hostkey, + &internal_hostkey_callback, + internal_context, + &internal_startup_callback, + internal_context); + } + else + { + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &internal_start, internal_context); + } +} + +#if USE_START_HELPER + +struct PeerStartHelperContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + + struct HostData *host; + + struct GNUNET_OS_Process *proc; +}; + +static void +check_peers_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerStartHelperContext *helper = cls; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + unsigned int i; + GNUNET_TESTING_NotifyDaemonRunning cb; + + if (GNUNET_NO == GNUNET_OS_process_status (helper->proc, &type, &code)) /* Still running, wait some more! */ + { + GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, + &check_peers_started, helper); + return; + } + + helper->pg->starting--; + if (helper->pg->starting == 0) /* All peers have finished starting! */ + { + /* Call the peer started callback for each peer, set proper FSM state (?) */ + for (i = 0; i < helper->pg->total; i++) + { + cb = helper->pg->peers[i].daemon->cb; + helper->pg->peers[i].daemon->cb = NULL; + helper->pg->peers[i].daemon->running = GNUNET_YES; + helper->pg->peers[i].daemon->phase = SP_START_DONE; + if (NULL != cb) + { + if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) + cb (helper->pg->peers[i].daemon->cb_cls, + &helper->pg->peers[i].daemon->id, + helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, + "Failed to execute peerStartHelper.pl, or return code bad!"); + else + cb (helper->pg->peers[i].daemon->cb_cls, + &helper->pg->peers[i].daemon->id, + helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, + NULL); + + } + + } + } + GNUNET_OS_process_destroy (helper->proc); +} + +static void +start_peer_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerStartHelperContext *helper = cls; + char *baseservicehome; + char *tempdir; + char *arg; + + /* ssh user@host peerStartHelper /path/to/basedirectory */ + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (helper->pg->cfg, + "PATHS", "SERVICEHOME", + &baseservicehome)); + GNUNET_asprintf (&tempdir, "%s/%s/", baseservicehome, helper->host->hostname); + if (NULL != helper->host->username) + GNUNET_asprintf (&arg, "%s@%s", helper->host->username, + helper->host->hostname); + else + GNUNET_asprintf (&arg, "%s", helper->host->hostname); + + /* FIXME: Doesn't support ssh_port option! */ + helper->proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, + "peerStartHelper.pl", tempdir, NULL); + GNUNET_assert (helper->proc != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting peers with cmd ssh %s %s %s\n", + arg, "peerStartHelper.pl", tempdir); + GNUNET_SCHEDULER_add_now (&check_peers_started, helper); + GNUNET_free (tempdir); + GNUNET_free (baseservicehome); + GNUNET_free (arg); +} +#endif + +/** + * Function which continues a peer group starting up + * after successfully generating hostkeys for each peer. + * + * @param pg the peer group to continue starting + * + */ +void +GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int i; + +#if USE_START_HELPER + if ((pg->num_hosts > 0) && (pg->hostkey_data != NULL)) + { + struct PeerStartHelperContext *helper; + + pg->starting = pg->num_hosts; + for (i = 0; i < pg->num_hosts; i++) + { + helper = GNUNET_malloc (sizeof (struct PeerStartHelperContext)); + helper->pg = pg; + helper->host = &pg->hosts[i]; + GNUNET_SCHEDULER_add_now (&start_peer_helper, helper); + } + } + else + { + pg->starting = 0; + for (i = 0; i < pg->total; i++) + { + pg->peers[i].startup_task = + GNUNET_SCHEDULER_add_now (&internal_continue_startup, + &pg->peers[i].internal_context); + } + } +#else + pg->starting = 0; + for (i = 0; i < pg->total; i++) + { + pg->peers[i].startup_task = + GNUNET_SCHEDULER_add_now (&internal_continue_startup, + &pg->peers[i].internal_context); + } +#endif +} + +#if USE_START_HELPER +static void +call_hostkey_callbacks (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct GNUNET_TESTING_PeerGroup *pg = cls; + unsigned int i; + + for (i = 0; i < pg->total; i++) + { + if (pg->peers[i].internal_context.hostkey_callback != NULL) + pg->peers[i].internal_context.hostkey_callback (pg->peers[i]. + internal_context.hostkey_cls, + &pg->peers[i].daemon->id, + pg->peers[i].daemon, + NULL); + } + + if (pg->peers[0].internal_context.hostkey_callback == NULL) + GNUNET_TESTING_daemons_continue_startup (pg); +} +#endif + +/** + * Start count gnunet instances with the same set of transports and + * applications. The port numbers (any option called "PORT") will be + * adjusted to ensure that no two peers running on the same system + * have the same port(s) in their respective configurations. + * + * @param cfg configuration template to use + * @param total number of daemons to start + * @param max_concurrent_connections for testing, how many peers can + * we connect to simultaneously + * @param max_concurrent_ssh when starting with ssh, how many ssh + * connections will we allow at once (based on remote hosts allowed!) + * @param timeout total time allowed for peers to start + * @param hostkey_callback function to call on each peers hostkey generation + * if NULL, peers will be started by this call, if non-null, + * GNUNET_TESTING_daemons_continue_startup must be called after + * successful hostkey generation + * @param hostkey_cls closure for hostkey callback + * @param cb function to call on each daemon that was started + * @param cb_cls closure for cb + * @param connect_callback function to call each time two hosts are connected + * @param connect_callback_cls closure for connect_callback + * @param hostnames linked list of host structs to use to start peers on + * (NULL to run on localhost only) + * + * @return NULL on error, otherwise handle to control peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int total, + unsigned int max_concurrent_connections, + unsigned int max_concurrent_ssh, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyHostkeyCreated + hostkey_callback, void *hostkey_cls, + GNUNET_TESTING_NotifyDaemonRunning cb, + void *cb_cls, + GNUNET_TESTING_NotifyConnection connect_callback, + void *connect_callback_cls, + const struct GNUNET_TESTING_Host *hostnames) +{ + struct GNUNET_TESTING_PeerGroup *pg; + const struct GNUNET_TESTING_Host *hostpos; + const char *hostname; + const char *username; + char *baseservicehome; + char *newservicehome; + char *tmpdir; + char *hostkeys_file; + char *arg; + char *ssh_port_str; + struct GNUNET_DISK_FileHandle *fd; + struct GNUNET_CONFIGURATION_Handle *pcfg; + unsigned int off; + struct OutstandingSSH *ssh_entry; + unsigned int hostcnt; + unsigned int i; + uint16_t minport; + uint16_t sshport; + uint32_t upnum; + uint32_t fdnum; + uint64_t fs; + uint64_t total_hostkeys; + struct GNUNET_OS_Process *proc; + + username = NULL; + if (0 == total) + { + GNUNET_break (0); + return NULL; + } + + upnum = 0; + fdnum = 0; + pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup)); + pg->cfg = cfg; + pg->notify_connection = connect_callback; + pg->notify_connection_cls = connect_callback_cls; + pg->total = total; + pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); + pg->peers = GNUNET_malloc (total * sizeof (struct PeerData)); + pg->max_outstanding_connections = max_concurrent_connections; + pg->max_concurrent_ssh = max_concurrent_ssh; + if (NULL != hostnames) + { + off = 0; + hostpos = hostnames; + while (hostpos != NULL) + { + hostpos = hostpos->next; + off++; + } + pg->hosts = GNUNET_malloc (off * sizeof (struct HostData)); + off = 0; + + hostpos = hostnames; + while (hostpos != NULL) + { + pg->hosts[off].minport = LOW_PORT; + pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname); + if (hostpos->username != NULL) + pg->hosts[off].username = GNUNET_strdup (hostpos->username); + pg->hosts[off].sshport = hostpos->port; + hostpos = hostpos->next; + off++; + } + + if (off == 0) + { + pg->hosts = NULL; + } + hostcnt = off; + minport = 0; + pg->num_hosts = off; + } + else + { + hostcnt = 0; + minport = LOW_PORT; + } + + /* Create the servicehome directory for each remote peer */ + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", + "SERVICEHOME", + &baseservicehome)); + for (i = 0; i < pg->num_hosts; i++) + { + ssh_entry = GNUNET_malloc (sizeof (struct OutstandingSSH)); + ssh_entry->hostname = pg->hosts[i].hostname; /* Don't free! */ + GNUNET_CONTAINER_DLL_insert (pg->ssh_head, pg->ssh_tail, ssh_entry); + GNUNET_asprintf (&tmpdir, "%s/%s", baseservicehome, pg->hosts[i].hostname); + if (NULL != pg->hosts[i].username) + GNUNET_asprintf (&arg, "%s@%s", pg->hosts[i].username, + pg->hosts[i].hostname); + else + GNUNET_asprintf (&arg, "%s", pg->hosts[i].hostname); + if (pg->hosts[i].sshport != 0) + { + GNUNET_asprintf (&ssh_port_str, "%d", pg->hosts[i].sshport); + proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-P", ssh_port_str, + "-q", + arg, "mkdir -p", tmpdir, NULL); + } + else + proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, "mkdir -p", + tmpdir, NULL); + GNUNET_assert (proc != NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating remote dir with command ssh %s %s %s\n", arg, + " mkdir -p ", tmpdir); + GNUNET_free (tmpdir); + GNUNET_free (arg); + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_destroy (proc); + } + GNUNET_free (baseservicehome); + baseservicehome = NULL; + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING_OLD", "HOSTKEYSFILE", + &hostkeys_file)) + { + if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Could not read hostkeys file!\n")); + else + { + /* Check hostkey file size, read entire thing into memory */ + fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fd) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", + hostkeys_file); + GNUNET_free (hostkeys_file); + for (i = 0; i < pg->num_hosts; i++) + { + GNUNET_free (pg->hosts[i].hostname); + GNUNET_free_non_null (pg->hosts[i].username); + } + GNUNET_free (pg->peers); + GNUNET_free (pg->hosts); + GNUNET_free (pg); + return NULL; + } + + if (GNUNET_OK != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES, GNUNET_YES)) + fs = 0; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found file size %llu for hostkeys\n", fs); + if (0 != (fs % HOSTKEYFILESIZE)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "File size %llu seems incorrect for hostkeys...\n", fs); + } + else + { + total_hostkeys = fs / HOSTKEYFILESIZE; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Will read %llu hostkeys from file\n", total_hostkeys); + pg->hostkey_data = GNUNET_malloc_large (fs); + GNUNET_assert (fs == GNUNET_DISK_file_read (fd, pg->hostkey_data, fs)); + } + GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); + } + GNUNET_free (hostkeys_file); + } + + for (off = 0; off < total; off++) + { + if (hostcnt > 0) + { + hostname = pg->hosts[off % hostcnt].hostname; + username = pg->hosts[off % hostcnt].username; + sshport = pg->hosts[off % hostcnt].sshport; + pcfg = + GNUNET_TESTING_create_cfg (cfg, off, &pg->hosts[off % hostcnt].minport, &upnum, + hostname, &fdnum); + } + else + { + hostname = NULL; + username = NULL; + sshport = 0; + pcfg = GNUNET_TESTING_create_cfg (cfg, off, &minport, &upnum, hostname, &fdnum); + } + + if (NULL == pcfg) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Could not create configuration for peer number %u on `%s'!\n"), + off, hostname == NULL ? "localhost" : hostname); + continue; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME", + &baseservicehome)) + { + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/%d/", baseservicehome, + hostname, off); + else + GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off); + GNUNET_free (baseservicehome); + baseservicehome = NULL; + } + else + { + tmpdir = getenv ("TMPDIR"); + tmpdir = tmpdir ? tmpdir : "/tmp"; + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/%s/%d/", tmpdir, hostname, + "gnunet-testing-test-test", off); + else + GNUNET_asprintf (&newservicehome, "%s/%s/%d/", tmpdir, + "gnunet-testing-test-test", off); + } + GNUNET_CONFIGURATION_set_value_string (pcfg, "PATHS", "SERVICEHOME", + newservicehome); + GNUNET_free (newservicehome); + pg->peers[off].cfg = pcfg; + pg->peers[off].pg = pg; + pg->peers[off].internal_context.peer = &pg->peers[off]; + pg->peers[off].internal_context.timeout = timeout; + pg->peers[off].internal_context.hostname = hostname; + pg->peers[off].internal_context.username = username; + pg->peers[off].internal_context.sshport = sshport; + if (pg->hostkey_data != NULL) + pg->peers[off].internal_context.hostkey = + &pg->hostkey_data[off * HOSTKEYFILESIZE]; + pg->peers[off].internal_context.hostkey_callback = hostkey_callback; + pg->peers[off].internal_context.hostkey_cls = hostkey_cls; + pg->peers[off].internal_context.start_cb = cb; + pg->peers[off].internal_context.start_cb_cls = cb_cls; +#if !USE_START_HELPER + GNUNET_SCHEDULER_add_now (&internal_start, + &pg->peers[off].internal_context); +#else + if ((pg->hostkey_data != NULL) && (hostcnt > 0)) + { + pg->peers[off].daemon = + GNUNET_TESTING_daemon_start (pcfg, timeout, GNUNET_YES, hostname, + username, sshport, + pg->peers[off].internal_context.hostkey, + &internal_hostkey_callback, + &pg->peers[off].internal_context, + &internal_startup_callback, + &pg->peers[off].internal_context); + /** + * At this point, given that we had a hostkeyfile, + * we can call the hostkey callback! + * But first, we should copy (rsync) all of the configs + * and hostkeys to the remote peers. Then let topology + * creation happen, then call the peer start helper processes, + * then set pg->whatever_phase for each peer and let them + * enter the fsm to get the HELLO's for peers and start connecting. + */ + } + else + { + GNUNET_SCHEDULER_add_now (&internal_start, + &pg->peers[off].internal_context); + } + +#endif + } + +#if USE_START_HELPER /* Now the peergroup has been set up, hostkeys and configs written to files. */ + if ((pg->hostkey_data != NULL) && (hostcnt > 0)) + { + for (off = 0; off < hostcnt; off++) + { + + if (hostcnt > 0) + { + hostname = pg->hosts[off % hostcnt].hostname; + username = pg->hosts[off % hostcnt].username; + sshport = pg->hosts[off % hostcnt].sshport; + } + else + { + hostname = NULL; + username = NULL; + sshport = 0; + } + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", + &baseservicehome)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "baseservice home is %s\n", + baseservicehome); + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/", baseservicehome, + hostname); + else + GNUNET_asprintf (&newservicehome, "%s/", baseservicehome); + GNUNET_free (baseservicehome); + baseservicehome = NULL; + } + else + { + tmpdir = getenv ("TMPDIR"); + tmpdir = tmpdir ? tmpdir : "/tmp"; + if (hostname != NULL) + GNUNET_asprintf (&newservicehome, "%s/%s/%s/", tmpdir, hostname, + "gnunet-testing-test-test"); + else + GNUNET_asprintf (&newservicehome, "%s/%s/", tmpdir, + "gnunet-testing-test-test", off); + } + + if (NULL != username) + GNUNET_asprintf (&arg, "%s@%s:%s", username, pg->hosts[off].hostname, + newservicehome); + else + GNUNET_asprintf (&arg, "%s:%s", pg->hosts[off].hostname, + newservicehome); + + /* FIXME: Doesn't support ssh_port option! */ + proc = + GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "rsync", "rsync", "-r", + newservicehome, arg, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "copying directory with command rsync -r %s %s\n", + newservicehome, arg); + GNUNET_free (newservicehome); + GNUNET_free (arg); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ + ("Could not start `%s' process to copy configuration directory.\n"), + "scp"); + GNUNET_assert (0); + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_destroy (proc); + } + /* Now all the configuration files and hostkeys are copied to the remote host. Call the hostkey callback for each peer! */ + GNUNET_SCHEDULER_add_now (&call_hostkey_callbacks, pg); + } +#endif + return pg; +} + +/* + * Get a daemon by number, so callers don't have to do nasty + * offsetting operation. + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, + unsigned int position) +{ + if (position < pg->total) + return pg->peers[position].daemon; + return NULL; +} + +/* + * Get a daemon by peer identity, so callers can + * retrieve the daemon without knowing it's offset. + * + * @param pg the peer group to retrieve the daemon from + * @param peer_id the peer identity of the daemon to retrieve + * + * @return the daemon on success, or NULL if no such peer identity is found + */ +struct GNUNET_TESTING_Daemon * +GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, + const struct GNUNET_PeerIdentity *peer_id) +{ + unsigned int i; + + for (i = 0; i < pg->total; i++) + { + if (0 == + memcmp (&pg->peers[i].daemon->id, peer_id, + sizeof (struct GNUNET_PeerIdentity))) + return pg->peers[i].daemon; + } + return NULL; +} + +/** + * Prototype of a function that will be called when a + * particular operation was completed the testing library. + * + * @param cls closure (a struct RestartContext) + * @param id id of the peer that was restarted + * @param cfg handle to the configuration of the peer + * @param d handle to the daemon that was restarted + * @param emsg NULL on success + */ +static void +restart_callback (void *cls, const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct RestartContext *restart_context = cls; + + if (emsg == NULL) + { + restart_context->peers_restarted++; + } + else + { + restart_context->peers_restart_failed++; + } + + if (restart_context->peers_restarted == restart_context->peer_group->total) + { + restart_context->callback (restart_context->callback_cls, NULL); + GNUNET_free (restart_context); + } + else if (restart_context->peers_restart_failed + + restart_context->peers_restarted == + restart_context->peer_group->total) + { + restart_context->callback (restart_context->callback_cls, + "Failed to restart peers!"); + GNUNET_free (restart_context); + } + +} + +/** + * Callback for informing us about a successful + * or unsuccessful churn stop call. + * + * @param cls a ChurnContext + * @param emsg NULL on success, non-NULL on failure + * + */ +static void +churn_stop_callback (void *cls, const char *emsg) +{ + struct ShutdownContext *shutdown_ctx = cls; + struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls; + unsigned int total_left; + char *error_message; + + error_message = NULL; + shutdown_ctx->outstanding--; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Churn stop callback failed with error `%s'\n", emsg); + churn_ctx->num_failed_stop++; + } + else + { + churn_ctx->num_to_stop--; + } + + total_left = + (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + + (churn_ctx->num_to_start - churn_ctx->num_failed_start); + + if (total_left == 0) + { + if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) + { + GNUNET_asprintf (&error_message, + "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", + churn_ctx->num_failed_start, churn_ctx->num_failed_stop); + } + churn_ctx->cb (churn_ctx->cb_cls, error_message); + GNUNET_free_non_null (error_message); + GNUNET_free (churn_ctx); + GNUNET_free (shutdown_ctx); + } +} + +/** + * Count the number of running peers. + * + * @param pg handle for the peer group + * + * @return the number of currently running peers in the peer group + */ +unsigned int +GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg) +{ + unsigned int i; + unsigned int running = 0; + + for (i = 0; i < pg->total; i++) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + GNUNET_assert (running != -1); + running++; + } + } + return running; +} + +/** + * Task to rate limit the number of outstanding peer shutdown + * requests. This is necessary for making sure we don't do + * too many ssh connections at once, but is generally nicer + * to any system as well (graduated task starts, as opposed + * to calling gnunet-arm N times all at once). + */ +static void +schedule_churn_shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerShutdownContext *peer_shutdown_ctx = cls; + struct ShutdownContext *shutdown_ctx; + struct ChurnContext *churn_ctx; + + GNUNET_assert (peer_shutdown_ctx != NULL); + shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; + GNUNET_assert (shutdown_ctx != NULL); + churn_ctx = (struct ChurnContext *) shutdown_ctx->cb_cls; + if (shutdown_ctx->outstanding > churn_ctx->pg->max_concurrent_ssh) + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_churn_shutdown_task, + peer_shutdown_ctx); + else + { + shutdown_ctx->outstanding++; + if (churn_ctx->service != NULL) + GNUNET_TESTING_daemon_stop_service (peer_shutdown_ctx->daemon, + churn_ctx->service, + shutdown_ctx->timeout, + shutdown_ctx->cb, shutdown_ctx); + else + GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, + shutdown_ctx->timeout, shutdown_ctx->cb, + shutdown_ctx, GNUNET_NO, GNUNET_YES); + GNUNET_free (peer_shutdown_ctx); + } +} + + +/** + * Simulate churn by stopping some peers (and possibly + * re-starting others if churn is called multiple times). This + * function can only be used to create leave-join churn (peers "never" + * leave for good). First "voff" random peers that are currently + * online will be taken offline; then "von" random peers that are then + * offline will be put back online. No notifications will be + * generated for any of these operations except for the callback upon + * completion. + * + * @param pg handle for the peer group + * @param service the service to churn off/on, NULL to churn peer + * @param voff number of peers that should go offline + * @param von number of peers that should come back online; + * must be zero on first call (since "testbed_start" + * always starts all of the peers) + * @param timeout how long to wait for operations to finish before + * giving up + * @param cb function to call at the end + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, + char *service, unsigned int voff, + unsigned int von, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) +{ + struct ChurnContext *churn_ctx; + struct ShutdownContext *shutdown_ctx; + struct PeerShutdownContext *peer_shutdown_ctx; + struct PeerRestartContext *peer_restart_ctx; + struct ChurnRestartContext *churn_startup_ctx; + + unsigned int running; + unsigned int stopped; + unsigned int total_running; + unsigned int total_stopped; + unsigned int i; + unsigned int *running_arr; + unsigned int *stopped_arr; + unsigned int *running_permute; + unsigned int *stopped_permute; + char *pos; + + shutdown_ctx = NULL; + peer_shutdown_ctx = NULL; + peer_restart_ctx = NULL; + churn_startup_ctx = NULL; + + running = 0; + stopped = 0; + + if ((von == 0) && (voff == 0)) /* No peers at all? */ + { + cb (cb_cls, NULL); + return; + } + + for (i = 0; i < pg->total; i++) + { + if (service == NULL) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + GNUNET_assert (running != -1); + running++; + } + else + { + GNUNET_assert (stopped != -1); + stopped++; + } + } + else + { + /* FIXME: make churned services a list! */ + pos = pg->peers[i].daemon->churned_services; + /* FIXME: while (pos != NULL) */ + if (pos != NULL) + { +#if FIXME + if (0 == strcasecmp (pos, service)) + { + + break; + } +#endif + GNUNET_assert (stopped != -1); + stopped++; + /* FIXME: pos = pos->next; */ + } + if (pos == NULL) + { + GNUNET_assert (running != -1); + running++; + } + } + } + + if (voff > running) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Trying to stop more peers (%d) than are currently running (%d)!\n", + voff, running); + cb (cb_cls, "Trying to stop more peers than are currently running!"); + return; + } + + if (von > stopped) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Trying to start more peers (%d) than are currently stopped (%d)!\n", + von, stopped); + cb (cb_cls, "Trying to start more peers than are currently stopped!"); + return; + } + + churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); + + if (service != NULL) + churn_ctx->service = GNUNET_strdup (service); + running_arr = NULL; + if (running > 0) + running_arr = GNUNET_malloc (running * sizeof (unsigned int)); + + stopped_arr = NULL; + if (stopped > 0) + stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int)); + + running_permute = NULL; + stopped_permute = NULL; + + if (running > 0) + running_permute = + GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, running); + if (stopped > 0) + stopped_permute = + GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, stopped); + + total_running = running; + total_stopped = stopped; + running = 0; + stopped = 0; + + churn_ctx->num_to_start = von; + churn_ctx->num_to_stop = voff; + churn_ctx->cb = cb; + churn_ctx->cb_cls = cb_cls; + churn_ctx->pg = pg; + + for (i = 0; i < pg->total; i++) + { + if (service == NULL) + { + if (pg->peers[i].daemon->running == GNUNET_YES) + { + GNUNET_assert ((running_arr != NULL) && (total_running > running)); + running_arr[running] = i; + running++; + } + else + { + GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); + stopped_arr[stopped] = i; + stopped++; + } + } + else + { + /* FIXME: make churned services a list! */ + pos = pg->peers[i].daemon->churned_services; + /* FIXME: while (pos != NULL) */ + if (pos != NULL) + { + GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); + stopped_arr[stopped] = i; + stopped++; + /* FIXME: pos = pos->next; */ + } + if (pos == NULL) + { + GNUNET_assert ((running_arr != NULL) && (total_running > running)); + running_arr[running] = i; + running++; + } + } + } + + GNUNET_assert (running >= voff); + if (voff > 0) + { + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + shutdown_ctx->cb = &churn_stop_callback; + shutdown_ctx->cb_cls = churn_ctx; + shutdown_ctx->total_peers = voff; + shutdown_ctx->timeout = timeout; + } + + for (i = 0; i < voff; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer %d!\n", + running_arr[running_permute[i]]); + GNUNET_assert (running_arr != NULL); + peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); + peer_shutdown_ctx->daemon = + pg->peers[running_arr[running_permute[i]]].daemon; + peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; + GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task, peer_shutdown_ctx); + } + + GNUNET_assert (stopped >= von); + if (von > 0) + { + churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); + churn_startup_ctx->churn_ctx = churn_ctx; + churn_startup_ctx->timeout = timeout; + churn_startup_ctx->pg = pg; + } + for (i = 0; i < von; i++) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting up peer %d!\n", + stopped_arr[stopped_permute[i]]); + GNUNET_assert (stopped_arr != NULL); + peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext)); + peer_restart_ctx->churn_restart_ctx = churn_startup_ctx; + peer_restart_ctx->daemon = + pg->peers[stopped_arr[stopped_permute[i]]].daemon; + GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx); + } + + GNUNET_free_non_null (running_arr); + GNUNET_free_non_null (stopped_arr); + GNUNET_free_non_null (running_permute); + GNUNET_free_non_null (stopped_permute); +} + +/* + * Start a given service for each of the peers in the peer group. + * + * @param pg handle for the peer group + * @param service the service to start + * @param timeout how long to wait for operations to finish before + * giving up + * @param cb function to call once finished + * @param cb_cls closure for cb + * + */ +void +GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg, + char *service, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, + void *cb_cls) +{ + struct ServiceStartContext *start_ctx; + struct PeerServiceStartContext *peer_start_ctx; + unsigned int i; + + GNUNET_assert (service != NULL); + + start_ctx = GNUNET_malloc (sizeof (struct ServiceStartContext)); + start_ctx->pg = pg; + start_ctx->remaining = pg->total; + start_ctx->cb = cb; + start_ctx->cb_cls = cb_cls; + start_ctx->service = GNUNET_strdup (service); + start_ctx->timeout = timeout; + + for (i = 0; i < pg->total; i++) + { + peer_start_ctx = GNUNET_malloc (sizeof (struct PeerServiceStartContext)); + peer_start_ctx->start_ctx = start_ctx; + peer_start_ctx->daemon = pg->peers[i].daemon; + GNUNET_SCHEDULER_add_now (&schedule_service_start, peer_start_ctx); + } +} + +/** + * Restart all peers in the given group. + * + * @param pg the handle to the peer group + * @param callback function to call on completion (or failure) + * @param callback_cls closure for the callback function + */ +void +GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, + GNUNET_TESTING_NotifyCompletion callback, + void *callback_cls) +{ + struct RestartContext *restart_context; + unsigned int off; + + if (pg->total > 0) + { + restart_context = GNUNET_malloc (sizeof (struct RestartContext)); + restart_context->peer_group = pg; + restart_context->peers_restarted = 0; + restart_context->callback = callback; + restart_context->callback_cls = callback_cls; + + for (off = 0; off < pg->total; off++) + { + GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, + restart_context); + } + } +} + + +/** + * Start or stop an individual peer from the given group. + * + * @param pg handle to the peer group + * @param offset which peer to start or stop + * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it + * @param timeout how long to wait for shutdown + * @param cb function to call at the end + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, + unsigned int offset, int desired_status, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) +{ + struct ShutdownContext *shutdown_ctx; + struct ChurnRestartContext *startup_ctx; + struct ChurnContext *churn_ctx; + + if (GNUNET_NO == desired_status) + { + if (NULL != pg->peers[offset].daemon) + { + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); + churn_ctx->num_to_start = 0; + churn_ctx->num_to_stop = 1; + churn_ctx->cb = cb; + churn_ctx->cb_cls = cb_cls; + shutdown_ctx->cb_cls = churn_ctx; + GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon, timeout, + &churn_stop_callback, shutdown_ctx, GNUNET_NO, + GNUNET_YES); + } + } + else if (GNUNET_YES == desired_status) + { + if (NULL == pg->peers[offset].daemon) + { + startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); + churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); + churn_ctx->num_to_start = 1; + churn_ctx->num_to_stop = 0; + churn_ctx->cb = cb; + churn_ctx->cb_cls = cb_cls; + startup_ctx->churn_ctx = churn_ctx; + GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon, timeout, + &churn_start_callback, startup_ctx); + } + } + else + GNUNET_break (0); +} + + +/** + * Callback for shutting down peers in a peer group. + * + * @param cls closure (struct ShutdownContext) + * @param emsg NULL on success + */ +static void +internal_shutdown_callback (void *cls, const char *emsg) +{ + struct PeerShutdownContext *peer_shutdown_ctx = cls; + struct ShutdownContext *shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; + unsigned int off; + int i; + struct OutstandingSSH *ssh_pos; + + shutdown_ctx->outstanding--; + if (peer_shutdown_ctx->daemon->hostname != NULL) + decrement_outstanding_at_host (peer_shutdown_ctx->daemon->hostname, + shutdown_ctx->pg); + + if (emsg == NULL) + { + shutdown_ctx->peers_down++; + } + else + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "internal_shutdown_callback", + "Failed to stop a peer: %s\n", emsg); + shutdown_ctx->peers_failed++; + } + + if ((shutdown_ctx->cb != NULL) && + (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == + shutdown_ctx->total_peers)) + { + if (shutdown_ctx->peers_failed > 0) + shutdown_ctx->cb (shutdown_ctx->cb_cls, + "Not all peers successfully shut down!"); + else + shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL); + + for (i = 0; i < shutdown_ctx->pg->total; i++) + { + if (shutdown_ctx->pg->peers[i].startup_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (shutdown_ctx->pg->peers[i].startup_task); + } + GNUNET_free (shutdown_ctx->pg->peers); + GNUNET_free_non_null (shutdown_ctx->pg->hostkey_data); + for (off = 0; off < shutdown_ctx->pg->num_hosts; off++) + { + GNUNET_free (shutdown_ctx->pg->hosts[off].hostname); + GNUNET_free_non_null (shutdown_ctx->pg->hosts[off].username); + } + GNUNET_free_non_null (shutdown_ctx->pg->hosts); + while (NULL != (ssh_pos = shutdown_ctx->pg->ssh_head)) + { + GNUNET_CONTAINER_DLL_remove (shutdown_ctx->pg->ssh_head, + shutdown_ctx->pg->ssh_tail, ssh_pos); + GNUNET_free (ssh_pos); + } + GNUNET_free (shutdown_ctx->pg); + GNUNET_free (shutdown_ctx); + } + GNUNET_free (peer_shutdown_ctx); +} + + +/** + * Task to rate limit the number of outstanding peer shutdown + * requests. This is necessary for making sure we don't do + * too many ssh connections at once, but is generally nicer + * to any system as well (graduated task starts, as opposed + * to calling gnunet-arm N times all at once). + */ +static void +schedule_shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerShutdownContext *peer_shutdown_ctx = cls; + struct ShutdownContext *shutdown_ctx; + struct GNUNET_TESTING_Daemon *d; + + GNUNET_assert (peer_shutdown_ctx != NULL); + d = peer_shutdown_ctx->daemon; + shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; + GNUNET_assert (shutdown_ctx != NULL); + + if ((shutdown_ctx->outstanding < shutdown_ctx->pg->max_concurrent_ssh) || + ((d->hostname != NULL) && + (count_outstanding_at_host + (d->hostname, + shutdown_ctx->pg) < shutdown_ctx->pg->max_concurrent_ssh))) + { + if (d->hostname != NULL) + increment_outstanding_at_host (d->hostname, + shutdown_ctx->pg); + shutdown_ctx->outstanding++; + GNUNET_TESTING_daemon_stop (d, + shutdown_ctx->timeout, + &internal_shutdown_callback, peer_shutdown_ctx, + shutdown_ctx->delete_files, GNUNET_NO); + } + else + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_MILLISECONDS, 100), + &schedule_shutdown_task, peer_shutdown_ctx); + +} + +/** + * Read a testing hosts file based on a configuration. + * Returns a DLL of hosts (caller must free!) on success + * or NULL on failure. + * + * @param cfg a configuration with a testing section + * + * @return DLL of hosts on success, NULL on failure + */ +struct GNUNET_TESTING_Host * +GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_TESTING_Host *hosts; + struct GNUNET_TESTING_Host *temphost; + char *data; + char *buf; + char *hostfile; + struct stat frstat; + int count; + int ret; + + /* Check for a hostfile containing user@host:port triples */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", "hostfile", + &hostfile)) + return NULL; + + hosts = NULL; + temphost = NULL; + data = NULL; + if (hostfile != NULL) + { + if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) + GNUNET_DISK_fn_write (hostfile, NULL, 0, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not open file specified for host list, ending test!"); + GNUNET_free (hostfile); + return NULL; + } + + data = GNUNET_malloc_large (frstat.st_size); + GNUNET_assert (data != NULL); + if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not read file %s specified for host list, ending test!", + hostfile); + GNUNET_free (hostfile); + GNUNET_free (data); + return NULL; + } + + GNUNET_free_non_null (hostfile); + + buf = data; + count = 0; + while (count < frstat.st_size - 1) + { + count++; + if (((data[count] == '\n')) && (buf != &data[count])) + { + data[count] = '\0'; + temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); + ret = + SSCANF (buf, "%a[a-zA-Z0-9_]@%a[a-zA-Z0-9.]:%hd", + &temphost->username, &temphost->hostname, &temphost->port); + if (3 == ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully read host %s, port %d and user %s from file\n", + temphost->hostname, temphost->port, temphost->username); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Error reading line `%s' in hostfile\n", buf); + GNUNET_free (temphost); + buf = &data[count + 1]; + continue; + } + temphost->next = hosts; + hosts = temphost; + buf = &data[count + 1]; + } + else if ((data[count] == '\n') || (data[count] == '\0')) + buf = &data[count + 1]; + } + } + GNUNET_free_non_null (data); + + return hosts; +} + +/** + * Shutdown all peers started in the given group. + * + * @param pg handle to the peer group + * @param timeout how long to wait for shutdown + * @param cb callback to notify upon success or failure + * @param cb_cls closure for cb + */ +void +GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) +{ + unsigned int off; + struct ShutdownContext *shutdown_ctx; + struct PeerShutdownContext *peer_shutdown_ctx; + +#if OLD + struct PeerConnection *conn_iter; + struct PeerConnection *temp_conn; +#endif + struct ConnectContext *cc; + + GNUNET_assert (pg->total > 0); + while (NULL != (cc = pg->cc_head)) + { + GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, cc); + if (GNUNET_SCHEDULER_NO_TASK != cc->task) + GNUNET_SCHEDULER_cancel (cc->task); + if (NULL != cc->cc) + GNUNET_TESTING_daemons_connect_cancel (cc->cc); + GNUNET_free (cc); + } + + shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); + shutdown_ctx->delete_files = + GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING_OLD", "DELETE_FILES"); + shutdown_ctx->cb = cb; + shutdown_ctx->cb_cls = cb_cls; + shutdown_ctx->total_peers = pg->total; + shutdown_ctx->timeout = timeout; + shutdown_ctx->pg = pg; + + for (off = 0; off < pg->total; off++) + { + GNUNET_assert (NULL != pg->peers[off].daemon); + peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); + peer_shutdown_ctx->daemon = pg->peers[off].daemon; + peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; + GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx); + + if (NULL != pg->peers[off].cfg) + { + GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg); + pg->peers[off].cfg = NULL; + } +#if OLD +// FIXME Do DLL remove for all pg->peers[off].LIST + conn_iter = pg->peers[off].allowed_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].allowed_peers_head = NULL; + + conn_iter = pg->peers[off].connect_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].connect_peers_head = NULL; + + conn_iter = pg->peers[off].blacklisted_peers_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].blacklisted_peers_head = NULL; + + conn_iter = pg->peers[off].connect_peers_working_set_head; + while (conn_iter != NULL) + { + temp_conn = conn_iter->next; + GNUNET_free (conn_iter); + conn_iter = temp_conn; + } + pg->peers[off].connect_peers_working_set_head = NULL; +#else + if (pg->peers[off].allowed_peers != NULL) + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers); + if (pg->peers[off].connect_peers != NULL) + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers); + if (pg->peers[off].blacklisted_peers != NULL) + GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].blacklisted_peers); +#endif + } +} + +/* end of testing_group.c */ diff --git a/src/testing_old/testing_peergroup.c b/src/testing_old/testing_peergroup.c new file mode 100644 index 000000000..d4451ccdf --- /dev/null +++ b/src/testing_old/testing_peergroup.c @@ -0,0 +1,1017 @@ +/* + This file is part of GNUnet + (C) 2008-2011 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 testing/testing_peergroup.c + * @brief API implementation for easy peer group creation + * @author Nathan Evans + * @author Christian Grothoff + * + */ +#include "platform.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_testing_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_disk_lib.h" + +/** Globals **/ +#define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) + +#define DEFAULT_CONNECT_ATTEMPTS 2 + +/** Struct definitions **/ + +struct PeerGroupStartupContext +{ + struct GNUNET_TESTING_PeerGroup *pg; + const struct GNUNET_CONFIGURATION_Handle *cfg; + unsigned int total; + unsigned int peers_left; + unsigned long long max_concurrent_connections; + + /** + * Maximum attemps to connect two daemons. + */ + unsigned long long connect_attempts; + + /** + * How long to spend trying to establish all the connections? + */ + struct GNUNET_TIME_Relative connect_timeout; + + unsigned long long max_concurrent_ssh; + struct GNUNET_TIME_Absolute timeout; + GNUNET_TESTING_NotifyConnection connect_cb; + GNUNET_TESTING_NotifyCompletion peergroup_cb; + + /** + * Closure for all peergroup callbacks. + */ + void *cls; + + const struct GNUNET_TESTING_Host *hostnames; + + /** + * FIXME document + */ + enum GNUNET_TESTING_Topology topology; + + float topology_percentage; + + float topology_probability; + + /** + * FIXME document + */ + enum GNUNET_TESTING_Topology restrict_topology; + + /** + * FIXME document + */ + char *restrict_transports; + + /** + * Initial connections + */ + enum GNUNET_TESTING_Topology connect_topology; + enum GNUNET_TESTING_TopologyOption connect_topology_option; + double connect_topology_option_modifier; + int verbose; + + struct ProgressMeter *hostkey_meter; + struct ProgressMeter *peer_start_meter; + struct ProgressMeter *connect_meter; + + /** + * Task used to kill the peergroup. + */ + GNUNET_SCHEDULER_TaskIdentifier die_task; + + char *fail_reason; + + /** + * Variable used to store the number of connections we should wait for. + */ + unsigned int expected_connections; + + /** + * Time when the connecting peers was started. + */ + struct GNUNET_TIME_Absolute connect_start_time; + + /** + * The total number of connections that have been created so far. + */ + unsigned int total_connections; + + /** + * The total number of connections that have failed so far. + */ + unsigned int failed_connections; + + /** + * File handle to write out topology in dot format. + */ + struct GNUNET_DISK_FileHandle *topology_output_file; +}; + +struct TopologyOutputContext +{ + struct GNUNET_DISK_FileHandle *file; + GNUNET_TESTING_NotifyCompletion notify_cb; + void *notify_cb_cls; +}; + +/** + * Simple struct to keep track of progress, and print a + * percentage meter for long running tasks. + */ +struct ProgressMeter +{ + /** + * Total number of tasks to complete. + */ + unsigned int total; + + /** + * Print percentage done after modnum tasks. + */ + unsigned int modnum; + + /** + * Print a . each dotnum tasks. + */ + unsigned int dotnum; + + /** + * Total number completed thus far. + */ + unsigned int completed; + + /** + * Whether or not to print. + */ + int print; + + /** + * Startup string for progress meter. + */ + char *startup_string; +}; + + +/** Utility functions **/ + +/** + * Create a meter to keep track of the progress of some task. + * + * @param total the total number of items to complete + * @param start_string a string to prefix the meter with (if printing) + * @param print GNUNET_YES to print the meter, GNUNET_NO to count + * internally only + * + * @return the progress meter + */ +static struct ProgressMeter * +create_meter (unsigned int total, char *start_string, int print) +{ + struct ProgressMeter *ret; + + ret = GNUNET_malloc (sizeof (struct ProgressMeter)); + ret->print = print; + ret->total = total; + ret->modnum = (total / 4 == 0) ? 1 : (total / 4); + ret->dotnum = (total / 50) + 1; + if (start_string != NULL) + ret->startup_string = GNUNET_strdup (start_string); + else + ret->startup_string = GNUNET_strdup (""); + + return ret; +} + +/** + * Update progress meter (increment by one). + * + * @param meter the meter to update and print info for + * + * @return GNUNET_YES if called the total requested, + * GNUNET_NO if more items expected + */ +static int +update_meter (struct ProgressMeter *meter) +{ + if (meter->print == GNUNET_YES) + { + if (meter->completed % meter->modnum == 0) + { + if (meter->completed == 0) + { + FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); + } + else + FPRINTF (stdout, "%d%%", + (int) (((float) meter->completed / meter->total) * 100)); + } + else if (meter->completed % meter->dotnum == 0) + FPRINTF (stdout, "%s", "."); + + if (meter->completed + 1 == meter->total) + FPRINTF (stdout, "%d%%]\n", 100); + fflush (stdout); + } + meter->completed++; + + if (meter->completed == meter->total) + return GNUNET_YES; + return GNUNET_NO; +} + +/** + * Reset progress meter. + * + * @param meter the meter to reset + * + * @return GNUNET_YES if meter reset, + * GNUNET_SYSERR on error + */ +static int +reset_meter (struct ProgressMeter *meter) +{ + if (meter == NULL) + return GNUNET_SYSERR; + + meter->completed = 0; + return GNUNET_YES; +} + +/** + * Release resources for meter + * + * @param meter the meter to free + */ +static void +free_meter (struct ProgressMeter *meter) +{ + GNUNET_free_non_null (meter->startup_string); + GNUNET_free (meter); +} + + +/** Functions for creating, starting and connecting the peergroup **/ + +/** + * Check whether peers successfully shut down. + */ +static void +internal_shutdown_callback (void *cls, const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + + if (emsg != NULL) + pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg); + else + pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason); +} + +/** + * Check if the get_handle is being used, if so stop the request. Either + * way, schedule the end_badly_cont function which actually shuts down the + * test. + */ +static void +end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failing peer group startup with error: `%s'!\n", + pg_start_ctx->fail_reason); + + GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, + GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), + &internal_shutdown_callback, pg_start_ctx); + + if (pg_start_ctx->hostkey_meter != NULL) + { + free_meter (pg_start_ctx->hostkey_meter); + pg_start_ctx->hostkey_meter = NULL; + } + if (pg_start_ctx->peer_start_meter != NULL) + { + free_meter (pg_start_ctx->peer_start_meter); + pg_start_ctx->peer_start_meter = NULL; + } + if (pg_start_ctx->connect_meter != NULL) + { + free_meter (pg_start_ctx->connect_meter); + pg_start_ctx->connect_meter = NULL; + } +} + +/** + * This function is called whenever a connection attempt is finished between two of + * the started peers (started with GNUNET_TESTING_daemons_start). The total + * number of times this function is called should equal the number returned + * from the GNUNET_TESTING_connect_topology call. + * + * The emsg variable is NULL on success (peers connected), and non-NULL on + * failure (peers failed to connect). + */ +static void +internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, + uint32_t distance, + const struct GNUNET_CONFIGURATION_Handle *first_cfg, + const struct GNUNET_CONFIGURATION_Handle + *second_cfg, + struct GNUNET_TESTING_Daemon *first_daemon, + struct GNUNET_TESTING_Daemon *second_daemon, + const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + char *temp_str; + char *second_str; + int temp; + +#if TIMING + unsigned long long duration; + unsigned long long total_duration; + unsigned int new_connections; + unsigned int new_failed_connections; + double conns_per_sec_recent; + double conns_per_sec_total; + double failed_conns_per_sec_recent; + double failed_conns_per_sec_total; +#endif + +#if TIMING + if (GNUNET_TIME_absolute_get_difference + (connect_last_time, + GNUNET_TIME_absolute_get ()).rel_value > + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + CONN_UPDATE_DURATION).rel_value) + { + /* Get number of new connections */ + new_connections = total_connections - previous_connections; + + /* Get number of new FAILED connections */ + new_failed_connections = failed_connections - previous_failed_connections; + + /* Get duration in seconds */ + duration = + GNUNET_TIME_absolute_get_difference (connect_last_time, + GNUNET_TIME_absolute_get + ()).rel_value / 1000; + total_duration = + GNUNET_TIME_absolute_get_difference (connect_start_time, + GNUNET_TIME_absolute_get + ()).rel_value / 1000; + + failed_conns_per_sec_recent = (double) new_failed_connections / duration; + failed_conns_per_sec_total = (double) failed_connections / total_duration; + conns_per_sec_recent = (double) new_connections / duration; + conns_per_sec_total = (double) total_connections / total_duration; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n", + conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total, + failed_conns_per_sec_recent, failed_conns_per_sec_total); + connect_last_time = GNUNET_TIME_absolute_get (); + previous_connections = total_connections; + previous_failed_connections = failed_connections; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "have %u total_connections, %u failed\n", total_connections, + failed_connections); + } +#endif + + + if (emsg == NULL) + { + pg_start_ctx->total_connections++; +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "connected peer %s to peer %s, distance %u\n", + first_daemon->shortname, second_daemon->shortname, distance); +#endif + if (pg_start_ctx->topology_output_file != NULL) + { + second_str = GNUNET_strdup (GNUNET_i2s (second)); + temp = + GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", + GNUNET_i2s (first), second_str); + GNUNET_free (second_str); + if (temp > 0) + GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, + temp); + GNUNET_free (temp_str); + } + } + else + { + pg_start_ctx->failed_connections++; +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to connect peer %s to peer %s with error :\n%s\n", + first_daemon->shortname, second_daemon->shortname, emsg); +#endif + } + + GNUNET_assert (pg_start_ctx->connect_meter != NULL); + if (pg_start_ctx->connect_cb != NULL) + pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance, + first_cfg, second_cfg, first_daemon, + second_daemon, emsg); + if (GNUNET_YES != update_meter (pg_start_ctx->connect_meter)) + { + /* No finished yet */ + return; + } +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Created %d total connections, which is our target number! Starting next phase of testing.\n", + pg_start_ctx->total_connections); +#endif + +#if TIMING + total_duration = + GNUNET_TIME_absolute_get_difference (connect_start_time, + GNUNET_TIME_absolute_get + ()).rel_value / 1000; + failed_conns_per_sec_total = (double) failed_connections / total_duration; + conns_per_sec_total = (double) total_connections / total_duration; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Overall connection info --- Total: %u, Total Failed %u/s\n", + total_connections, failed_connections); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n", + conns_per_sec_total, failed_conns_per_sec_total); +#endif + + GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + + /* Call final callback, signifying that the peer group has been started and connected */ + if (pg_start_ctx->peergroup_cb != NULL) + pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL); + + if (pg_start_ctx->topology_output_file != NULL) + { + temp = GNUNET_asprintf (&temp_str, "}\n"); + if (temp > 0) + GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, + temp); + GNUNET_free (temp_str); + GNUNET_DISK_file_close (pg_start_ctx->topology_output_file); + } + GNUNET_free_non_null (pg_start_ctx->fail_reason); + if (NULL != pg_start_ctx->hostkey_meter) + free_meter(pg_start_ctx->hostkey_meter); + if (NULL != pg_start_ctx->peer_start_meter) + free_meter(pg_start_ctx->peer_start_meter); + if (NULL != pg_start_ctx->connect_meter) + free_meter(pg_start_ctx->connect_meter); + GNUNET_free (pg_start_ctx); +} + + +/** + * Callback called for each started daemon. + * + * @param cls Clause (PG Context). + * @param id PeerIdentidy of started daemon. + * @param cfg Configuration used by the daemon. + * @param d Handle for the daemon. + * @param emsg Error message, NULL on success. + */ +static void +internal_peers_started_callback (void *cls, + const struct GNUNET_PeerIdentity *id, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Daemon *d, + const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to start daemon with error: `%s'\n", emsg); + return; + } + GNUNET_assert (id != NULL); + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", + (pg_start_ctx->total - pg_start_ctx->peers_left) + 1, + pg_start_ctx->total); +#endif + + pg_start_ctx->peers_left--; + + if (NULL == pg_start_ctx->peer_start_meter) + { + /* Cancelled Ctrl-C or error */ + return; + } + if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter)) + { +#if VERBOSE + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All %d daemons started, now connecting peers!\n", + pg_start_ctx->total); +#endif + GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + + pg_start_ctx->expected_connections = UINT_MAX; + // FIXME: why whould peers_left be != 0?? Or pg NULL? + if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0)) + { + pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get (); + pg_start_ctx->expected_connections = + GNUNET_TESTING_connect_topology (pg_start_ctx->pg, + pg_start_ctx->connect_topology, + pg_start_ctx->connect_topology_option, + pg_start_ctx->connect_topology_option_modifier, + pg_start_ctx->connect_timeout, + pg_start_ctx->connect_attempts, NULL, + NULL); + + pg_start_ctx->connect_meter = + create_meter (pg_start_ctx->expected_connections, "Peer connection ", + pg_start_ctx->verbose); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", + pg_start_ctx->expected_connections); + } + + if (pg_start_ctx->expected_connections == 0) + { + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from connect topology (bad return)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); + return; + } + + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from connect topology (timeout)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + } +} + +/** + * Callback indicating that the hostkey was created for a peer. + * + * @param cls NULL + * @param id the peer identity + * @param d the daemon handle (pretty useless at this point, remove?) + * @param emsg non-null on failure + */ +static void +internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, + struct GNUNET_TESTING_Daemon *d, const char *emsg) +{ + struct PeerGroupStartupContext *pg_start_ctx = cls; + unsigned int create_expected_connections; + + if (emsg != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Hostkey callback received error: %s\n", emsg); + } + +#if VERBOSE > 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Hostkey (%d/%d) created for peer `%s'\n", + pg_start_ctx->total - pg_start_ctx->peers_left + 1, + pg_start_ctx->total, GNUNET_i2s (id)); +#endif + + pg_start_ctx->peers_left--; + if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter)) + { + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + GNUNET_free_non_null (pg_start_ctx->fail_reason); + /* Set up task in case topology creation doesn't finish + * within a reasonable amount of time */ + pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */ + create_expected_connections = + GNUNET_TESTING_create_topology (pg_start_ctx->pg, + pg_start_ctx->topology, + pg_start_ctx->restrict_topology, + pg_start_ctx->restrict_transports); + if (create_expected_connections > 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Topology set up, have %u expected connections, now starting peers!\n", + create_expected_connections); + GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg); + } + else + { + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from create topology (bad return)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); + return; + } + + GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); + GNUNET_free_non_null (pg_start_ctx->fail_reason); + pg_start_ctx->fail_reason = + GNUNET_strdup ("from continue startup (timeout)"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + } +} + + +/** + * Prototype of a callback function indicating that two peers + * are currently connected. + * + * @param cls closure + * @param first peer id for first daemon + * @param second peer id for the second daemon + * @param emsg error message (NULL on success) + */ +void +write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, + const struct GNUNET_PeerIdentity *second, const char *emsg) +{ + struct TopologyOutputContext *topo_ctx; + int temp; + char *temp_str; + char *temp_pid2; + + topo_ctx = (struct TopologyOutputContext *) cls; + GNUNET_assert (topo_ctx->file != NULL); + if ((emsg == NULL) && (first != NULL) && (second != NULL)) + { + GNUNET_assert (first != NULL); + GNUNET_assert (second != NULL); + temp_pid2 = GNUNET_strdup (GNUNET_i2s (second)); + temp = + GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first), + temp_pid2); + GNUNET_free (temp_pid2); + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + } + else if ((emsg == NULL) && (first == NULL) && (second == NULL)) + { + temp = GNUNET_asprintf (&temp_str, "}\n"); + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + GNUNET_DISK_file_close (topo_ctx->file); + topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL); + GNUNET_free (topo_ctx); + } + else + { + temp = GNUNET_asprintf (&temp_str, "}\n"); + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + GNUNET_DISK_file_close (topo_ctx->file); + topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg); + GNUNET_free (topo_ctx); + } +} + +/** + * Print current topology to a graphviz readable file. + * + * @param pg a currently running peergroup to print to file + * @param output_filename the file to write the topology to + * @param notify_cb callback to call upon completion or failure + * @param notify_cb_cls closure for notify_cb + * + */ +void +GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg, + const char *output_filename, + GNUNET_TESTING_NotifyCompletion + notify_cb, void *notify_cb_cls) +{ + struct TopologyOutputContext *topo_ctx; + int temp; + char *temp_str; + + topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext)); + + topo_ctx->notify_cb = notify_cb; + topo_ctx->notify_cb_cls = notify_cb_cls; + topo_ctx->file = + GNUNET_DISK_file_open (output_filename, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (topo_ctx->file == NULL) + { + notify_cb (notify_cb_cls, "Failed to open output file!"); + GNUNET_free (topo_ctx); + return; + } + + temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); + if (temp > 0) + GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); + GNUNET_free_non_null (temp_str); + GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx); +} + +/** + * Start a peer group with a given number of peers. Notify + * on completion of peer startup and connection based on given + * topological constraints. Optionally notify on each + * established connection. + * + * @param cfg configuration template to use + * @param total number of daemons to start + * @param timeout total time allowed for peers to start + * @param connect_cb function to call each time two daemons are connected + * @param peergroup_cb function to call once all peers are up and connected + * @param peergroup_cls closure for peergroup callbacks + * @param hostnames linked list of host structs to use to start peers on + * (NULL to run on localhost only) + * + * @return NULL on error, otherwise handle to control peer group + */ +struct GNUNET_TESTING_PeerGroup * +GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int total, + struct GNUNET_TIME_Relative timeout, + GNUNET_TESTING_NotifyConnection connect_cb, + GNUNET_TESTING_NotifyCompletion peergroup_cb, + void *peergroup_cls, + const struct GNUNET_TESTING_Host *hostnames) +{ + struct PeerGroupStartupContext *pg_start_ctx; + char *temp_str; + int temp; + struct GNUNET_TIME_Relative rtimeout; + + GNUNET_assert (total > 0); + GNUNET_assert (cfg != NULL); + + pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext)); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing_old", "connect_attempts", + &pg_start_ctx->connect_attempts)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing_old", "connect_attempts"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing_old", "CONNECT_TIMEOUT", + &pg_start_ctx->connect_timeout)) + { + pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing_old", + "max_outstanding_connections", + &pg_start_ctx->max_concurrent_connections)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing_old", "max_outstanding_connections"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "testing_old", + "max_concurrent_ssh", + &pg_start_ctx->max_concurrent_ssh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing_old", "max_concurrent_ssh"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_SYSERR == + (pg_start_ctx->verbose = + GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing_old", + "use_progressbars"))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing_old", "use_progressbars"); + GNUNET_free (pg_start_ctx); + return NULL; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, "testing_old", "PEERGROUP_TIMEOUT", + &rtimeout)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", + "testing_old", "PEERGROUP_TIMEOUT"); + GNUNET_free (pg_start_ctx); + return NULL; + } + pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout); + + + /* Read topology related options from the configuration file */ + temp_str = NULL; + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", "topology", + &temp_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + temp_str, "TESTING_old", "TOPOLOGY"); + pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ + } + GNUNET_free_non_null (temp_str); + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", + "topology_output_file", &temp_str)) + { + pg_start_ctx->topology_output_file = + GNUNET_DISK_file_open (temp_str, + GNUNET_DISK_OPEN_READWRITE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (pg_start_ctx->topology_output_file != NULL) + { + GNUNET_free (temp_str); + temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); + if (temp > 0) + GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, + temp); + } + GNUNET_free (temp_str); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", "percentage", + &temp_str)) + pg_start_ctx->topology_percentage = 0.5; + else + { + pg_start_ctx->topology_percentage = atof (temp_str); + GNUNET_free (temp_str); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", "probability", + &temp_str)) + pg_start_ctx->topology_probability = 0.5; + else + { + pg_start_ctx->topology_probability = atof (temp_str); + GNUNET_free (temp_str); + } + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", + "connect_topology", &temp_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology `%s' given for section %s option %s\n", + temp_str, "TESTING_old", "CONNECT_TOPOLOGY"); + } + GNUNET_free_non_null (temp_str); + + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", + "connect_topology_option", + &temp_str)) && + (GNUNET_NO == + GNUNET_TESTING_topology_option_get + (&pg_start_ctx->connect_topology_option, temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid connect topology option `%s' given for section %s option %s\n", + temp_str, "TESTING_old", "CONNECT_TOPOLOGY_OPTION"); + pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ + } + GNUNET_free_non_null (temp_str); + + if (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", + "connect_topology_option_modifier", + &temp_str)) + { + if (SSCANF + (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _ + ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), + temp_str, "connect_topology_option_modifier", "TESTING_old"); + GNUNET_free (temp_str); + GNUNET_free (pg_start_ctx); + return NULL; + } + GNUNET_free (temp_str); + } + + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", + "blacklist_transports", + &pg_start_ctx->restrict_transports)) + pg_start_ctx->restrict_transports = NULL; + + pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE; + if ((GNUNET_YES == + GNUNET_CONFIGURATION_get_value_string (cfg, "testing_old", + "blacklist_topology", &temp_str)) + && (GNUNET_NO == + GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology, + temp_str))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid topology `%s' given for section %s option %s\n", + temp_str, "TESTING_OLD", "BLACKLIST_TOPOLOGY"); + } + + GNUNET_free_non_null (temp_str); + + pg_start_ctx->cfg = cfg; + pg_start_ctx->total = total; + pg_start_ctx->peers_left = total; + pg_start_ctx->connect_cb = connect_cb; + pg_start_ctx->peergroup_cb = peergroup_cb; + pg_start_ctx->cls = peergroup_cls; + pg_start_ctx->hostnames = hostnames; + pg_start_ctx->hostkey_meter = + create_meter (pg_start_ctx->peers_left, "Hostkeys created ", + pg_start_ctx->verbose); + pg_start_ctx->peer_start_meter = + create_meter (pg_start_ctx->peers_left, "Peers started ", + pg_start_ctx->verbose); + /* Make compilers happy */ + reset_meter (pg_start_ctx->peer_start_meter); + pg_start_ctx->fail_reason = + GNUNET_strdup + ("didn't generate all hostkeys within allowed startup time!"); + pg_start_ctx->die_task = + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), &end_badly, + pg_start_ctx); + + pg_start_ctx->pg = + GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left, + pg_start_ctx->max_concurrent_connections, + pg_start_ctx->max_concurrent_ssh, + GNUNET_TIME_absolute_get_remaining + (pg_start_ctx->timeout), + &internal_hostkey_callback, pg_start_ctx, + &internal_peers_started_callback, + pg_start_ctx, &internal_topology_callback, + pg_start_ctx, pg_start_ctx->hostnames); + + return pg_start_ctx->pg; +} + +/* end of testing_peergroup.c */ diff --git a/src/topology/Makefile.am b/src/topology/Makefile.am index 261be8619..4234625d6 100644 --- a/src/topology/Makefile.am +++ b/src/topology/Makefile.am @@ -36,7 +36,7 @@ endif test_gnunet_daemon_topology_SOURCES = \ test_gnunet_daemon_topology.c test_gnunet_daemon_topology_LDADD = \ - $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/testing_old/libgnunettesting_old.la \ $(top_builddir)/src/util/libgnunetutil.la EXTRA_DIST = \ -- cgit v1.2.3