aboutsummaryrefslogtreecommitdiff
path: root/src/testbed
diff options
context:
space:
mode:
Diffstat (limited to 'src/testbed')
-rw-r--r--src/testbed/.gitignore37
-rw-r--r--src/testbed/Makefile.am401
-rw-r--r--src/testbed/barriers.README.org95
-rw-r--r--src/testbed/buildvars.py.in34
-rw-r--r--src/testbed/generate-underlay-topology.c407
-rw-r--r--src/testbed/gnunet-daemon-latency-logger.c322
-rw-r--r--src/testbed/gnunet-daemon-testbed-blacklist.c254
-rw-r--r--src/testbed/gnunet-daemon-testbed-underlay.c481
-rw-r--r--src/testbed/gnunet-helper-testbed-valgrind.patch21
-rw-r--r--src/testbed/gnunet-helper-testbed.c613
-rw-r--r--src/testbed/gnunet-service-test-barriers.c152
-rw-r--r--src/testbed/gnunet-service-testbed.c981
-rw-r--r--src/testbed/gnunet-service-testbed.h899
-rw-r--r--src/testbed/gnunet-service-testbed_barriers.c929
-rw-r--r--src/testbed/gnunet-service-testbed_barriers.h128
-rw-r--r--src/testbed/gnunet-service-testbed_cache.c270
-rw-r--r--src/testbed/gnunet-service-testbed_connectionpool.c1045
-rw-r--r--src/testbed/gnunet-service-testbed_connectionpool.h172
-rw-r--r--src/testbed/gnunet-service-testbed_cpustatus.c664
-rw-r--r--src/testbed/gnunet-service-testbed_links.c1468
-rw-r--r--src/testbed/gnunet-service-testbed_links.h209
-rw-r--r--src/testbed/gnunet-service-testbed_meminfo.c279
-rw-r--r--src/testbed/gnunet-service-testbed_meminfo.h55
-rw-r--r--src/testbed/gnunet-service-testbed_oc.c1997
-rw-r--r--src/testbed/gnunet-service-testbed_peers.c1552
-rw-r--r--src/testbed/gnunet-testbed-profiler.c323
-rw-r--r--src/testbed/gnunet_mpi_test.c108
-rw-r--r--src/testbed/misc.supp49
-rw-r--r--src/testbed/overlay_topology.txt5
-rw-r--r--src/testbed/profile-testbed.patch43
-rwxr-xr-xsrc/testbed/sample.job16
-rw-r--r--src/testbed/sample_hosts.txt7
-rw-r--r--src/testbed/test-underlay.sqlitebin3072 -> 0 bytes
-rw-r--r--src/testbed/test_gnunet_helper_testbed.c255
-rw-r--r--src/testbed/test_testbed_api.c515
-rw-r--r--src/testbed/test_testbed_api.conf1
-rw-r--r--src/testbed/test_testbed_api_2peers_1controller.c540
-rw-r--r--src/testbed/test_testbed_api_3peers_3controllers.c964
-rw-r--r--src/testbed/test_testbed_api_barriers.c234
-rw-r--r--src/testbed/test_testbed_api_barriers.conf.in103
-rw-r--r--src/testbed/test_testbed_api_barriers.h4
-rw-r--r--src/testbed/test_testbed_api_controllerlink.c881
-rw-r--r--src/testbed/test_testbed_api_hosts.c183
-rw-r--r--src/testbed/test_testbed_api_operations.c568
-rw-r--r--src/testbed/test_testbed_api_peer_reconfiguration.c194
-rw-r--r--src/testbed/test_testbed_api_peers_manage_services.c216
-rw-r--r--src/testbed/test_testbed_api_sd.c111
-rw-r--r--src/testbed/test_testbed_api_statistics.c205
-rw-r--r--src/testbed/test_testbed_api_statistics.conf9
-rw-r--r--src/testbed/test_testbed_api_template.conf49
-rw-r--r--src/testbed/test_testbed_api_test.c251
-rw-r--r--src/testbed/test_testbed_api_test_timeout.c126
-rw-r--r--src/testbed/test_testbed_api_test_timeout.conf5
-rw-r--r--src/testbed/test_testbed_api_testbed_run.c242
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf5
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyclique.conf4
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf5
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyline.conf4
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyrandom.conf5
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyring.conf4
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf6
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf5
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf5
-rw-r--r--src/testbed/test_testbed_api_testbed_run_topologystar.conf4
-rw-r--r--src/testbed/test_testbed_api_topology.c189
-rw-r--r--src/testbed/test_testbed_api_topology_clique.c185
-rw-r--r--src/testbed/test_testbed_underlay.c174
-rw-r--r--src/testbed/test_testbed_underlay.conf.in13
-rw-r--r--src/testbed/testbed.conf.in116
-rw-r--r--src/testbed/testbed.h866
-rw-r--r--src/testbed/testbed_api.c2427
-rw-r--r--src/testbed/testbed_api.h521
-rw-r--r--src/testbed/testbed_api_barriers.c253
-rw-r--r--src/testbed/testbed_api_hosts.c1520
-rw-r--r--src/testbed/testbed_api_hosts.h227
-rw-r--r--src/testbed/testbed_api_operations.c1379
-rw-r--r--src/testbed/testbed_api_operations.h233
-rw-r--r--src/testbed/testbed_api_peers.c961
-rw-r--r--src/testbed/testbed_api_peers.h311
-rw-r--r--src/testbed/testbed_api_sd.c213
-rw-r--r--src/testbed/testbed_api_sd.h81
-rw-r--r--src/testbed/testbed_api_services.c291
-rw-r--r--src/testbed/testbed_api_statistics.c435
-rw-r--r--src/testbed/testbed_api_test.c175
-rw-r--r--src/testbed/testbed_api_testbed.c1467
-rw-r--r--src/testbed/testbed_api_topology.c1598
-rw-r--r--src/testbed/testbed_api_topology.h115
-rw-r--r--src/testbed/testbed_api_underlay.c260
-rw-r--r--src/testbed/testbed_helper.h89
-rw-r--r--src/testbed/valgrind-zlib.supp6
-rw-r--r--src/testbed/x64_misc.supp34
91 files changed, 0 insertions, 33858 deletions
diff --git a/src/testbed/.gitignore b/src/testbed/.gitignore
deleted file mode 100644
index f7cfb1e23..000000000
--- a/src/testbed/.gitignore
+++ /dev/null
@@ -1,37 +0,0 @@
1gnunet-testbed-profiler
2generate-underlay-topology
3gnunet-daemon-latency-logger
4gnunet-daemon-testbed-blacklist
5gnunet-daemon-testbed-underlay
6gnunet-helper-testbed
7gnunet-service-testbed
8gnunet-service-test-barriers
9test_gnunet_helper_testbed
10test_testbed_api
11test_testbed_api_2peers_1controller
12test_testbed_api_3peers_3controllers
13test_testbed_api_barriers
14test_testbed_api_controllerlink
15test_testbed_api_hosts
16test_testbed_api_operations
17test_testbed_api_peer_reconfiguration
18test_testbed_api_peers_manage_services
19test_testbed_api_sd
20test_testbed_api_statistics
21test_testbed_api_test
22test_testbed_api_test_timeout
23test_testbed_api_testbed_run
24test_testbed_api_testbed_run_topology2dtorus
25test_testbed_api_testbed_run_topologyclique
26test_testbed_api_testbed_run_topologyfromfile
27test_testbed_api_testbed_run_topologyline
28test_testbed_api_testbed_run_topologyrandom
29test_testbed_api_testbed_run_topologyring
30test_testbed_api_testbed_run_topologyscalefree
31test_testbed_api_testbed_run_topologysmallworld
32test_testbed_api_testbed_run_topologysmallworldring
33test_testbed_api_testbed_run_topologystar
34test_testbed_api_testbed_run_waitforever
35test_testbed_api_topology
36test_testbed_api_topology_clique
37test_testbed_underlay
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am
deleted file mode 100644
index 11399e77c..000000000
--- a/src/testbed/Makefile.am
+++ /dev/null
@@ -1,401 +0,0 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6 XLIB = -lgcov
7endif
8
9plugindir = $(libdir)/gnunet
10
11libexecdir= $(pkglibdir)/libexec/
12
13pkgcfgdir= $(pkgdatadir)/config.d/
14
15pkgcfg_DATA = \
16 testbed.conf
17
18if HAVE_SQLITE
19 underlay_daemon = gnunet-daemon-testbed-underlay
20 latency_logger = gnunet-daemon-latency-logger
21 generate_underlay = generate-underlay-topology
22 underlay_testcases = test_testbed_underlay
23endif
24
25libexec_PROGRAMS = \
26 gnunet-service-testbed \
27 gnunet-helper-testbed \
28 gnunet-daemon-testbed-blacklist \
29 $(underlay_daemon) \
30 $(latency_logger)
31
32bin_PROGRAMS = \
33 gnunet-testbed-profiler
34
35noinst_PROGRAMS = \
36 $(generate_underlay)
37
38gnunet_service_testbed_SOURCES = \
39 gnunet-service-testbed.c gnunet-service-testbed.h \
40 gnunet-service-testbed_links.c gnunet-service-testbed_links.h \
41 gnunet-service-testbed_peers.c \
42 gnunet-service-testbed_cache.c \
43 gnunet-service-testbed_oc.c \
44 gnunet-service-testbed_cpustatus.c \
45 gnunet-service-testbed_meminfo.c gnunet-service-testbed_meminfo.h \
46 gnunet-service-testbed_barriers.c gnunet-service-testbed_barriers.h \
47 gnunet-service-testbed_connectionpool.c gnunet-service-testbed_connectionpool.h
48gnunet_service_testbed_LDADD = $(XLIB) \
49 $(top_builddir)/src/util/libgnunetutil.la \
50 $(top_builddir)/src/core/libgnunetcore.la \
51 $(top_builddir)/src/hello/libgnunethello.la \
52 $(top_builddir)/src/transport/libgnunettransport.la \
53 $(top_builddir)/src/ats/libgnunetats.la \
54 $(top_builddir)/src/testing/libgnunettesting.la \
55 libgnunettestbed.la \
56 $(top_builddir)/src/arm/libgnunetarm.la \
57 $(LTLIBINTL) $(Z_LIBS)
58
59gnunet_testbed_profiler_SOURCES = \
60 gnunet-testbed-profiler.c
61gnunet_testbed_profiler_LDADD = $(XLIB) \
62 $(top_builddir)/src/testing/libgnunettesting.la \
63 $(top_builddir)/src/util/libgnunetutil.la \
64 libgnunettestbed.la
65gnunet_testbed_profiler_LDFLAGS = \
66 $(GN_LIBINTL)
67
68gnunet_helper_testbed_SOURCES = \
69 gnunet-helper-testbed.c
70gnunet_helper_testbed_LDADD = $(XLIB) \
71 $(top_builddir)/src/util/libgnunetutil.la \
72 $(top_builddir)/src/testing/libgnunettesting.la \
73 libgnunettestbed.la \
74 $(LTLIBINTL) $(Z_LIBS)
75
76gnunet_daemon_testbed_blacklist_SOURCES = gnunet-daemon-testbed-blacklist.c
77gnunet_daemon_testbed_blacklist_LDADD = $(XLIB) \
78 $(top_builddir)/src/transport/libgnunettransport.la \
79 $(top_builddir)/src/util/libgnunetutil.la \
80 $(LTLIBINTL)
81
82gnunet_daemon_testbed_underlay_SOURCES = gnunet-daemon-testbed-underlay.c
83gnunet_daemon_testbed_underlay_LDADD = $(XLIB) \
84 $(top_builddir)/src/transport/libgnunettransport.la \
85 $(top_builddir)/src/util/libgnunetutil.la \
86 $(LTLIBINTL) -lsqlite3
87
88gnunet_daemon_latency_logger_SOURCES = gnunet-daemon-latency-logger.c
89gnunet_daemon_latency_logger_LDADD = $(XLIB) \
90 $(top_builddir)/src/ats/libgnunetats.la \
91 $(top_builddir)/src/util/libgnunetutil.la \
92 $(LTLIBINTL) -lsqlite3
93
94lib_LTLIBRARIES = \
95 libgnunettestbed.la
96
97libgnunettestbed_la_SOURCES = \
98 testbed_api.c testbed_api.h testbed.h \
99 testbed_api_hosts.c testbed_api_hosts.h testbed_helper.h \
100 testbed_api_operations.c testbed_api_operations.h \
101 testbed_api_peers.c testbed_api_peers.h \
102 testbed_api_services.c \
103 testbed_api_statistics.c \
104 testbed_api_testbed.c \
105 testbed_api_test.c \
106 testbed_api_topology.c testbed_api_topology.h \
107 testbed_api_sd.c testbed_api_sd.h \
108 testbed_api_barriers.c
109libgnunettestbed_la_LIBADD = $(XLIB) \
110 $(top_builddir)/src/statistics/libgnunetstatistics.la \
111 $(top_builddir)/src/transport/libgnunettransport.la \
112 $(top_builddir)/src/hello/libgnunethello.la \
113 -lm $(Z_LIBS) \
114 $(top_builddir)/src/testing/libgnunettesting.la \
115 $(top_builddir)/src/arm/libgnunetarm.la \
116 $(top_builddir)/src/util/libgnunetutil.la \
117 $(LTLIBINTL)
118libgnunettestbed_la_LDFLAGS = \
119 $(GN_LIB_LDFLAGS) \
120 -version-info 0:0:0
121
122generate_underlay_topology_SOURCES = generate-underlay-topology.c
123generate_underlay_topology_LDADD = $(XLIB) \
124 $(top_builddir)/src/testing/libgnunettesting.la \
125 $(top_builddir)/src/util/libgnunetutil.la \
126 libgnunettestbed.la \
127 $(LTLIBINTL) -lsqlite3
128
129check_PROGRAMS = \
130 test_testbed_api_hosts \
131 test_gnunet_helper_testbed \
132 test_testbed_api_controllerlink \
133 test_testbed_api_2peers_1controller \
134 test_testbed_api_3peers_3controllers \
135 test_testbed_api \
136 test_testbed_api_sd \
137 test_testbed_api_operations \
138 test_testbed_api_testbed_run \
139 test_testbed_api_test \
140 test_testbed_api_test_timeout \
141 test_testbed_api_peer_reconfiguration \
142 test_testbed_api_peers_manage_services \
143 test_testbed_api_topology \
144 test_testbed_api_topology_clique \
145 test_testbed_api_testbed_run_topologyrandom \
146 test_testbed_api_testbed_run_topologyline \
147 test_testbed_api_testbed_run_topologystar \
148 test_testbed_api_testbed_run_topologyclique \
149 test_testbed_api_testbed_run_topologyring \
150 test_testbed_api_testbed_run_topologysmallworldring \
151 test_testbed_api_testbed_run_topology2dtorus \
152 test_testbed_api_testbed_run_topologysmallworld \
153 test_testbed_api_testbed_run_topologyfromfile \
154 test_testbed_api_testbed_run_topologyscalefree \
155 test_testbed_api_testbed_run_waitforever \
156 test_testbed_api_statistics \
157 gnunet-service-test-barriers \
158 test_testbed_api_barriers \
159 $(underlay_testcases)
160
161if ENABLE_TEST_RUN
162 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
163 TESTS = \
164 test_testbed_api \
165 test_testbed_api_sd \
166 test_testbed_api_operations \
167 test_testbed_api_hosts \
168 test_gnunet_helper_testbed \
169 test_testbed_api_2peers_1controller \
170 test_testbed_api_controllerlink \
171 test_testbed_api_3peers_3controllers \
172 test_testbed_api_testbed_run \
173 test_testbed_api_test \
174 test_testbed_api_test_timeout \
175 test_testbed_api_statistics \
176 test_testbed_api_peer_reconfiguration \
177 test_testbed_api_peers_manage_services \
178 test_testbed_api_topology \
179 test_testbed_api_topology_clique \
180 test_testbed_api_testbed_run_topologyrandom \
181 test_testbed_api_testbed_run_topologyline \
182 test_testbed_api_testbed_run_topologystar \
183 test_testbed_api_testbed_run_topologyclique \
184 test_testbed_api_testbed_run_topologyring \
185 test_testbed_api_testbed_run_topology2dtorus \
186 test_testbed_api_testbed_run_topologysmallworld \
187 test_testbed_api_testbed_run_topologysmallworldring \
188 test_testbed_api_testbed_run_topologyfromfile \
189 test_testbed_api_testbed_run_topologyscalefree \
190 test_testbed_api_barriers \
191 $(underlay_testcases)
192endif
193
194test_testbed_api_SOURCES = \
195 test_testbed_api.c
196test_testbed_api_LDADD = \
197 $(top_builddir)/src/util/libgnunetutil.la \
198 $(top_builddir)/src/testing/libgnunettesting.la \
199 $(top_builddir)/src/arm/libgnunetarm.la \
200 libgnunettestbed.la
201
202test_testbed_api_sd_SOURCES = \
203 test_testbed_api_sd.c
204test_testbed_api_sd_LDADD = \
205 $(top_builddir)/src/util/libgnunetutil.la \
206 libgnunettestbed.la
207
208test_testbed_api_2peers_1controller_SOURCES = \
209 test_testbed_api_2peers_1controller.c
210test_testbed_api_2peers_1controller_LDADD = \
211 $(top_builddir)/src/util/libgnunetutil.la \
212 $(top_builddir)/src/testing/libgnunettesting.la \
213 libgnunettestbed.la
214
215test_testbed_api_3peers_3controllers_SOURCES = \
216 test_testbed_api_3peers_3controllers.c
217test_testbed_api_3peers_3controllers_LDADD = \
218 $(top_builddir)/src/util/libgnunetutil.la \
219 $(top_builddir)/src/testing/libgnunettesting.la \
220 libgnunettestbed.la
221
222test_testbed_api_operations_SOURCES = \
223 test_testbed_api_operations.c
224test_testbed_api_operations_LDADD = \
225 $(top_builddir)/src/util/libgnunetutil.la \
226 libgnunettestbed.la
227
228test_testbed_api_hosts_SOURCES = \
229 test_testbed_api_hosts.c
230test_testbed_api_hosts_LDADD = \
231 $(top_builddir)/src/util/libgnunetutil.la \
232 libgnunettestbed.la
233
234test_testbed_api_controllerlink_SOURCES = \
235 test_testbed_api_controllerlink.c
236test_testbed_api_controllerlink_LDADD = \
237 $(top_builddir)/src/util/libgnunetutil.la \
238 libgnunettestbed.la
239
240test_testbed_api_testbed_run_SOURCES = \
241 test_testbed_api_testbed_run.c
242test_testbed_api_testbed_run_LDADD = \
243 $(top_builddir)/src/util/libgnunetutil.la \
244 libgnunettestbed.la
245
246test_testbed_api_test_SOURCES = \
247 test_testbed_api_test.c
248test_testbed_api_test_LDADD = \
249 $(top_builddir)/src/util/libgnunetutil.la \
250 libgnunettestbed.la
251
252test_testbed_api_test_timeout_SOURCES = \
253 test_testbed_api_test_timeout.c
254test_testbed_api_test_timeout_LDADD = \
255 $(top_builddir)/src/util/libgnunetutil.la \
256 libgnunettestbed.la
257
258test_testbed_api_topology_SOURCES = \
259 test_testbed_api_topology.c
260test_testbed_api_topology_LDADD = \
261 $(top_builddir)/src/util/libgnunetutil.la \
262 libgnunettestbed.la
263
264test_testbed_api_topology_clique_SOURCES = \
265 test_testbed_api_topology_clique.c
266test_testbed_api_topology_clique_LDADD = \
267 $(top_builddir)/src/util/libgnunetutil.la \
268 libgnunettestbed.la
269
270test_gnunet_helper_testbed_SOURCES = \
271 test_gnunet_helper_testbed.c
272test_gnunet_helper_testbed_LDADD = \
273 $(top_builddir)/src/util/libgnunetutil.la \
274 libgnunettestbed.la \
275 $(Z_LIBS)
276
277test_testbed_api_testbed_run_topologyrandom_SOURCES = \
278 test_testbed_api_testbed_run.c
279test_testbed_api_testbed_run_topologyrandom_LDADD = \
280 $(top_builddir)/src/util/libgnunetutil.la \
281 libgnunettestbed.la
282
283test_testbed_api_testbed_run_topologyline_SOURCES = \
284 test_testbed_api_testbed_run.c
285test_testbed_api_testbed_run_topologyline_LDADD = \
286 $(top_builddir)/src/util/libgnunetutil.la \
287 libgnunettestbed.la
288
289test_testbed_api_testbed_run_topologystar_SOURCES = \
290 test_testbed_api_testbed_run.c
291test_testbed_api_testbed_run_topologystar_LDADD = \
292 $(top_builddir)/src/util/libgnunetutil.la \
293 libgnunettestbed.la
294
295test_testbed_api_testbed_run_topologyclique_SOURCES = \
296 test_testbed_api_testbed_run.c
297test_testbed_api_testbed_run_topologyclique_LDADD = \
298 $(top_builddir)/src/util/libgnunetutil.la \
299 libgnunettestbed.la
300
301test_testbed_api_testbed_run_topologyring_SOURCES = \
302 test_testbed_api_testbed_run.c
303test_testbed_api_testbed_run_topologyring_LDADD = \
304 $(top_builddir)/src/util/libgnunetutil.la \
305 libgnunettestbed.la
306
307test_testbed_api_testbed_run_topologysmallworldring_SOURCES = \
308 test_testbed_api_testbed_run.c
309test_testbed_api_testbed_run_topologysmallworldring_LDADD = \
310 $(top_builddir)/src/util/libgnunetutil.la \
311 libgnunettestbed.la
312
313test_testbed_api_testbed_run_topology2dtorus_SOURCES = \
314 test_testbed_api_testbed_run.c
315test_testbed_api_testbed_run_topology2dtorus_LDADD = \
316 $(top_builddir)/src/util/libgnunetutil.la \
317 libgnunettestbed.la
318
319test_testbed_api_testbed_run_topologysmallworld_SOURCES = \
320 test_testbed_api_testbed_run.c
321test_testbed_api_testbed_run_topologysmallworld_LDADD = \
322 $(top_builddir)/src/util/libgnunetutil.la \
323 libgnunettestbed.la
324
325test_testbed_api_testbed_run_topologyfromfile_SOURCES = \
326 test_testbed_api_testbed_run.c
327test_testbed_api_testbed_run_topologyfromfile_LDADD = \
328 $(top_builddir)/src/util/libgnunetutil.la \
329 libgnunettestbed.la
330
331test_testbed_api_testbed_run_topologyscalefree_SOURCES = \
332 test_testbed_api_testbed_run.c
333test_testbed_api_testbed_run_topologyscalefree_LDADD = \
334 $(top_builddir)/src/util/libgnunetutil.la \
335 libgnunettestbed.la
336
337test_testbed_api_testbed_run_waitforever_SOURCES = \
338 test_testbed_api_testbed_run.c
339test_testbed_api_testbed_run_waitforever_LDADD = \
340 $(top_builddir)/src/util/libgnunetutil.la \
341 libgnunettestbed.la
342
343test_testbed_api_statistics_SOURCES = \
344 test_testbed_api_statistics.c
345test_testbed_api_statistics_LDADD = \
346 $(top_builddir)/src/util/libgnunetutil.la \
347 libgnunettestbed.la
348
349test_testbed_api_peers_manage_services_SOURCES = \
350 test_testbed_api_peers_manage_services.c
351test_testbed_api_peers_manage_services_LDADD = \
352 $(top_builddir)/src/util/libgnunetutil.la \
353 libgnunettestbed.la
354
355test_testbed_api_peer_reconfiguration_SOURCES = \
356 test_testbed_api_peer_reconfiguration.c
357test_testbed_api_peer_reconfiguration_LDADD = \
358 $(top_builddir)/src/util/libgnunetutil.la \
359 libgnunettestbed.la
360
361test_testbed_api_barriers_SOURCES = \
362 test_testbed_api_barriers.c \
363 test_testbed_api_barriers.h
364test_testbed_api_barriers_LDADD = \
365 $(top_builddir)/src/util/libgnunetutil.la \
366 libgnunettestbed.la
367
368gnunet_service_test_barriers_SOURCES = \
369 gnunet-service-test-barriers.c \
370 test_testbed_api_barriers.h
371gnunet_service_test_barriers_LDADD = \
372 $(top_builddir)/src/util/libgnunetutil.la \
373 libgnunettestbed.la
374
375test_testbed_underlay_SOURCES = \
376 test_testbed_underlay.c
377test_testbed_underlay_LDADD = \
378 $(top_builddir)/src/util/libgnunetutil.la \
379 libgnunettestbed.la
380
381EXTRA_DIST = \
382 test_testbed_api.conf \
383 test_testbed_api_statistics.conf \
384 test_testbed_api_test_timeout.conf \
385 test_testbed_api_template.conf \
386 test_testbed_api_testbed_run_topologyring.conf \
387 test_testbed_api_testbed_run_topologystar.conf \
388 test_testbed_api_testbed_run_topologyclique.conf \
389 test_testbed_api_testbed_run_topologyline.conf \
390 test_testbed_api_testbed_run_topologyrandom.conf \
391 test_testbed_api_testbed_run_topologysmallworldring.conf \
392 test_testbed_api_testbed_run_topology2dtorus.conf \
393 test_testbed_api_testbed_run_topologysmallworld.conf \
394 test_testbed_api_testbed_run_topologyfromfile.conf \
395 test_testbed_api_testbed_run_topologyscalefree.conf \
396 test_testbed_api_barriers.conf.in \
397 overlay_topology.txt \
398 sample_hosts.txt \
399 sample.job \
400 test_testbed_underlay.conf.in \
401 test-underlay.sqlite
diff --git a/src/testbed/barriers.README.org b/src/testbed/barriers.README.org
deleted file mode 100644
index 159e1c355..000000000
--- a/src/testbed/barriers.README.org
+++ /dev/null
@@ -1,95 +0,0 @@
1* Description
2The testbed subsystem's barriers API facilitates coordination among the peers
3run by the testbed and the experiment driver. The concept is similar to the
4barrier synchronisation mechanism found in parallel programming or
5multi-threading paradigms - a peer waits at a barrier upon reaching it until the
6barrier is reached by a predefined number of peers. This predefined number of
7peers required to cross a barrier is also called quorum. We say a peer has
8reached a barrier if the peer is waiting for the barrier to be crossed.
9Similarly a barrier is said to be reached if the required quorum of peers reach
10the barrier. A barrier which is reached is deemed as crossed after all the
11peers waiting on it are notified.
12
13The barriers API provides the following functions:
141) GNUNET_TESTBED_barrier_init(): function to initialise a barrier in the
15 experiment
162) GNUNET_TESTBED_barrier_cancel(): function to cancel a barrier which has been
17 initialised before
183) GNUNET_TESTBED_barrier_wait(): function to signal barrier service that the
19 caller has reached a barrier and is waiting for it to be crossed
204) GNUNET_TESTBED_barrier_wait_cancel(): function to stop waiting for a barrier
21 to be crossed
22
23Among the above functions, the first two, namely GNUNET_TESTBED_barrier_init()
24and GNUNET_TESTBED_barrier_cacel() are used by experiment drivers. All barriers
25should be initialised by the experiment driver by calling
26GNUNET_TESTBED_barrier_init(). This function takes a name to identify the
27barrier, the quorum required for the barrier to be crossed and a notification
28callback for notifying the experiment driver when the barrier is crossed. The
29GNUNET_TESTBED_function barrier_cancel() cancels an initialised barrier and
30frees the resources allocated for it. This function can be called upon a
31initialised barrier before it is crossed.
32
33The remaining two functions GNUNET_TESTBED_barrier_wait() and
34GNUNET_TESTBED_barrier_wait_cancel() are used in the peer's processes.
35GNUNET_TESTBED_barrier_wait() connects to the local barrier service running on
36the same host the peer is running on and registers that the caller has reached
37the barrier and is waiting for the barrier to be crossed. Note that this
38function can only be used by peers which are started by testbed as this function
39tries to access the local barrier service which is part of the testbed
40controller service. Calling GNUNET_TESTBED_barrier_wait() on an uninitialised
41barrier results in failure. GNUNET_TESTBED_barrier_wait_cancel() cancels the
42notification registered by GNUNET_TESTBED_barrier_wait().
43
44
45* Implementation
46Since barriers involve coordination between experiment driver and peers, the
47barrier service in the testbed controller is split into two components. The
48first component responds to the message generated by the barrier API used by the
49experiment driver (functions GNUNET_TESTBED_barrier_init() and
50GNUNET_TESTBED_barrier_cancel()) and the second component to the messages
51generated by barrier API used by peers (functions GNUNET_TESTBED_barrier_wait()
52and GNUNET_TESTBED_barrier_wait_cancel()).
53
54Calling GNUNET_TESTBED_barrier_init() sends a BARRIER_INIT message to the master
55controller. The master controller then registers a barrier and calls
56GNUNET_TESTBED_barrier_init() for each its subcontrollers. In this way barrier
57initialisation is propagated to the controller hierarchy. While propagating
58initialisation, any errors at a subcontroller such as timeout during further
59propagation are reported up the hierarchy back to the experiment driver.
60
61Similar to GNUNET_TESTBED_barrier_init(), GNUNET_TESTBED_barrier_cancel()
62propagates BARRIER_CANCEL message which causes controllers to remove an
63initialised barrier.
64
65The second component is implemented as a separate service in the binary
66`gnunet-service-testbed' which already has the testbed controller service.
67Although this deviates from the gnunet process architecture of having one
68service per binary, it is needed in this case as this component needs access to
69barrier data created by the first component. This component responds to
70BARRIER_WAIT messages from local peers when they call
71GNUNET_TESTBED_barrier_wait(). Upon receiving BARRIER_WAIT message, the service
72checks if the requested barrier has been initialised before and if it was not
73initialised, an error status is sent through BARRIER_STATUS message to the local
74peer and the connection from the peer is terminated. If the barrier is
75initialised before, the barrier's counter for reached peers is incremented and a
76notification is registered to notify the peer when the barrier is reached. The
77connection from the peer is left open.
78
79When enough peers required to attain the quorum send BARRIER_WAIT messages, the
80controller sends a BARRIER_STATUS message to its parent informing that the
81barrier is crossed. If the controller has started further subcontrollers, it
82delays this message until it receives a similar notification from each of those
83subcontrollers. Finally, the barriers API at the experiment driver receives the
84BARRIER_STATUS when the barrier is reached at all the controllers.
85
86The barriers API at the experiment driver responds to the BARRIER_STATUS message
87by echoing it back to the master controller and notifying the experiment
88controller through the notification callback that a barrier has been crossed.
89The echoed BARRIER_STATUS message is propagated by the master controller to the
90controller hierarchy. This propagation triggers the notifications registered by
91peers at each of the controllers in the hierarchy. Note the difference between
92this downward propagation of the BARRIER_STATUS message from its upward
93propagation -- the upward propagation is needed for ensuring that the barrier is
94reached by all the controllers and the downward propagation is for triggering
95that the barrier is crossed.
diff --git a/src/testbed/buildvars.py.in b/src/testbed/buildvars.py.in
deleted file mode 100644
index 3b2f56118..000000000
--- a/src/testbed/buildvars.py.in
+++ /dev/null
@@ -1,34 +0,0 @@
1# This file is part of GNUnet.
2# (C) 2008--2013, 2018 Christian Grothoff (and other contributing authors)
3#
4# GNUnet is free software: you can redistribute it and/or modify it
5# under the terms of the GNU Affero General Public License as published
6# by the Free Software Foundation, either version 3 of the License,
7# or (at your option) any later version.
8#
9# GNUnet is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# SPDX-License-Identifier: AGPL3.0-or-later
18
19# file: testbed/buildvars.py
20# brief: file for importing variables from build system into python
21# author: Sree Harsha Totakura
22
23import os
24
25exec_prefix = '@exec_prefix@'
26libexecdir = '@libexecdir@'
27
28if libexecdir.startswith(exec_prefix):
29 libexecdir = libexecdir[len(exec_prefix):]
30
31gnunet_prefix = os.environ.get('GNUNET_PREFIX', None)
32
33if gnunet_prefix and libexecdir.startswith('/'):
34 libexecdir = os.path.join(gnunet_prefix, libexecdir[1:])
diff --git a/src/testbed/generate-underlay-topology.c b/src/testbed/generate-underlay-topology.c
deleted file mode 100644
index b7bd8fce9..000000000
--- a/src/testbed/generate-underlay-topology.c
+++ /dev/null
@@ -1,407 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/generate-underlay-topology.c
23 * @brief Program to generate a database file containing given underlay topology
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30#include "testbed_api_topology.h"
31#include "sqlite3.h"
32
33#define LOG(type, ...) GNUNET_log (type, __VA_ARGS__)
34
35
36#define LOG_ERROR(...) LOG (GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
37
38/**
39 * Log an error message at log-level 'level' that indicates
40 * a failure of the command 'cmd' on file 'filename'
41 * with the message given by strerror(errno).
42 */
43#define LOG_SQLITE(db, msg, level, cmd) \
44 do \
45 { \
46 GNUNET_log_from (level, \
47 "sqlite", \
48 _ ("`%s' failed at %s:%d with error: %s\n"), \
49 cmd, \
50 __FILE__, \
51 __LINE__, \
52 sqlite3_errmsg (db)); \
53 if (msg != NULL) \
54 GNUNET_asprintf (msg, \
55 _ ("`%s' failed at %s:%u with error: %s"), \
56 cmd, \
57 __FILE__, \
58 __LINE__, \
59 sqlite3_errmsg (db)); \
60 } while (0)
61
62
63/**
64 * Handle to the sqlite3 database
65 */
66static struct sqlite3 *db;
67
68/**
69 * Prepared statement for inserting link values into db
70 */
71struct sqlite3_stmt *stmt_insert;
72
73/**
74 * The topology to generate
75 */
76enum GNUNET_TESTBED_TopologyOption topology;
77
78/**
79 * The number of peers to include in the topology
80 */
81static unsigned int num_peers;
82
83/**
84 * program result
85 */
86static int exit_result;
87
88
89/**
90 * Functions of this type are called to process underlay link
91 *
92 * @param cls closure
93 * @param A offset of first peer
94 * @param B offset of second peer
95 * @param bandwidth the bandwidth of the link in bytes per second
96 * @param latency the latency of link in milliseconds
97 * @param loss the percentage of messages dropped on the link
98 * @return GNUNET_OK to continue processing; GNUNET_SYSERR to abort
99 */
100static int
101link_processor (void *cls,
102 unsigned int A,
103 unsigned int B,
104 unsigned int bandwidth,
105 unsigned int latency,
106 unsigned int loss)
107{
108 if ((SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, A)) ||
109 (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, B)) ||
110 (SQLITE_OK != sqlite3_bind_int (stmt_insert, 3, bandwidth)) ||
111 (SQLITE_OK != sqlite3_bind_int (stmt_insert, 4, latency)) ||
112 (SQLITE_OK != sqlite3_bind_int (stmt_insert, 5, loss)))
113 {
114 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
115 return GNUNET_SYSERR;
116 }
117 if (SQLITE_DONE != sqlite3_step (stmt_insert))
118 {
119 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
120 return GNUNET_SYSERR;
121 }
122 fprintf (stdout, "%u -> %u\n", A, B);
123 GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
124 // GNUNET_break (SQLITE_OK == sqlite3_clear_bindings (stmt_insert));
125 if ((SQLITE_OK != sqlite3_bind_int (stmt_insert, 1, B)) ||
126 (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, A)))
127 {
128 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
129 return GNUNET_SYSERR;
130 }
131 if (SQLITE_DONE != sqlite3_step (stmt_insert))
132 {
133 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
134 return GNUNET_SYSERR;
135 }
136 fprintf (stdout, "%u -> %u\n", B, A);
137 GNUNET_break (SQLITE_OK == sqlite3_reset (stmt_insert));
138 return GNUNET_OK;
139}
140
141
142/**
143 * Open the database file, creating a new database if not existing and setup the
144 * whitelist table
145 *
146 * @param dbfile the database filename
147 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure (error message has
148 * to be printed)
149 */
150static int
151setup_db (const char *dbfile)
152{
153 const char *query_create = "CREATE TABLE whitelist ("
154 "id INTEGER,"
155 "oid INTEGER,"
156 "bandwidth INTEGER DEFAULT NULL,"
157 "latency INTEGER DEFAULT NULL,"
158 "loss INTEGER DEFAULT NULL,"
159 " UNIQUE ("
160 " id,"
161 " oid"
162 " ) ON CONFLICT IGNORE"
163 ");";
164 const char *query_insert = "INSERT INTO whitelist("
165 " id,"
166 " oid,"
167 " bandwidth,"
168 " latency,"
169 " loss"
170 ") VALUES ("
171 " ?1,"
172 " ?2,"
173 " ?3,"
174 " ?4,"
175 " ?5);";
176 int ret;
177
178 ret = GNUNET_SYSERR;
179 if (SQLITE_OK != sqlite3_open (dbfile, &db))
180 {
181 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_open");
182 goto err_ret;
183 }
184 if (0 != sqlite3_exec (db, query_create, NULL, NULL, NULL))
185 {
186 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
187 fprintf (stderr,
188 "Error: %d. Perhaps the database `%s' already exits.\n",
189 sqlite3_errcode (db),
190 dbfile);
191 goto err_ret;
192 }
193 GNUNET_break (0 ==
194 sqlite3_exec (db, "PRAGMA synchronous = 0;", NULL, NULL, NULL));
195 if (SQLITE_OK !=
196 sqlite3_prepare_v2 (db, query_insert, -1, &stmt_insert, NULL))
197 {
198 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
199 goto err_ret;
200 }
201 ret = GNUNET_OK;
202
203err_ret:
204 return ret;
205}
206
207
208/**
209 * Main run function.
210 *
211 * @param cls NULL
212 * @param args arguments passed to GNUNET_PROGRAM_run
213 * @param cfgfile the path to configuration file
214 * @param cfg the configuration file handle
215 */
216static void
217run (void *cls,
218 char *const *args,
219 const char *cfgfile,
220 const struct GNUNET_CONFIGURATION_Handle *config)
221{
222 const char *dbfile;
223 const char *topology_string;
224 unsigned int arg_uint1;
225 unsigned int arg_uint2;
226 const char *arg_str1;
227 const char *value;
228 unsigned int argc;
229
230 argc = 0;
231 arg_uint1 = 0; /* make compilers happy */
232 arg_uint2 = 0; /* make compilers happy */
233 if (NULL == args)
234 {
235 LOG_ERROR (_ ("Need at least 2 arguments\n"));
236 return;
237 }
238 if (NULL == (dbfile = args[argc++]))
239 {
240 LOG_ERROR (_ ("Database filename missing\n"));
241 return;
242 }
243 if (GNUNET_OK != setup_db (dbfile))
244 return;
245 if (NULL == (topology_string = args[argc++]))
246 {
247 LOG_ERROR (_ ("Topology string missing\n"));
248 return;
249 }
250 if (GNUNET_YES != GNUNET_TESTBED_topology_get_ (&topology, topology_string))
251 {
252 LOG_ERROR (_ ("Invalid topology: %s\n"), topology_string);
253 return;
254 }
255 arg_str1 = NULL;
256 /* parse for first TOPOOPT. This can either be arg_uint1 or arg_str1 */
257 switch (topology)
258 {
259 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
260 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
261 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
262 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
263 if (NULL == (value = args[argc++]))
264 {
265 LOG_ERROR (_ ("An argument is missing for given topology `%s'\n"),
266 topology_string);
267 return;
268 }
269 if (-1 == sscanf (value, "%u", &arg_uint1))
270 {
271 LOG_ERROR (_ ("Invalid argument `%s' given as topology argument\n"),
272 value);
273 return;
274 }
275 break;
276
277 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
278 if (NULL == (arg_str1 = args[argc++]))
279 {
280 LOG_ERROR (_ ("Filename argument missing for topology `%s'\n"),
281 topology_string);
282 return;
283 }
284 break;
285
286 default:
287 break;
288 }
289 /* parse for second TOPOOPT. Only required for SCALE_FREE topology */
290 switch (topology)
291 {
292 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
293 if (NULL == (value = args[argc++]))
294 {
295 LOG_ERROR (_ ("Second argument for topology `%s' is missing\n"),
296 topology_string);
297 return;
298 }
299 if (-1 == sscanf (value, "%u", &arg_uint2))
300 {
301 LOG_ERROR (_ ("Invalid argument `%s'; expecting unsigned int\n"), value);
302 return;
303 }
304 break;
305
306 default:
307 break;
308 }
309 /* construct topologies */
310 switch (topology)
311 {
312 case GNUNET_TESTBED_TOPOLOGY_LINE:
313 case GNUNET_TESTBED_TOPOLOGY_RING:
314 case GNUNET_TESTBED_TOPOLOGY_STAR:
315 case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
316 case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
317 GNUNET_TESTBED_underlay_construct_ (num_peers,
318 link_processor,
319 NULL,
320 topology);
321 break;
322
323 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
324 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
325 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
326 GNUNET_TESTBED_underlay_construct_ (num_peers,
327 link_processor,
328 NULL,
329 topology,
330 arg_uint1);
331 break;
332
333 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
334 GNUNET_TESTBED_underlay_construct_ (num_peers,
335 link_processor,
336 NULL,
337 topology,
338 arg_str1);
339 break;
340
341 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
342 GNUNET_TESTBED_underlay_construct_ (num_peers,
343 link_processor,
344 NULL,
345 topology,
346 arg_uint1,
347 arg_uint2);
348 break;
349
350 default:
351 GNUNET_assert (0);
352 }
353}
354
355
356/**
357 * Main
358 */
359int
360main (int argc, char *const argv[])
361{
362 struct GNUNET_GETOPT_CommandLineOption option[] = {
363 GNUNET_GETOPT_option_uint ('p',
364 "num-peers",
365 "COUNT",
366 gettext_noop ("create COUNT number of peers"),
367 &num_peers),
368 GNUNET_GETOPT_OPTION_END
369 };
370
371 int ret;
372
373 exit_result = GNUNET_SYSERR;
374 ret = GNUNET_PROGRAM_run (
375 argc,
376 argv,
377 "gnunet-underlay-topology",
378 _ (
379 "Generates SQLite3 database representing a given underlay topology.\n"
380 "Usage: gnunet-underlay-topology [OPTIONS] db-filename TOPO [TOPOOPTS]\n"
381 "The following options are available for TOPO followed by TOPOOPTS if applicable:\n"
382 "\t LINE\n"
383 "\t RING\n"
384 "\t RANDOM <num_rnd_links>\n"
385 "\t SMALL_WORLD <num_rnd_links>\n"
386 "\t SMALL_WORLD_RING <num_rnd_links>\n"
387 "\t CLIQUE\n"
388 "\t 2D_TORUS\n"
389 "\t SCALE_FREE <cap> <m>\n"
390 "\t FROM_FILE <filename>\n"
391 "TOPOOPTS:\n"
392 "\t num_rnd_links: The number of random links\n"
393 "\t cap: the maximum number of links a node can have\n"
394 "\t m: the number of links a node should have while joining the network\n"
395 "\t filename: the path of the file which contains topology information\n"
396 "NOTE: the format of the above file is described here: https://www.gnunet.org/content/topology-file-format\n"),
397 option,
398 &run,
399 NULL);
400 if (NULL != stmt_insert)
401 sqlite3_finalize (stmt_insert);
402 if (NULL != db)
403 GNUNET_break (SQLITE_OK == sqlite3_close (db));
404 if ((GNUNET_OK != ret) || (GNUNET_OK != exit_result))
405 return 1;
406 return 0;
407}
diff --git a/src/testbed/gnunet-daemon-latency-logger.c b/src/testbed/gnunet-daemon-latency-logger.c
deleted file mode 100644
index cbc9cfdbf..000000000
--- a/src/testbed/gnunet-daemon-latency-logger.c
+++ /dev/null
@@ -1,322 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-daemon-latency-logger.c
23 * @brief log latency values from neighbour connections into an SQLite database
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_ats_service.h"
30#include <sqlite3.h>
31
32
33/**
34 * Logging shorthand
35 */
36#define LOG(type, ...) \
37 GNUNET_log (type, __VA_ARGS__)
38
39/**
40 * Debug logging shorthand
41 */
42#define DEBUG(...) \
43 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
44
45/**
46 * Log an error message at log-level 'level' that indicates
47 * a failure of the command 'cmd' on file 'filename'
48 * with the message given by strerror(errno).
49 */
50#define LOG_SQLITE(db, msg, level, cmd) \
51 do { \
52 GNUNET_log_from (level, "sqlite", _ ( \
53 "`%s' failed at %s:%d with error: %s\n"), \
54 cmd, __FILE__, __LINE__, sqlite3_errmsg (db)); \
55 if (msg != NULL) \
56 GNUNET_asprintf (msg, _ ("`%s' failed at %s:%u with error: %s"), cmd, \
57 __FILE__, __LINE__, sqlite3_errmsg (db)); \
58 } while (0)
59
60
61/**
62 * Entry type to be used in the map to store old latency values
63 */
64struct Entry
65{
66 /**
67 * The peer's identity
68 */
69 struct GNUNET_PeerIdentity id;
70
71 /**
72 * The last known value for latency.
73 * FIXME: type!
74 */
75 unsigned int latency;
76};
77
78
79/**
80 * Handle to the map used to store old latency values for peers
81 */
82static struct GNUNET_CONTAINER_MultiPeerMap *map;
83
84/**
85 * The SQLite database handle
86 */
87static struct sqlite3 *db;
88
89/**
90 * Handle to the ATS performance subsystem
91 */
92static struct GNUNET_ATS_PerformanceHandle *ats;
93
94/**
95 * Prepared statement for inserting values into the database table
96 */
97static struct sqlite3_stmt *stmt_insert;
98
99
100/**
101 * @ingroup hashmap
102 * Iterator over hash map entries.
103 *
104 * @param cls closure
105 * @param key current public key
106 * @param value value in the hash map
107 * @return #GNUNET_YES if we should continue to
108 * iterate,
109 * #GNUNET_NO if not.
110 */
111static int
112free_iterator (void *cls,
113 const struct GNUNET_PeerIdentity *key,
114 void *value)
115{
116 struct Entry *e = cls;
117
118 GNUNET_assert (GNUNET_YES ==
119 GNUNET_CONTAINER_multipeermap_remove (map, key, e));
120 GNUNET_free (e);
121 return GNUNET_YES;
122}
123
124
125/**
126 * Shutdown
127 *
128 * @param cls NULL
129 * @return
130 */
131static void
132do_shutdown (void *cls)
133{
134 GNUNET_ATS_performance_done (ats);
135 ats = NULL;
136 if (NULL != stmt_insert)
137 {
138 sqlite3_finalize (stmt_insert);
139 stmt_insert = NULL;
140 }
141 GNUNET_break (SQLITE_OK == sqlite3_close (db));
142 db = NULL;
143 if (NULL != map)
144 {
145 GNUNET_assert (GNUNET_SYSERR !=
146 GNUNET_CONTAINER_multipeermap_iterate (map, free_iterator,
147 NULL));
148 GNUNET_CONTAINER_multipeermap_destroy (map);
149 map = NULL;
150 }
151}
152
153
154/**
155 * Signature of a function that is called with QoS information about an address.
156 *
157 * @param cls closure
158 * @param address the address
159 * @param address_active #GNUNET_YES if this address is actively used
160 * to maintain a connection to a peer;
161 * #GNUNET_NO if the address is not actively used;
162 * #GNUNET_SYSERR if this address is no longer available for ATS
163 * @param bandwidth_out assigned outbound bandwidth for the connection
164 * @param bandwidth_in assigned inbound bandwidth for the connection
165 * @param prop performance data for the address (as far as known)
166 */
167static void
168addr_info_cb (void *cls,
169 const struct GNUNET_HELLO_Address *address,
170 int address_active,
171 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
172 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
173 const struct GNUNET_ATS_Properties *prop)
174{
175 static const char *query_insert =
176 "INSERT INTO ats_info("
177 " id,"
178 " val,"
179 " timestamp"
180 ") VALUES ("
181 " ?1,"
182 " ?2,"
183 " datetime('now')"
184 ");";
185 struct Entry *entry;
186 int latency; /* FIXME: type!? */
187
188 if (NULL == address)
189 {
190 /* ATS service temporarily disconnected */
191 return;
192 }
193
194 GNUNET_assert (NULL != db);
195 if (GNUNET_YES != address_active)
196 return;
197 latency = (int) prop->delay.rel_value_us;
198 entry = NULL;
199 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (map,
200 &address->peer))
201 {
202 entry = GNUNET_CONTAINER_multipeermap_get (map, &address->peer);
203 GNUNET_assert (NULL != entry);
204 if (latency == entry->latency)
205 return;
206 }
207 if (NULL == stmt_insert)
208 {
209 if (SQLITE_OK != sqlite3_prepare_v2 (db, query_insert, -1, &stmt_insert,
210 NULL))
211 {
212 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
213 goto err_shutdown;
214 }
215 }
216 if ((SQLITE_OK != sqlite3_bind_text (stmt_insert, 1,
217 GNUNET_i2s (&address->peer), -1,
218 SQLITE_STATIC)) ||
219 (SQLITE_OK != sqlite3_bind_int (stmt_insert, 2, latency)))
220 {
221 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_text");
222 goto err_shutdown;
223 }
224 if (SQLITE_DONE != sqlite3_step (stmt_insert))
225 {
226 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_step");
227 goto err_shutdown;
228 }
229 if (SQLITE_OK != sqlite3_reset (stmt_insert))
230 {
231 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_insert");
232 goto err_shutdown;
233 }
234 if (NULL == entry)
235 {
236 entry = GNUNET_new (struct Entry);
237 entry->id = address->peer;
238 GNUNET_CONTAINER_multipeermap_put (map,
239 &entry->id, entry,
240 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
241 }
242 entry->latency = latency;
243 return;
244
245err_shutdown:
246 GNUNET_SCHEDULER_shutdown ();
247}
248
249
250/**
251 * Main function that will be run.
252 *
253 * @param cls closure
254 * @param args remaining command-line arguments
255 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
256 * @param c configuration
257 */
258static void
259run (void *cls, char *const *args, const char *cfgfile,
260 const struct GNUNET_CONFIGURATION_Handle *c)
261{
262 const char *query_create =
263 "CREATE TABLE ats_info ("
264 "id TEXT,"
265 "val INTEGER,"
266 "timestamp NUMERIC"
267 ");";
268 char *dbfile;
269
270 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "LATENCY-LOGGER",
271 "DBFILE",
272 &dbfile))
273 {
274 GNUNET_break (0);
275 return;
276 }
277 if (SQLITE_OK != sqlite3_open (dbfile, &db))
278 {
279 if (NULL != db)
280 {
281 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_open_v2");
282 GNUNET_break (SQLITE_OK == sqlite3_close (db));
283 }
284 else
285 LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot open sqlite file %s\n", dbfile);
286 GNUNET_free (dbfile);
287 return;
288 }
289 if (0 != sqlite3_exec (db, query_create, NULL, NULL, NULL))
290 DEBUG ("SQLite Error: %d. Perhaps the database `%s' already exits.\n",
291 sqlite3_errcode (db), dbfile);
292 DEBUG ("Opened database %s\n", dbfile);
293 GNUNET_free (dbfile);
294 dbfile = NULL;
295 ats = GNUNET_ATS_performance_init (c, &addr_info_cb, NULL);
296 map = GNUNET_CONTAINER_multipeermap_create (30, GNUNET_YES);
297 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
298}
299
300
301/**
302 * Execution entry point
303 */
304int
305main (int argc, char *const *argv)
306{
307 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
308 GNUNET_GETOPT_OPTION_END
309 };
310 int ret;
311
312 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
313 return 2;
314 ret =
315 (GNUNET_OK ==
316 GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-latency-logger",
317 _ (
318 "Daemon to log latency values of connections to neighbours"),
319 options, &run, NULL)) ? 0 : 1;
320 GNUNET_free_nz ((void *) argv);
321 return ret;
322}
diff --git a/src/testbed/gnunet-daemon-testbed-blacklist.c b/src/testbed/gnunet-daemon-testbed-blacklist.c
deleted file mode 100644
index c82f8075f..000000000
--- a/src/testbed/gnunet-daemon-testbed-blacklist.c
+++ /dev/null
@@ -1,254 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21
22/**
23 * @file testbed/gnunet-daemon-testbed-blacklist.c
24 * @brief daemon to restrict incoming connections from other peers at the
25 * transport layer of a peer
26 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
27 */
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_transport_service.h"
32
33
34/**
35 * Logging shorthand
36 */
37#define LOG(type, ...) \
38 GNUNET_log (type, __VA_ARGS__)
39
40/**
41 * Debug logging shorthand
42 */
43#define DEBUG(...) \
44 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
45
46/**
47 * Allow access from the peers read from the whitelist
48 */
49#define ACCESS_ALLOW 1
50
51/**
52 * Deny access from the peers read from the blacklist
53 */
54#define ACCESS_DENY 0
55
56/**
57 * The map to store the peer identities to allow/deny
58 */
59static struct GNUNET_CONTAINER_MultiPeerMap *map;
60
61/**
62 * The array of peer identities we read from whitelist/blacklist
63 */
64static struct GNUNET_PeerIdentity *ilist;
65
66/**
67 * The blacklist handle we obtain from transport when we register ourselves for
68 * access control
69 */
70static struct GNUNET_TRANSPORT_Blacklist *bh;
71
72/**
73 * Are we allowing or denying access from peers
74 */
75static int mode;
76
77
78/**
79 * Cleaup and destroy the map
80 */
81static void
82cleanup_map ()
83{
84 if (NULL != map)
85 {
86 GNUNET_CONTAINER_multipeermap_destroy (map);
87 map = NULL;
88 }
89}
90
91
92/**
93 * Shutdown task to cleanup our resources and exit.
94 *
95 * @param cls NULL
96 */
97static void
98do_shutdown (void *cls)
99{
100 cleanup_map ();
101 if (NULL != bh)
102 GNUNET_TRANSPORT_blacklist_cancel (bh);
103}
104
105
106/**
107 * Function that decides if a connection is acceptable or not.
108 *
109 * @param cls closure
110 * @param pid peer to approve or disapproave
111 * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not
112 */
113static int
114check_access (void *cls, const struct GNUNET_PeerIdentity *pid)
115{
116 int contains;
117
118 if (NULL != map)
119 contains = GNUNET_CONTAINER_multipeermap_contains (map, pid);
120 else
121 contains = GNUNET_NO;
122 if (ACCESS_DENY == mode)
123 return (contains) ? GNUNET_SYSERR : GNUNET_OK;
124 return (contains) ? GNUNET_OK : GNUNET_SYSERR;
125}
126
127
128/**
129 * Setup the access control by reading the given file containing peer identities
130 * and then establishing blacklist handler with the peer's transport service
131 *
132 * @param fname the filename to read the list of peer identities
133 * @param cfg the configuration for connecting to the peer's transport service
134 */
135static void
136setup_ac (const char *fname,
137 const struct GNUNET_CONFIGURATION_Handle *cfg)
138{
139 uint64_t fsize;
140 unsigned int npeers;
141 unsigned int cnt;
142
143 GNUNET_assert (GNUNET_OK !=
144 GNUNET_DISK_file_size (fname, &fsize, GNUNET_NO,
145 GNUNET_YES));
146 if (0 != (fsize % sizeof(struct GNUNET_PeerIdentity)))
147 {
148 GNUNET_break (0);
149 return;
150 }
151 npeers = fsize / sizeof(struct GNUNET_PeerIdentity);
152 if (0 != npeers)
153 {
154 map = GNUNET_CONTAINER_multipeermap_create (npeers, GNUNET_YES);
155 ilist = GNUNET_malloc_large (fsize);
156 GNUNET_assert (fsize == GNUNET_DISK_fn_read (fname, ilist, fsize));
157 }
158 for (cnt = 0; cnt < npeers; cnt++)
159 {
160 if (GNUNET_SYSERR ==
161 GNUNET_CONTAINER_multipeermap_put (map, &ilist[cnt],
162 &ilist[cnt],
163 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
164 {
165 cleanup_map ();
166 GNUNET_free (ilist);
167 return;
168 }
169 }
170 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
171 bh = GNUNET_TRANSPORT_blacklist (cfg, &check_access, NULL);
172}
173
174
175/**
176 * Main function that will be run.
177 *
178 * @param cls closure
179 * @param args remaining command-line arguments
180 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
181 * @param c configuration
182 */
183static void
184run (void *cls,
185 char *const *args,
186 const char *cfgfile,
187 const struct GNUNET_CONFIGURATION_Handle *c)
188{
189 char *shome;
190 char *fname;
191
192 if (GNUNET_OK !=
193 GNUNET_CONFIGURATION_get_value_filename (c,
194 "PATHS",
195 "GNUNET_HOME",
196 &shome))
197 {
198 GNUNET_break (0);
199 return;
200 }
201 GNUNET_asprintf (&fname,
202 "%s/whitelist",
203 shome);
204 if (GNUNET_YES == GNUNET_DISK_file_test (fname))
205 {
206 mode = ACCESS_ALLOW;
207 setup_ac (fname, c);
208 GNUNET_free (shome);
209 GNUNET_free (fname);
210 return;
211 }
212 GNUNET_free (fname);
213 GNUNET_asprintf (&fname,
214 "%s/blacklist",
215 shome);
216 if (GNUNET_YES == GNUNET_DISK_file_test (fname))
217 {
218 mode = ACCESS_DENY;
219 setup_ac (shome, c);
220 }
221 GNUNET_free (shome);
222 GNUNET_free (fname);
223}
224
225
226/**
227 * The main function.
228 *
229 * @param argc number of arguments from the command line
230 * @param argv command line arguments
231 * @return 0 ok, 1 on error
232 */
233int
234main (int argc, char *const *argv)
235{
236 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
237 GNUNET_GETOPT_OPTION_END
238 };
239 int ret;
240
241 if (GNUNET_OK !=
242 GNUNET_STRINGS_get_utf8_args (argc, argv,
243 &argc, &argv))
244 return 2;
245 ret =
246 (GNUNET_OK ==
247 GNUNET_PROGRAM_run (argc, argv,
248 "gnunet-daemon-testbed-blacklist",
249 _ (
250 "Daemon to restrict incoming transport layer connections during testbed deployments"),
251 options, &run, NULL)) ? 0 : 1;
252 GNUNET_free_nz ((void *) argv);
253 return ret;
254}
diff --git a/src/testbed/gnunet-daemon-testbed-underlay.c b/src/testbed/gnunet-daemon-testbed-underlay.c
deleted file mode 100644
index c3b424c9b..000000000
--- a/src/testbed/gnunet-daemon-testbed-underlay.c
+++ /dev/null
@@ -1,481 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21
22/**
23 * @file testbed/gnunet-daemon-testbed-blacklist.c
24 * @brief daemon to restrict incoming connections from other peers at the
25 * transport layer of a peer
26 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
27 */
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_transport_service.h"
32#include "gnunet_transport_manipulation_service.h"
33#include "gnunet_ats_service.h"
34#include "gnunet_testing_lib.h"
35#include <sqlite3.h>
36
37/**
38 * Logging shorthand
39 */
40#define LOG(type, ...) \
41 GNUNET_log (type, __VA_ARGS__)
42
43/**
44 * Debug logging shorthand
45 */
46#define DEBUG(...) \
47 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
48
49/**
50 * Log an error message at log-level 'level' that indicates
51 * a failure of the command 'cmd' on file 'filename'
52 * with the message given by strerror(errno).
53 */
54#define LOG_SQLITE(db, msg, level, cmd) \
55 do { \
56 GNUNET_log_from (level, "sqlite", _ ( \
57 "`%s' failed at %s:%d with error: %s\n"), \
58 cmd, __FILE__, __LINE__, sqlite3_errmsg (db)); \
59 if (msg != NULL) \
60 GNUNET_asprintf (msg, _ ("`%s' failed at %s:%u with error: %s"), cmd, \
61 __FILE__, __LINE__, sqlite3_errmsg (db)); \
62 } while (0)
63
64
65/**
66 * The map to store the peer identities to allow/deny
67 */
68static struct GNUNET_CONTAINER_MultiPeerMap *map;
69
70/**
71 * The database connection
72 */
73static struct sqlite3 *db;
74
75/**
76 * The blacklist handle we obtain from transport when we register ourselves for
77 * access control
78 */
79static struct GNUNET_TRANSPORT_Blacklist *bh;
80
81/**
82 * The hostkeys file
83 */
84struct GNUNET_DISK_FileHandle *hostkeys_fd;
85
86/**
87 * The hostkeys map
88 */
89static struct GNUNET_DISK_MapHandle *hostkeys_map;
90
91/**
92 * The hostkeys data
93 */
94static void *hostkeys_data;
95
96/**
97 * Handle to the transport service. This is used for setting link metrics
98 */
99static struct GNUNET_TRANSPORT_ManipulationHandle *transport;
100
101/**
102 * The number of hostkeys in the hostkeys array
103 */
104static unsigned int num_hostkeys;
105
106
107/**
108 * @ingroup hashmap
109 * Iterator over hash map entries.
110 *
111 * @param cls closure
112 * @param key current key code
113 * @param value value in the hash map
114 * @return #GNUNET_YES if we should continue to
115 * iterate,
116 * #GNUNET_NO if not.
117 */
118static int
119iterator (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
120{
121 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (map, key,
122 value));
123 return GNUNET_YES;
124}
125
126
127/**
128 * Cleaup and destroy the map
129 */
130static void
131cleanup_map ()
132{
133 if (NULL != map)
134 {
135 GNUNET_assert (GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_iterate (map,
136 &
137 iterator,
138 NULL));
139 GNUNET_CONTAINER_multipeermap_destroy (map);
140 map = NULL;
141 }
142}
143
144
145/**
146 * Function that decides if a connection is acceptable or not.
147 *
148 * @param cls closure
149 * @param pid peer to approve or disapproave
150 * @return GNUNET_OK if the connection is allowed, GNUNET_SYSERR if not
151 */
152static int
153check_access (void *cls, const struct GNUNET_PeerIdentity *pid)
154{
155 int contains;
156
157 GNUNET_assert (NULL != map);
158 contains = GNUNET_CONTAINER_multipeermap_contains (map, pid);
159 if (GNUNET_YES == contains)
160 {
161 DEBUG ("Permitting `%s'\n", GNUNET_i2s (pid));
162 return GNUNET_OK;
163 }
164 DEBUG ("Not permitting `%s'\n", GNUNET_i2s (pid));
165 return GNUNET_SYSERR;
166}
167
168
169static int
170get_identity (unsigned int offset,
171 struct GNUNET_PeerIdentity *id)
172{
173 struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
174
175 if (offset >= num_hostkeys)
176 return GNUNET_SYSERR;
177 GNUNET_memcpy (&private_key,
178 hostkeys_data + (offset * GNUNET_TESTING_HOSTKEYFILESIZE),
179 GNUNET_TESTING_HOSTKEYFILESIZE);
180 GNUNET_CRYPTO_eddsa_key_get_public (&private_key,
181 &id->public_key);
182 return GNUNET_OK;
183}
184
185
186/**
187 * Whilelist entry
188 */
189struct WhiteListRow
190{
191 /**
192 * Next ptr
193 */
194 struct WhiteListRow *next;
195
196 /**
197 * The offset where to find the hostkey for the peer
198 */
199 unsigned int id;
200
201 /**
202 * Latency to be assigned to the link
203 */
204 int latency;
205};
206
207
208/**
209 * Function to load keys
210 */
211static int
212load_keys (const struct GNUNET_CONFIGURATION_Handle *c)
213{
214 char *data_dir;
215 char *idfile;
216 uint64_t fsize;
217
218 data_dir = NULL;
219 idfile = NULL;
220 fsize = 0;
221 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
222 GNUNET_asprintf (&idfile, "%s/testing_hostkeys.ecc", data_dir);
223 GNUNET_free (data_dir);
224 data_dir = NULL;
225 if (GNUNET_OK !=
226 GNUNET_DISK_file_size (idfile, &fsize, GNUNET_YES, GNUNET_YES))
227 {
228 GNUNET_free (idfile);
229 return GNUNET_SYSERR;
230 }
231 if (0 != (fsize % GNUNET_TESTING_HOSTKEYFILESIZE))
232 {
233 LOG (GNUNET_ERROR_TYPE_ERROR,
234 _ ("Incorrect hostkey file format: %s\n"), idfile);
235 GNUNET_free (idfile);
236 return GNUNET_SYSERR;
237 }
238 hostkeys_fd = GNUNET_DISK_file_open (idfile, GNUNET_DISK_OPEN_READ,
239 GNUNET_DISK_PERM_NONE);
240 if (NULL == hostkeys_fd)
241 {
242 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", idfile);
243 GNUNET_free (idfile);
244 return GNUNET_SYSERR;
245 }
246 GNUNET_free (idfile);
247 idfile = NULL;
248 hostkeys_data = GNUNET_DISK_file_map (hostkeys_fd,
249 &hostkeys_map,
250 GNUNET_DISK_MAP_TYPE_READ,
251 fsize);
252 if (NULL == hostkeys_data)
253 {
254 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "mmap");
255 return GNUNET_SYSERR;
256 }
257 num_hostkeys = fsize / GNUNET_TESTING_HOSTKEYFILESIZE;
258 return GNUNET_OK;
259}
260
261
262/**
263 * Function to unload keys
264 */
265static void
266unload_keys ()
267{
268 if (NULL != hostkeys_map)
269 {
270 GNUNET_assert (NULL != hostkeys_data);
271 GNUNET_DISK_file_unmap (hostkeys_map);
272 hostkeys_map = NULL;
273 hostkeys_data = NULL;
274 }
275 if (NULL != hostkeys_fd)
276 {
277 GNUNET_DISK_file_close (hostkeys_fd);
278 hostkeys_fd = NULL;
279 }
280}
281
282
283/**
284 * Shutdown task to cleanup our resources and exit.
285 *
286 * @param cls NULL
287 */
288static void
289do_shutdown (void *cls)
290{
291 if (NULL != transport)
292 {
293 GNUNET_TRANSPORT_manipulation_disconnect (transport);
294 transport = NULL;
295 }
296 cleanup_map ();
297 unload_keys ();
298 if (NULL != bh)
299 GNUNET_TRANSPORT_blacklist_cancel (bh);
300}
301
302
303/**
304 * Function to read whitelist rows from the database
305 *
306 * @param db the database connection
307 * @param pid the identity of this peer
308 * @param wl_rows where to store the retrieved whitelist rows
309 * @return GNUNET_SYSERR upon error OR the number of rows retrieved
310 */
311static int
312db_read_whitelist (struct sqlite3 *db, int pid, struct WhiteListRow **wl_rows)
313{
314 static const char *query_wl =
315 "SELECT oid, latency FROM whitelist WHERE (id == ?);";
316 struct sqlite3_stmt *stmt_wl;
317 struct WhiteListRow *lr;
318 int nrows;
319 int ret;
320
321 if (SQLITE_OK != (ret = sqlite3_prepare_v2 (db, query_wl, -1, &stmt_wl,
322 NULL)))
323 {
324 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_prepare_v2");
325 return GNUNET_SYSERR;
326 }
327 if (SQLITE_OK != (ret = sqlite3_bind_int (stmt_wl, 1, pid)))
328 {
329 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite3_bind_int");
330 sqlite3_finalize (stmt_wl);
331 return GNUNET_SYSERR;
332 }
333 nrows = 0;
334 do
335 {
336 ret = sqlite3_step (stmt_wl);
337 if (SQLITE_ROW != ret)
338 break;
339 nrows++;
340 lr = GNUNET_new (struct WhiteListRow);
341 lr->id = sqlite3_column_int (stmt_wl, 0);
342 lr->latency = sqlite3_column_int (stmt_wl, 1);
343 lr->next = *wl_rows;
344 *wl_rows = lr;
345 }
346 while (1);
347 sqlite3_finalize (stmt_wl);
348 return nrows;
349}
350
351
352/**
353 * Main function that will be run.
354 *
355 * @param cls closure
356 * @param args remaining command-line arguments
357 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
358 * @param c configuration
359 */
360static void
361run (void *cls, char *const *args, const char *cfgfile,
362 const struct GNUNET_CONFIGURATION_Handle *c)
363{
364 char *dbfile;
365 struct WhiteListRow *wl_head;
366 struct WhiteListRow *wl_entry;
367 struct GNUNET_PeerIdentity identity;
368 struct GNUNET_ATS_Properties prop;
369 struct GNUNET_TIME_Relative delay;
370 unsigned long long pid;
371 unsigned int nrows;
372 int ret;
373
374 if (GNUNET_OK !=
375 GNUNET_CONFIGURATION_get_value_number (c, "TESTBED",
376 "PEERID", &pid))
377 {
378 GNUNET_break (0);
379 return;
380 }
381 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c,
382 "TESTBED-UNDERLAY",
383 "DBFILE",
384 &dbfile))
385 {
386 GNUNET_break (0);
387 return;
388 }
389 if (SQLITE_OK != (ret = sqlite3_open_v2 (dbfile, &db, SQLITE_OPEN_READONLY,
390 NULL)))
391 {
392 if (NULL != db)
393 {
394 LOG_SQLITE (db, NULL, GNUNET_ERROR_TYPE_ERROR, "sqlite_open_v2");
395 GNUNET_break (SQLITE_OK == sqlite3_close (db));
396 }
397 else
398 LOG (GNUNET_ERROR_TYPE_ERROR, "Cannot open sqlite file %s\n", dbfile);
399 GNUNET_free (dbfile);
400 return;
401 }
402 DEBUG ("Opened database %s\n", dbfile);
403 GNUNET_free (dbfile);
404 dbfile = NULL;
405 wl_head = NULL;
406 if (GNUNET_OK != load_keys (c))
407 goto close_db;
408
409 transport = GNUNET_TRANSPORT_manipulation_connect (c);
410 if (NULL == transport)
411 {
412 GNUNET_break (0);
413 return;
414 }
415 /* read and process whitelist */
416 nrows = 0;
417 wl_head = NULL;
418 nrows = db_read_whitelist (db, pid, &wl_head);
419 if ((GNUNET_SYSERR == nrows) || (0 == nrows))
420 {
421 GNUNET_TRANSPORT_manipulation_disconnect (transport);
422 goto close_db;
423 }
424 map = GNUNET_CONTAINER_multipeermap_create (nrows, GNUNET_NO);
425 while (NULL != (wl_entry = wl_head))
426 {
427 wl_head = wl_entry->next;
428 delay.rel_value_us = wl_entry->latency;
429 memset (&prop, 0, sizeof(prop));
430 GNUNET_assert (GNUNET_OK == get_identity (wl_entry->id, &identity));
431 GNUNET_break (GNUNET_OK ==
432 GNUNET_CONTAINER_multipeermap_put (map, &identity, &identity,
433 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
434 DEBUG ("Setting %u ms latency to peer `%s'\n",
435 wl_entry->latency,
436 GNUNET_i2s (&identity));
437 GNUNET_TRANSPORT_manipulation_set (transport,
438 &identity,
439 &prop,
440 delay,
441 delay);
442 GNUNET_free (wl_entry);
443 }
444 bh = GNUNET_TRANSPORT_blacklist (c, &check_access, NULL);
445 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
446
447close_db:
448 GNUNET_break (SQLITE_OK == sqlite3_close (db));
449}
450
451
452/**
453 * The main function.
454 *
455 * @param argc number of arguments from the command line
456 * @param argv command line arguments
457 * @return 0 ok, 1 on error
458 */
459int
460main (int argc, char *const *argv)
461{
462 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
463 GNUNET_GETOPT_OPTION_END
464 };
465 int ret;
466
467 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
468 return 2;
469#ifdef SQLITE_CONFIG_MMAP_SIZE
470 (void) sqlite3_config (SQLITE_CONFIG_MMAP_SIZE, 512000, 256000000);
471#endif
472 ret =
473 (GNUNET_OK ==
474 GNUNET_PROGRAM_run (argc, argv, "testbed-underlay",
475 _
476 (
477 "Daemon to restrict underlay network in testbed deployments"),
478 options, &run, NULL)) ? 0 : 1;
479 GNUNET_free_nz ((void *) argv);
480 return ret;
481}
diff --git a/src/testbed/gnunet-helper-testbed-valgrind.patch b/src/testbed/gnunet-helper-testbed-valgrind.patch
deleted file mode 100644
index 1777c30d0..000000000
--- a/src/testbed/gnunet-helper-testbed-valgrind.patch
+++ /dev/null
@@ -1,21 +0,0 @@
1Index: gnunet-helper-testbed.c
2===================================================================
3--- gnunet-helper-testbed.c (revision 32320)
4+++ gnunet-helper-testbed.c (working copy)
5@@ -462,7 +462,15 @@
6 testbed =
7 GNUNET_OS_start_process (PIPE_CONTROL,
8 GNUNET_OS_INHERIT_STD_ERR /*verbose? */ , NULL,
9- NULL, binary, "gnunet-service-testbed", "-c",
10+ NULL, "valgrind",
11+ "valgrind",
12+ "--leak-check=full",
13+ "--show-reachable=yes",
14+ "--suppressions=$HOME/gnunet/src/util/util.supp",
15+ "--suppressions=$HOME/gnunet/src/testbed/misc.supp",
16+ "--suppressions=$HOME/gnunet/src/testbed/valgrind-zlib.supp",
17+ "--suppressions=$HOME/gnunet/src/testbed/x64_misc.supp",
18+ binary, "-c",
19 config, NULL);
20 GNUNET_free (binary);
21 GNUNET_free (config);
diff --git a/src/testbed/gnunet-helper-testbed.c b/src/testbed/gnunet-helper-testbed.c
deleted file mode 100644
index 938e50448..000000000
--- a/src/testbed/gnunet-helper-testbed.c
+++ /dev/null
@@ -1,613 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-helper-testbed.c
23 * @brief Helper binary that is started from a remote controller to start
24 * gnunet-service-testbed. This binary also receives configuration
25 * from the remove controller which is put in a temporary location
26 * with ports and paths fixed so that gnunet-service-testbed runs
27 * without any hurdles.
28 *
29 * This helper monitors for three termination events. They are: (1)The
30 * stdin of the helper is closed for reading; (2)the helper received
31 * SIGTERM/SIGINT; (3)the testbed crashed. In case of events 1 and 2
32 * the helper kills the testbed service. When testbed crashed (event
33 * 3), the helper should send a SIGTERM to its own process group; this
34 * behaviour will help terminate any child processes (peers) testbed
35 * has started and prevents them from leaking and running forever.
36 *
37 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
38 */
39
40
41#include "platform.h"
42#include "gnunet_util_lib.h"
43#include "gnunet_testing_lib.h"
44#include "gnunet_testbed_service.h"
45#include "testbed_helper.h"
46#include "testbed_api.h"
47#include <zlib.h>
48
49/**
50 * Generic logging shortcut
51 */
52#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
53
54/**
55 * Debug logging shorthand
56 */
57#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
58
59
60/**
61 * Context for a single write on a chunk of memory
62 */
63struct WriteContext
64{
65 /**
66 * The data to write
67 */
68 void *data;
69
70 /**
71 * The length of the data
72 */
73 size_t length;
74
75 /**
76 * The current position from where the write operation should begin
77 */
78 size_t pos;
79};
80
81
82/**
83 * Handle to the testing system
84 */
85static struct GNUNET_TESTING_System *test_system;
86
87/**
88 * Our message stream tokenizer
89 */
90struct GNUNET_MessageStreamTokenizer *tokenizer;
91
92/**
93 * Disk handle from stdin
94 */
95static struct GNUNET_DISK_FileHandle *stdin_fd;
96
97/**
98 * Disk handle for stdout
99 */
100static struct GNUNET_DISK_FileHandle *stdout_fd;
101
102/**
103 * The process handle to the testbed service
104 */
105static struct GNUNET_OS_Process *testbed;
106
107/**
108 * Pipe used to communicate shutdown via signal.
109 */
110static struct GNUNET_DISK_PipeHandle *sigpipe;
111
112/**
113 * Task identifier for the read task
114 */
115static struct GNUNET_SCHEDULER_Task *read_task_id;
116
117/**
118 * Task identifier for the write task
119 */
120static struct GNUNET_SCHEDULER_Task *write_task_id;
121
122/**
123 * Task to kill the child
124 */
125static struct GNUNET_SCHEDULER_Task *child_death_task_id;
126
127/**
128 * Are we done reading messages from stdin?
129 */
130static int done_reading;
131
132/**
133 * Result to return in case we fail
134 */
135static int status;
136
137
138/**
139 * Task to shut down cleanly
140 *
141 * @param cls NULL
142 */
143static void
144shutdown_task (void *cls)
145{
146 LOG_DEBUG ("Shutting down\n");
147 if (NULL != testbed)
148 {
149 LOG_DEBUG ("Killing testbed\n");
150 GNUNET_break (0 == GNUNET_OS_process_kill (testbed, GNUNET_TERM_SIG));
151 }
152 if (NULL != read_task_id)
153 {
154 GNUNET_SCHEDULER_cancel (read_task_id);
155 read_task_id = NULL;
156 }
157 if (NULL != write_task_id)
158 {
159 struct WriteContext *wc;
160
161 wc = GNUNET_SCHEDULER_cancel (write_task_id);
162 write_task_id = NULL;
163 GNUNET_free (wc->data);
164 GNUNET_free (wc);
165 }
166 if (NULL != child_death_task_id)
167 {
168 GNUNET_SCHEDULER_cancel (child_death_task_id);
169 child_death_task_id = NULL;
170 }
171 if (NULL != stdin_fd)
172 (void) GNUNET_DISK_file_close (stdin_fd);
173 if (NULL != stdout_fd)
174 (void) GNUNET_DISK_file_close (stdout_fd);
175 GNUNET_MST_destroy (tokenizer);
176 tokenizer = NULL;
177 if (NULL != testbed)
178 {
179 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (testbed));
180 GNUNET_OS_process_destroy (testbed);
181 testbed = NULL;
182 }
183 if (NULL != test_system)
184 {
185 GNUNET_TESTING_system_destroy (test_system, GNUNET_YES);
186 test_system = NULL;
187 }
188}
189
190
191/**
192 * Task to write to the standard out
193 *
194 * @param cls the WriteContext
195 */
196static void
197write_task (void *cls)
198{
199 struct WriteContext *wc = cls;
200 ssize_t bytes_wrote;
201
202 GNUNET_assert (NULL != wc);
203 write_task_id = NULL;
204 bytes_wrote = GNUNET_DISK_file_write (stdout_fd,
205 wc->data + wc->pos,
206 wc->length - wc->pos);
207 if (GNUNET_SYSERR == bytes_wrote)
208 {
209 LOG (GNUNET_ERROR_TYPE_WARNING, "Cannot reply back configuration\n");
210 GNUNET_free (wc->data);
211 GNUNET_free (wc);
212 return;
213 }
214 wc->pos += bytes_wrote;
215 if (wc->pos == wc->length)
216 {
217 GNUNET_free (wc->data);
218 GNUNET_free (wc);
219 return;
220 }
221 write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
222 stdout_fd,
223 &write_task,
224 wc);
225}
226
227
228/**
229 * Task triggered whenever we receive a SIGCHLD (child
230 * process died).
231 *
232 * @param cls closure, NULL if we need to self-restart
233 */
234static void
235child_death_task (void *cls)
236{
237 const struct GNUNET_DISK_FileHandle *pr;
238 char c[16];
239 enum GNUNET_OS_ProcessStatusType type;
240 unsigned long code;
241 int ret;
242
243 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
244 child_death_task_id = NULL;
245 /* consume the signal */
246 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof(c)));
247 LOG_DEBUG ("Got SIGCHLD\n");
248 if (NULL == testbed)
249 {
250 GNUNET_break (0);
251 return;
252 }
253 GNUNET_break (GNUNET_SYSERR !=
254 (ret = GNUNET_OS_process_status (testbed, &type, &code)));
255 if (GNUNET_NO != ret)
256 {
257 GNUNET_OS_process_destroy (testbed);
258 testbed = NULL;
259 /* Send SIGTERM to our process group */
260 if (0 != kill (0, GNUNET_TERM_SIG))
261 {
262 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "signal");
263 GNUNET_SCHEDULER_shutdown (); /* Couldn't send the signal, we shutdown frowning */
264 }
265 return;
266 }
267 LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n");
268 child_death_task_id =
269 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
270 pr,
271 &child_death_task,
272 NULL);
273}
274
275
276/**
277 * Functions with this signature are called whenever a
278 * complete message is received by the tokenizer.
279 *
280 * Do not call #GNUNET_mst_destroy() in this callback
281 *
282 * @param cls identification of the client
283 * @param message the actual message
284 * @return #GNUNET_OK on success,
285 * #GNUNET_NO to stop further processing (no error)
286 * #GNUNET_SYSERR to stop further processing with error
287 */
288static int
289tokenizer_cb (void *cls, const struct GNUNET_MessageHeader *message)
290{
291 const struct GNUNET_TESTBED_HelperInit *msg;
292 struct GNUNET_TESTBED_HelperReply *reply;
293 struct GNUNET_CONFIGURATION_Handle *cfg;
294 struct WriteContext *wc;
295 char *binary;
296 char *trusted_ip;
297 char *hostname;
298 char *config;
299 char *xconfig;
300 char *evstr;
301 // char *str;
302 size_t config_size;
303 uLongf ul_config_size;
304 size_t xconfig_size;
305 uint16_t trusted_ip_size;
306 uint16_t hostname_size;
307 uint16_t msize;
308
309 msize = ntohs (message->size);
310 if ((sizeof(struct GNUNET_TESTBED_HelperInit) >= msize) ||
311 (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT != ntohs (message->type)))
312 {
313 LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
314 goto error;
315 }
316 msg = (const struct GNUNET_TESTBED_HelperInit *) message;
317 trusted_ip_size = ntohs (msg->trusted_ip_size);
318 trusted_ip = (char *) &msg[1];
319 if ('\0' != trusted_ip[trusted_ip_size])
320 {
321 LOG (GNUNET_ERROR_TYPE_WARNING, "Trusted IP cannot be empty -- exiting\n");
322 goto error;
323 }
324 hostname_size = ntohs (msg->hostname_size);
325 if ((sizeof(struct GNUNET_TESTBED_HelperInit) + trusted_ip_size + 1
326 + hostname_size) >= msize)
327 {
328 GNUNET_break (0);
329 LOG (GNUNET_ERROR_TYPE_WARNING, "Received unexpected message -- exiting\n");
330 goto error;
331 }
332 ul_config_size = (uLongf) ntohs (msg->config_size);
333 config = GNUNET_malloc (ul_config_size);
334 xconfig_size = msize - (trusted_ip_size + 1 + hostname_size
335 + sizeof(struct GNUNET_TESTBED_HelperInit));
336 int ret = uncompress ((Bytef *) config,
337 &ul_config_size,
338 (const Bytef *) (trusted_ip + trusted_ip_size + 1
339 + hostname_size),
340 (uLongf) xconfig_size);
341 if (Z_OK != ret)
342 {
343 switch (ret)
344 {
345 case Z_MEM_ERROR:
346 LOG (GNUNET_ERROR_TYPE_ERROR, "Not enough memory for decompression\n");
347 break;
348
349 case Z_BUF_ERROR:
350 LOG (GNUNET_ERROR_TYPE_ERROR, "Output buffer too small\n");
351 break;
352
353 case Z_DATA_ERROR:
354 LOG (GNUNET_ERROR_TYPE_ERROR, "Data corrupted/incomplete\n");
355 break;
356
357 default:
358 GNUNET_break (0);
359 }
360 LOG (GNUNET_ERROR_TYPE_ERROR,
361 "Error while uncompressing config -- exiting\n");
362 GNUNET_free (config);
363 goto error;
364 }
365 cfg = GNUNET_CONFIGURATION_create ();
366 if (GNUNET_OK !=
367 GNUNET_CONFIGURATION_deserialize (cfg, config, ul_config_size, NULL))
368 {
369 LOG (GNUNET_ERROR_TYPE_ERROR, "Unable to deserialize config -- exiting\n");
370 GNUNET_free (config);
371 goto error;
372 }
373 GNUNET_free (config);
374 hostname = NULL;
375 if (0 != hostname_size)
376 {
377 hostname = GNUNET_malloc (hostname_size + 1);
378 GNUNET_strlcpy (hostname,
379 ((char *) &msg[1]) + trusted_ip_size + 1,
380 hostname_size + 1);
381 }
382 /* unset GNUNET_TESTING_PREFIX if present as it is more relevant for testbed */
383 evstr = getenv (GNUNET_TESTING_PREFIX);
384 if (NULL != evstr)
385 {
386 /* unsetting the variable will invalidate the pointer! */
387 evstr = GNUNET_strdup (evstr);
388 GNUNET_break (0 == unsetenv (GNUNET_TESTING_PREFIX));
389 }
390 test_system =
391 GNUNET_TESTING_system_create ("testbed-helper", trusted_ip, hostname, NULL);
392 if (NULL != evstr)
393 {
394 char *evar;
395
396 GNUNET_asprintf (&evar, GNUNET_TESTING_PREFIX "=%s", evstr);
397 GNUNET_assert (0 == putenv (evar)); /* consumes 'evar',
398 see putenv(): becomes part of environment! */
399 GNUNET_free (evstr);
400 evstr = NULL;
401 }
402 GNUNET_free (hostname);
403 hostname = NULL;
404 GNUNET_assert (NULL != test_system);
405 GNUNET_assert (GNUNET_OK ==
406 GNUNET_TESTING_configuration_create (test_system, cfg));
407 GNUNET_assert (GNUNET_OK ==
408 GNUNET_CONFIGURATION_get_value_filename (cfg,
409 "PATHS",
410 "DEFAULTCONFIG",
411 &config));
412 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config))
413 {
414 LOG (GNUNET_ERROR_TYPE_WARNING,
415 "Unable to write config file: %s -- exiting\n",
416 config);
417 GNUNET_CONFIGURATION_destroy (cfg);
418 GNUNET_free (config);
419 goto error;
420 }
421 LOG_DEBUG ("Staring testbed with config: %s\n", config);
422 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-testbed");
423 {
424 char *evar;
425
426 /* expose testbed configuration through env variable */
427 GNUNET_asprintf (&evar, "%s=%s", ENV_TESTBED_CONFIG, config);
428 GNUNET_assert (0 == putenv (evar)); /* consumes 'evar',
429 see putenv(): becomes part of environment! */
430 evstr = NULL;
431 }
432 testbed = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR /*verbose? */,
433 NULL,
434 NULL,
435 NULL,
436 binary,
437 "gnunet-service-testbed",
438 "-c",
439 config,
440 NULL);
441 GNUNET_free (binary);
442 GNUNET_free (config);
443 if (NULL == testbed)
444 {
445 LOG (GNUNET_ERROR_TYPE_WARNING,
446 "Error starting gnunet-service-testbed -- exiting\n");
447 GNUNET_CONFIGURATION_destroy (cfg);
448 goto error;
449 }
450 done_reading = GNUNET_YES;
451 config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
452 GNUNET_CONFIGURATION_destroy (cfg);
453 cfg = NULL;
454 xconfig_size =
455 GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
456 GNUNET_free (config);
457 wc = GNUNET_new (struct WriteContext);
458 wc->length = xconfig_size + sizeof(struct GNUNET_TESTBED_HelperReply);
459 reply = GNUNET_realloc (xconfig, wc->length);
460 memmove (&reply[1], reply, xconfig_size);
461 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY);
462 reply->header.size = htons ((uint16_t) wc->length);
463 reply->config_size = htons ((uint16_t) config_size);
464 wc->data = reply;
465 write_task_id = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
466 stdout_fd,
467 &write_task,
468 wc);
469 child_death_task_id = GNUNET_SCHEDULER_add_read_file (
470 GNUNET_TIME_UNIT_FOREVER_REL,
471 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
472 &child_death_task,
473 NULL);
474 return GNUNET_OK;
475
476error:
477 status = GNUNET_SYSERR;
478 GNUNET_SCHEDULER_shutdown ();
479 return GNUNET_SYSERR;
480}
481
482
483/**
484 * Task to read from stdin
485 *
486 * @param cls NULL
487 */
488static void
489read_task (void *cls)
490{
491 char buf[GNUNET_MAX_MESSAGE_SIZE];
492 ssize_t sread;
493
494 read_task_id = NULL;
495 sread = GNUNET_DISK_file_read (stdin_fd, buf, sizeof(buf));
496 if ((GNUNET_SYSERR == sread) || (0 == sread))
497 {
498 LOG_DEBUG ("STDIN closed\n");
499 GNUNET_SCHEDULER_shutdown ();
500 return;
501 }
502 if (GNUNET_YES == done_reading)
503 {
504 /* didn't expect any more data! */
505 GNUNET_break_op (0);
506 GNUNET_SCHEDULER_shutdown ();
507 return;
508 }
509 LOG_DEBUG ("Read %u bytes\n", (unsigned int) sread);
510 /* FIXME: could introduce a GNUNET_MST_read2 to read
511 directly from 'stdin_fd' and save a memcpy() here */
512 if (GNUNET_OK !=
513 GNUNET_MST_from_buffer (tokenizer, buf, sread, GNUNET_NO, GNUNET_NO))
514 {
515 GNUNET_break (0);
516 GNUNET_SCHEDULER_shutdown ();
517 return;
518 }
519 read_task_id /* No timeout while reading */
520 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
521 stdin_fd,
522 &read_task,
523 NULL);
524}
525
526
527/**
528 * Main function that will be run.
529 *
530 * @param cls closure
531 * @param args remaining command-line arguments
532 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
533 * @param cfg configuration
534 */
535static void
536run (void *cls,
537 char *const *args,
538 const char *cfgfile,
539 const struct GNUNET_CONFIGURATION_Handle *cfg)
540{
541 LOG_DEBUG ("Starting testbed helper...\n");
542 tokenizer = GNUNET_MST_create (&tokenizer_cb, NULL);
543 stdin_fd = GNUNET_DISK_get_handle_from_native (stdin);
544 stdout_fd = GNUNET_DISK_get_handle_from_native (stdout);
545 read_task_id = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
546 stdin_fd,
547 &read_task,
548 NULL);
549 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
550}
551
552
553/**
554 * Signal handler called for SIGCHLD.
555 */
556static void
557sighandler_child_death ()
558{
559 static char c;
560 int old_errno; /* back-up errno */
561
562 old_errno = errno;
563 GNUNET_break (
564 1 ==
565 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (sigpipe,
566 GNUNET_DISK_PIPE_END_WRITE),
567 &c,
568 sizeof(c)));
569 errno = old_errno;
570}
571
572
573/**
574 * Main function
575 *
576 * @param argc the number of command line arguments
577 * @param argv command line arg array
578 * @return return code
579 */
580int
581main (int argc, char **argv)
582{
583 struct GNUNET_SIGNAL_Context *shc_chld;
584 struct GNUNET_GETOPT_CommandLineOption options[] =
585 { GNUNET_GETOPT_OPTION_END };
586 int ret;
587
588 status = GNUNET_OK;
589 if (NULL ==
590 (sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE)))
591 {
592 GNUNET_break (0);
593 return 1;
594 }
595 shc_chld =
596 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
597 ret = GNUNET_PROGRAM_run (argc,
598 argv,
599 "gnunet-helper-testbed",
600 "Helper for starting gnunet-service-testbed",
601 options,
602 &run,
603 NULL);
604 GNUNET_SIGNAL_handler_uninstall (shc_chld);
605 shc_chld = NULL;
606 GNUNET_DISK_pipe_close (sigpipe);
607 if (GNUNET_OK != ret)
608 return 1;
609 return (GNUNET_OK == status) ? 0 : 1;
610}
611
612
613/* end of gnunet-helper-testbed.c */
diff --git a/src/testbed/gnunet-service-test-barriers.c b/src/testbed/gnunet-service-test-barriers.c
deleted file mode 100644
index e10a28902..000000000
--- a/src/testbed/gnunet-service-test-barriers.c
+++ /dev/null
@@ -1,152 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-test-barriers.c
23 * @brief Daemon acting as a service for testing testbed barriers. It is
24 * started as a peer service and waits for a barrier to be crossed.
25 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_testbed_service.h"
31#include "test_testbed_api_barriers.h"
32
33/**
34 * logging short hand
35 */
36#define LOG(type, ...) \
37 GNUNET_log (type, __VA_ARGS__);
38
39/**
40 * Our barrier wait handle
41 */
42static struct GNUNET_TESTBED_BarrierWaitHandle *wh;
43
44static struct GNUNET_SCHEDULER_Task *tt;
45
46
47/**
48 * Dummy task callback to keep us running forever
49 *
50 * @param cls NULL
51 */
52static void
53do_shutdown (void *cls)
54{
55 if (NULL != wh)
56 {
57 GNUNET_TESTBED_barrier_wait_cancel (wh);
58 wh = NULL;
59 }
60 if (NULL != tt)
61 {
62 GNUNET_SCHEDULER_cancel (tt);
63 tt = NULL;
64 }
65}
66
67
68/**
69 * Functions of this type are to be given as acallback argument to
70 * GNUNET_TESTBED_barrier_wait(). The callback will be called when the barrier
71 * corresponding given in GNUNET_TESTBED_barrier_wait() is crossed or cancelled.
72 *
73 * @param cls NULL
74 * @param name the barrier name
75 * @param status #GNUNET_SYSERR in case of error while waiting for the barrier;
76 * #GNUNET_OK if the barrier is crossed
77 */
78static void
79barrier_wait_cb (void *cls,
80 const char *name,
81 int status)
82{
83 GNUNET_break (NULL == cls);
84 wh = NULL;
85 GNUNET_break (GNUNET_OK == status);
86}
87
88
89/**
90 * Task to wait for the barrier
91 *
92 * @param cls NULL
93 * @return
94 */
95static void
96do_wait (void *cls)
97{
98 tt = NULL;
99 wh = GNUNET_TESTBED_barrier_wait (TEST_BARRIER_NAME,
100 &barrier_wait_cb,
101 NULL);
102 GNUNET_break (NULL != wh);
103}
104
105
106/**
107 * Main run function.
108 *
109 * @param cls NULL
110 * @param args arguments passed to GNUNET_PROGRAM_run
111 * @param cfgfile the path to configuration file
112 * @param config the configuration file handle
113 */
114static void
115run (void *cls,
116 char *const *args,
117 const char *cfgfile,
118 const struct GNUNET_CONFIGURATION_Handle *config)
119{
120 unsigned int rsec;
121
122 rsec = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
123 10);
124 tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
125 GNUNET_TIME_UNIT_SECONDS,
126 rsec),
127 &do_wait,
128 NULL);
129 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
130}
131
132
133/**
134 * Main
135 */
136int
137main (int argc, char **argv)
138{
139 struct GNUNET_GETOPT_CommandLineOption options[] = {
140 GNUNET_GETOPT_OPTION_END
141 };
142 int ret;
143
144 ret =
145 GNUNET_PROGRAM_run (argc, argv,
146 "test-barriers",
147 "nohelp",
148 options,
149 &run,
150 NULL);
151 return ret;
152}
diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c
deleted file mode 100644
index 1e6e02294..000000000
--- a/src/testbed/gnunet-service-testbed.c
+++ /dev/null
@@ -1,981 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed.c
23 * @brief implementation of the TESTBED service
24 * @author Sree Harsha Totakura
25 */
26
27#include "platform.h"
28#include "gnunet-service-testbed.h"
29#include "gnunet-service-testbed_barriers.h"
30#include "gnunet-service-testbed_connectionpool.h"
31
32/***********/
33/* Globals */
34/***********/
35
36/**
37 * Our configuration
38 */
39struct GNUNET_CONFIGURATION_Handle *GST_config;
40
41/**
42 * The master context; generated with the first INIT message
43 */
44struct Context *GST_context;
45
46/**
47 * Array of hosts
48 */
49struct GNUNET_TESTBED_Host **GST_host_list;
50
51/**
52 * DLL head for forwarded operation contexts
53 */
54struct ForwardedOperationContext *fopcq_head;
55
56/**
57 * DLL tail for forwarded operation contexts
58 */
59struct ForwardedOperationContext *fopcq_tail;
60
61/**
62 * Operation queue for open file descriptors
63 */
64struct OperationQueue *GST_opq_openfds;
65
66/**
67 * Timeout for operations which may take some time
68 */
69struct GNUNET_TIME_Relative GST_timeout;
70
71/**
72 * The size of the host list
73 */
74unsigned int GST_host_list_size;
75
76/**
77 * The size of the peer list
78 */
79unsigned int GST_peer_list_size;
80
81
82/***********************************/
83/* Local definitions and variables */
84/***********************************/
85
86/**
87 * Our hostname; we give this to all the peers we start
88 */
89static char *hostname;
90
91
92/**
93 * Function to add a host to the current list of known hosts
94 *
95 * @param host the host to add
96 * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure due to host-id
97 * already in use
98 */
99static int
100host_list_add (struct GNUNET_TESTBED_Host *host)
101{
102 uint32_t host_id;
103
104 host_id = GNUNET_TESTBED_host_get_id_ (host);
105 if (GST_host_list_size <= host_id)
106 GST_array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
107 if (NULL != GST_host_list[host_id])
108 {
109 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
110 return GNUNET_SYSERR;
111 }
112 GST_host_list[host_id] = host;
113 return GNUNET_OK;
114}
115
116
117/**
118 * Send operation failure message to client
119 *
120 * @param client the client to which the failure message has to be sent to
121 * @param operation_id the id of the failed operation
122 * @param emsg the error message; can be NULL
123 */
124void
125GST_send_operation_fail_msg (struct GNUNET_SERVICE_Client *client,
126 uint64_t operation_id,
127 const char *emsg)
128{
129 struct GNUNET_MQ_Envelope *env;
130 struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
131 uint16_t emsg_len;
132
133 emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
134 env = GNUNET_MQ_msg_extra (msg,
135 emsg_len,
136 GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
137 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
138 msg->operation_id = GNUNET_htonll (operation_id);
139 GNUNET_memcpy (&msg[1],
140 emsg,
141 emsg_len);
142 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
143 env);
144}
145
146
147/**
148 * Function to send generic operation success message to given client
149 *
150 * @param client the client to send the message to
151 * @param operation_id the id of the operation which was successful
152 */
153void
154GST_send_operation_success_msg (struct GNUNET_SERVICE_Client *client,
155 uint64_t operation_id)
156{
157 struct GNUNET_MQ_Envelope *env;
158 struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
159
160 env = GNUNET_MQ_msg (msg,
161 GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
162 msg->operation_id = GNUNET_htonll (operation_id);
163 msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
164 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
165 env);
166}
167
168
169/**
170 * Callback which will be called after a host registration succeeded or failed
171 *
172 * @param cls the handle to the slave at which the registration is completed
173 * @param emsg the error message; NULL if host registration is successful
174 */
175static void
176hr_completion (void *cls,
177 const char *emsg);
178
179
180/**
181 * Attempts to register the next host in the host registration queue
182 *
183 * @param slave the slave controller whose host registration queue is checked
184 * for host registrations
185 */
186static void
187register_next_host (struct Slave *slave)
188{
189 struct HostRegistration *hr;
190
191 hr = slave->hr_dll_head;
192 GNUNET_assert (NULL != hr);
193 GNUNET_assert (NULL == slave->rhandle);
194 LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
195 GNUNET_TESTBED_host_get_id_ (hr->host),
196 GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
197 slave->rhandle
198 = GNUNET_TESTBED_register_host (slave->controller,
199 hr->host,
200 hr_completion,
201 slave);
202}
203
204
205/**
206 * Callback which will be called to after a host registration succeeded or failed
207 *
208 * @param cls the handle to the slave at which the registration is completed
209 * @param emsg the error message; NULL if host registration is successful
210 */
211static void
212hr_completion (void *cls,
213 const char *emsg)
214{
215 struct Slave *slave = cls;
216 struct HostRegistration *hr;
217
218 slave->rhandle = NULL;
219 hr = slave->hr_dll_head;
220 GNUNET_assert (NULL != hr);
221 LOG (GNUNET_ERROR_TYPE_DEBUG,
222 "Registering host %u at %u successful\n",
223 GNUNET_TESTBED_host_get_id_ (hr->host),
224 GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
225 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head,
226 slave->hr_dll_tail,
227 hr);
228 if (NULL != hr->cb)
229 hr->cb (hr->cb_cls,
230 emsg);
231 GNUNET_free (hr);
232 if (NULL != slave->hr_dll_head)
233 register_next_host (slave);
234}
235
236
237/**
238 * Adds a host registration's request to a slave's registration queue
239 *
240 * @param slave the slave controller at which the given host has to be
241 * registered
242 * @param cb the host registration completion callback
243 * @param cb_cls the closure for the host registration completion callback
244 * @param host the host which has to be registered
245 */
246void
247GST_queue_host_registration (struct Slave *slave,
248 GNUNET_TESTBED_HostRegistrationCompletion cb,
249 void *cb_cls,
250 struct GNUNET_TESTBED_Host *host)
251{
252 struct HostRegistration *hr;
253 int call_register;
254
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "Queueing host registration for host %u at %u\n",
257 GNUNET_TESTBED_host_get_id_ (host),
258 GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
259 hr = GNUNET_new (struct HostRegistration);
260 hr->cb = cb;
261 hr->cb_cls = cb_cls;
262 hr->host = host;
263 call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
264 GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head,
265 slave->hr_dll_tail,
266 hr);
267 if (GNUNET_YES == call_register)
268 register_next_host (slave);
269}
270
271
272/**
273 * Callback to relay the reply msg of a forwarded operation back to the client
274 *
275 * @param cls ForwardedOperationContext
276 * @param msg the message to relay
277 */
278void
279GST_forwarded_operation_reply_relay (void *cls,
280 const struct GNUNET_MessageHeader *msg)
281{
282 struct ForwardedOperationContext *fopc = cls;
283 struct GNUNET_MQ_Envelope *env;
284
285 LOG_DEBUG ("Relaying message with type: %u, size: %u\n",
286 ntohs (msg->type),
287 ntohs (msg->size));
288 env = GNUNET_MQ_msg_copy (msg);
289 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (fopc->client),
290 env);
291 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
292 GNUNET_CONTAINER_DLL_remove (fopcq_head,
293 fopcq_tail,
294 fopc);
295 GNUNET_free (fopc);
296}
297
298
299void
300GST_forwarded_operation_timeout (void *cls)
301{
302 struct ForwardedOperationContext *fopc = cls;
303
304 fopc->timeout_task = NULL;
305 GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
306 LOG (GNUNET_ERROR_TYPE_DEBUG,
307 "A forwarded operation has timed out\n");
308 GST_send_operation_fail_msg (fopc->client,
309 fopc->operation_id,
310 "A forwarded operation has timed out");
311 GNUNET_CONTAINER_DLL_remove (fopcq_head,
312 fopcq_tail,
313 fopc);
314 GNUNET_free (fopc);
315}
316
317
318/**
319 * Parse service sharing specification line.
320 * Format is "[<service:share>] [<service:share>] ..."
321 *
322 * @param ss_str the spec string to be parsed
323 * @param cfg the configuration to use for shared services
324 * @return an array suitable to pass to GNUNET_TESTING_system_create(). NULL
325 * upon empty service sharing specification.
326 */
327static struct GNUNET_TESTING_SharedService *
328parse_shared_services (char *ss_str,
329 struct GNUNET_CONFIGURATION_Handle *cfg)
330{
331 struct GNUNET_TESTING_SharedService ss;
332 struct GNUNET_TESTING_SharedService *slist;
333 char service[256];
334 char *arg;
335 unsigned int n;
336
337#define GROW_SS \
338 do { \
339 GNUNET_array_grow (slist, n, n + 1); \
340 GNUNET_memcpy (&slist[n - 1], &ss, \
341 sizeof(struct GNUNET_TESTING_SharedService)); \
342 } while (0)
343
344 slist = NULL;
345 n = 0;
346 ss.cfg = cfg;
347 for (; NULL != (arg = strtok (ss_str, " ")); ss_str = NULL)
348 {
349 ss.service = NULL;
350 ss.share = 0;
351 if (2 != sscanf (arg, "%255[^:]:%u",
352 service,
353 &ss.share))
354 {
355 LOG (GNUNET_ERROR_TYPE_WARNING,
356 "Ignoring shared service spec: %s",
357 arg);
358 continue;
359 }
360 LOG_DEBUG ("Will be sharing %s service among %u peers\n",
361 service,
362 ss.share);
363 ss.service = GNUNET_strdup (service);
364 GROW_SS;
365 }
366 if (NULL != slist)
367 {
368 /* Add trailing NULL block */
369 (void) memset (&ss,
370 0,
371 sizeof(struct GNUNET_TESTING_SharedService));
372 GROW_SS;
373 }
374 return slist;
375#undef GROW_SS
376}
377
378
379/**
380 * Check #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
381 *
382 * @param cls identification of the client
383 * @param msg the actual message
384 * @return #GNUNET_OK if @a message is well-formed
385 */
386static int
387check_init (void *cls,
388 const struct GNUNET_TESTBED_InitMessage *msg)
389{
390 const char *controller_hostname;
391 uint16_t msize;
392
393 msize = ntohs (msg->header.size) - sizeof(struct GNUNET_TESTBED_InitMessage);
394 controller_hostname = (const char *) &msg[1];
395 if ('\0' != controller_hostname[msize - 1])
396 {
397 GNUNET_break (0);
398 return GNUNET_SYSERR;
399 }
400 return GNUNET_OK;
401}
402
403
404/**
405 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
406 *
407 * @param cls identification of the client
408 * @param msg the actual message
409 */
410static void
411handle_init (void *cls,
412 const struct GNUNET_TESTBED_InitMessage *msg)
413{
414 struct GNUNET_SERVICE_Client *client = cls;
415 struct GNUNET_TESTBED_Host *host;
416 const char *controller_hostname;
417 char *ss_str;
418 struct GNUNET_TESTING_SharedService *ss;
419 unsigned int cnt;
420
421 if (NULL != GST_context)
422 {
423 LOG_DEBUG ("We are being connected to laterally\n");
424 GNUNET_SERVICE_client_continue (client);
425 return;
426 }
427 controller_hostname = (const char *) &msg[1];
428 ss_str = NULL;
429 ss = NULL;
430 if (GNUNET_OK ==
431 GNUNET_CONFIGURATION_get_value_string (GST_config,
432 "TESTBED",
433 "SHARED_SERVICES",
434 &ss_str))
435 {
436 ss = parse_shared_services (ss_str,
437 GST_config);
438 GNUNET_free (ss_str);
439 ss_str = NULL;
440 }
441 GST_context = GNUNET_new (struct Context);
442 GST_context->client = client;
443 GST_context->host_id = ntohl (msg->host_id);
444 GST_context->master_ip = GNUNET_strdup (controller_hostname);
445 LOG_DEBUG ("Our IP: %s\n",
446 GST_context->master_ip);
447 GST_context->system
448 = GNUNET_TESTING_system_create ("testbed",
449 GST_context->master_ip,
450 hostname,
451 ss);
452 if (NULL != ss)
453 {
454 for (cnt = 0; NULL != ss[cnt].service; cnt++)
455 {
456 ss_str = (char *) ss[cnt].service;
457 GNUNET_free (ss_str);
458 }
459 GNUNET_free (ss);
460 ss = NULL;
461 }
462 host =
463 GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
464 GST_context->master_ip,
465 NULL,
466 GST_config,
467 0);
468 host_list_add (host);
469 LOG_DEBUG ("Created master context with host ID: %u\n",
470 GST_context->host_id);
471 GNUNET_SERVICE_client_continue (client);
472}
473
474
475/**
476 * Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
477 *
478 * @param cls identification of the client
479 * @param msg the actual message
480 * @return #GNUNET_OK if @a message is well-formed
481 */
482static int
483check_add_host (void *cls,
484 const struct GNUNET_TESTBED_AddHostMessage *msg)
485{
486 uint16_t username_length;
487 uint16_t hostname_length;
488 uint16_t msize;
489
490 msize = ntohs (msg->header.size) - sizeof(struct
491 GNUNET_TESTBED_AddHostMessage);
492 username_length = ntohs (msg->username_length);
493 hostname_length = ntohs (msg->hostname_length);
494 /* msg must contain hostname */
495 if ((msize <= username_length) ||
496 (0 == hostname_length))
497 {
498 GNUNET_break (0);
499 return GNUNET_SYSERR;
500 }
501 /* msg must contain configuration */
502 if (msize <= username_length + hostname_length)
503 {
504 GNUNET_break (0);
505 return GNUNET_SYSERR;
506 }
507 return GNUNET_OK;
508}
509
510
511/**
512 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
513 *
514 * @param cls identification of the client
515 * @param msg the actual message
516 */
517static void
518handle_add_host (void *cls,
519 const struct GNUNET_TESTBED_AddHostMessage *msg)
520{
521 struct GNUNET_SERVICE_Client *client = cls;
522 struct GNUNET_TESTBED_Host *host;
523 struct GNUNET_TESTBED_HostConfirmedMessage *reply;
524 struct GNUNET_CONFIGURATION_Handle *host_cfg;
525 char *username;
526 char *hostname;
527 char *emsg;
528 const void *ptr;
529 uint32_t host_id;
530 uint16_t username_length;
531 uint16_t hostname_length;
532 struct GNUNET_MQ_Envelope *env;
533
534 username_length = ntohs (msg->username_length);
535 hostname_length = ntohs (msg->hostname_length);
536 username = NULL;
537 hostname = NULL;
538 ptr = &msg[1];
539 if (0 != username_length)
540 {
541 username = GNUNET_malloc (username_length + 1);
542 GNUNET_strlcpy (username, ptr, username_length + 1);
543 ptr += username_length;
544 }
545 hostname = GNUNET_malloc (hostname_length + 1);
546 GNUNET_strlcpy (hostname, ptr, hostname_length + 1);
547 if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (&msg->header)))
548 {
549 GNUNET_free (username);
550 GNUNET_free (hostname);
551 GNUNET_break_op (0);
552 GNUNET_SERVICE_client_drop (client);
553 return;
554 }
555 host_id = ntohl (msg->host_id);
556 LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
557 LOG_DEBUG ("-------host id: %u\n", host_id);
558 LOG_DEBUG ("-------hostname: %s\n", hostname);
559 if (NULL != username)
560 LOG_DEBUG ("-------username: %s\n", username);
561 else
562 LOG_DEBUG ("-------username: <not given>\n");
563 LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
564 host = GNUNET_TESTBED_host_create_with_id (host_id,
565 hostname,
566 username,
567 host_cfg,
568 ntohs (msg->ssh_port));
569 GNUNET_free (username);
570 GNUNET_free (hostname);
571 GNUNET_CONFIGURATION_destroy (host_cfg);
572 if (NULL == host)
573 {
574 GNUNET_break_op (0);
575 GNUNET_SERVICE_client_drop (client);
576 return;
577 }
578 if (GNUNET_OK != host_list_add (host))
579 {
580 /* We are unable to add a host */
581 emsg = "A host exists with given host-id";
582 LOG_DEBUG ("%s: %u",
583 emsg,
584 host_id);
585 GNUNET_TESTBED_host_destroy (host);
586 env = GNUNET_MQ_msg_extra (reply,
587 strlen (emsg) + 1,
588 GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
589 GNUNET_memcpy (&reply[1],
590 emsg,
591 strlen (emsg) + 1);
592 }
593 else
594 {
595 LOG_DEBUG ("Added host %u at %u\n",
596 host_id,
597 GST_context->host_id);
598 env = GNUNET_MQ_msg (reply,
599 GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
600 }
601 reply->host_id = htonl (host_id);
602 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
603 env);
604 GNUNET_SERVICE_client_continue (client);
605}
606
607
608/**
609 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
610 *
611 * @param cls identification of the client
612 * @param msg the actual message
613 */
614static void
615handle_slave_get_config (void *cls,
616 const struct
617 GNUNET_TESTBED_SlaveGetConfigurationMessage *msg)
618{
619 struct GNUNET_SERVICE_Client *client = cls;
620 struct Slave *slave;
621 struct GNUNET_TESTBED_SlaveConfiguration *reply;
622 const struct GNUNET_CONFIGURATION_Handle *cfg;
623 struct GNUNET_MQ_Envelope *env;
624 char *config;
625 char *xconfig;
626 size_t config_size;
627 size_t xconfig_size;
628 uint64_t op_id;
629 uint32_t slave_id;
630
631 slave_id = ntohl (msg->slave_id);
632 op_id = GNUNET_ntohll (msg->operation_id);
633 if ((GST_slave_list_size <= slave_id) ||
634 (NULL == GST_slave_list[slave_id]))
635 {
636 /* FIXME: Add forwardings for this type of message here.. */
637 GST_send_operation_fail_msg (client,
638 op_id,
639 "Slave not found");
640 GNUNET_SERVICE_client_continue (client);
641 return;
642 }
643 slave = GST_slave_list[slave_id];
644 GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (
645 GST_host_list[slave->host_id])));
646 config = GNUNET_CONFIGURATION_serialize (cfg,
647 &config_size);
648 /* FIXME: maybe we want to transmit the delta to the default here? */
649 xconfig_size = GNUNET_TESTBED_compress_config_ (config,
650 config_size,
651 &xconfig);
652 GNUNET_free (config);
653 GNUNET_assert (xconfig_size + sizeof(struct
654 GNUNET_TESTBED_SlaveConfiguration) <=
655 UINT16_MAX);
656 GNUNET_assert (xconfig_size <= UINT16_MAX);
657 env = GNUNET_MQ_msg_extra (reply,
658 xconfig_size,
659 GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
660 reply->slave_id = msg->slave_id;
661 reply->operation_id = msg->operation_id;
662 reply->config_size = htons ((uint16_t) config_size);
663 GNUNET_memcpy (&reply[1],
664 xconfig,
665 xconfig_size);
666 GNUNET_free (xconfig);
667 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
668 env);
669 GNUNET_SERVICE_client_continue (client);
670}
671
672
673/**
674 * Clears the forwarded operations queue
675 */
676void
677GST_clear_fopcq ()
678{
679 struct ForwardedOperationContext *fopc;
680
681 while (NULL != (fopc = fopcq_head))
682 {
683 GNUNET_CONTAINER_DLL_remove (fopcq_head,
684 fopcq_tail,
685 fopc);
686 GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
687 if (NULL != fopc->timeout_task)
688 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
689 switch (fopc->type)
690 {
691 case OP_PEER_CREATE:
692 GNUNET_free (fopc->cls);
693 break;
694
695 case OP_SHUTDOWN_PEERS:
696 {
697 struct HandlerContext_ShutdownPeers *hc = fopc->cls;
698
699 GNUNET_assert (0 < hc->nslaves);
700 hc->nslaves--;
701 if (0 == hc->nslaves)
702 GNUNET_free (hc);
703 }
704 break;
705
706 case OP_PEER_START:
707 case OP_PEER_STOP:
708 case OP_PEER_DESTROY:
709 case OP_PEER_INFO:
710 case OP_OVERLAY_CONNECT:
711 case OP_LINK_CONTROLLERS:
712 case OP_GET_SLAVE_CONFIG:
713 case OP_MANAGE_SERVICE:
714 case OP_PEER_RECONFIGURE:
715 break;
716
717 case OP_FORWARDED:
718 GNUNET_assert (0);
719 }
720 ;
721 GNUNET_free (fopc);
722 }
723}
724
725
726/**
727 * Task to clean up and shutdown nicely
728 *
729 * @param cls NULL
730 */
731static void
732shutdown_task (void *cls)
733{
734 uint32_t id;
735
736 LOG_DEBUG ("Shutting down testbed service\n");
737 /* cleanup any remaining forwarded operations */
738 GST_clear_fopcq ();
739 GST_free_lcf ();
740 GST_free_mctxq ();
741 GST_free_occq ();
742 GST_free_roccq ();
743 GST_free_nccq ();
744 GST_neighbour_list_clean ();
745 GST_free_prcq ();
746 /* Clear peer list */
747 GST_destroy_peers ();
748 /* Clear route list */
749 GST_route_list_clear ();
750 /* Clear GST_slave_list */
751 GST_slave_list_clear ();
752 /* Clear host list */
753 for (id = 0; id < GST_host_list_size; id++)
754 if (NULL != GST_host_list[id])
755 GNUNET_TESTBED_host_destroy (GST_host_list[id]);
756 GNUNET_free (GST_host_list);
757 if (NULL != GST_context)
758 {
759 GNUNET_free (GST_context->master_ip);
760 if (NULL != GST_context->system)
761 GNUNET_TESTING_system_destroy (GST_context->system,
762 GNUNET_YES);
763 GNUNET_free (GST_context);
764 GST_context = NULL;
765 }
766 GNUNET_free (hostname);
767 /* Free hello cache */
768 GST_cache_clear ();
769 GST_connection_pool_destroy ();
770 GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
771 GST_opq_openfds = NULL;
772 GST_stats_destroy ();
773 GST_barriers_destroy ();
774 GNUNET_CONFIGURATION_destroy (GST_config);
775}
776
777
778/**
779 * Callback for client connect
780 *
781 * @param cls NULL
782 * @param client the client which has disconnected
783 * @param mq queue for sending messages to @a client
784 * @return @a client
785 */
786static void *
787client_connect_cb (void *cls,
788 struct GNUNET_SERVICE_Client *client,
789 struct GNUNET_MQ_Handle *mq)
790{
791 return client;
792}
793
794
795/**
796 * Callback for client disconnect
797 *
798 * @param cls NULL
799 * @param client the client which has disconnected
800 * @param app_ctx should match @a client
801 */
802static void
803client_disconnect_cb (void *cls,
804 struct GNUNET_SERVICE_Client *client,
805 void *app_ctx)
806{
807 struct ForwardedOperationContext *fopc;
808 struct ForwardedOperationContext *fopcn;
809
810 GNUNET_assert (client == app_ctx);
811 GST_notify_client_disconnect_oc (client);
812 GST_link_notify_disconnect (client);
813 GST_notify_client_disconnect_peers (client);
814 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
815 {
816 fopcn = fopc->next;
817 if (fopc->client == client)
818 {
819 /* handle as if it were a timeout */
820 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
821 GST_forwarded_operation_timeout (fopc);
822 }
823 }
824 if (NULL == GST_context)
825 return;
826 if (client == GST_context->client)
827 {
828 LOG (GNUNET_ERROR_TYPE_DEBUG,
829 "Master client disconnected\n");
830 GST_context->client = NULL;
831 /* should not be needed as we're terminated by failure to read
832 * from stdin, but if stdin fails for some reason, this shouldn't
833 * hurt for now --- might need to revise this later if we ever
834 * decide that master connections might be temporarily down
835 * for some reason */// GNUNET_SCHEDULER_shutdown ();
836 }
837}
838
839
840/**
841 * Testbed setup
842 *
843 * @param cls closure
844 * @param cfg configuration to use
845 * @param service the initialized server
846 */
847static void
848testbed_run (void *cls,
849 const struct GNUNET_CONFIGURATION_Handle *cfg,
850 struct GNUNET_SERVICE_Handle *service)
851{
852 char *logfile;
853 unsigned long long num;
854
855 LOG_DEBUG ("Starting testbed\n");
856 if (GNUNET_OK ==
857 GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
858 &logfile))
859 {
860 GNUNET_break (GNUNET_OK ==
861 GNUNET_log_setup ("testbed",
862 "DEBUG",
863 logfile));
864 GNUNET_free (logfile);
865 }
866 GNUNET_assert (GNUNET_OK ==
867 GNUNET_CONFIGURATION_get_value_number (cfg,
868 "testbed",
869 "CACHE_SIZE",
870 &num));
871 GST_cache_init ((unsigned int) num);
872 GST_connection_pool_init ((unsigned int) num);
873 GNUNET_assert (GNUNET_OK ==
874 GNUNET_CONFIGURATION_get_value_number (cfg,
875 "testbed",
876 "MAX_OPEN_FDS",
877 &num));
878 GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ (
879 OPERATION_QUEUE_TYPE_FIXED,
880 (unsigned int) num);
881 GNUNET_assert (GNUNET_OK ==
882 GNUNET_CONFIGURATION_get_value_time (cfg,
883 "testbed",
884 "OPERATION_TIMEOUT",
885 &GST_timeout));
886 GNUNET_assert (GNUNET_OK ==
887 GNUNET_CONFIGURATION_get_value_string (cfg,
888 "testbed",
889 "HOSTNAME",
890 &hostname));
891 GST_config = GNUNET_CONFIGURATION_dup (cfg);
892 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
893 NULL);
894 LOG_DEBUG ("Testbed startup complete\n");
895 GST_stats_init (GST_config);
896 GST_barriers_init (GST_config);
897}
898
899
900/**
901 * Define "main" method using service macro.
902 */
903GNUNET_SERVICE_MAIN
904 ("testbed",
905 GNUNET_SERVICE_OPTION_NONE,
906 &testbed_run,
907 &client_connect_cb,
908 &client_disconnect_cb,
909 NULL,
910 GNUNET_MQ_hd_var_size (init,
911 GNUNET_MESSAGE_TYPE_TESTBED_INIT,
912 struct GNUNET_TESTBED_InitMessage,
913 NULL),
914 GNUNET_MQ_hd_var_size (add_host,
915 GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
916 struct GNUNET_TESTBED_AddHostMessage,
917 NULL),
918 GNUNET_MQ_hd_fixed_size (slave_get_config,
919 GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
920 struct GNUNET_TESTBED_SlaveGetConfigurationMessage,
921 NULL),
922 GNUNET_MQ_hd_fixed_size (link_controllers,
923 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
924 struct GNUNET_TESTBED_ControllerLinkRequest,
925 NULL),
926 GNUNET_MQ_hd_var_size (remote_overlay_connect,
927 GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT,
928 struct GNUNET_TESTBED_RemoteOverlayConnectMessage,
929 NULL),
930 GNUNET_MQ_hd_fixed_size (overlay_connect,
931 GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
932 struct GNUNET_TESTBED_OverlayConnectMessage,
933 NULL),
934 GNUNET_MQ_hd_var_size (peer_create,
935 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER,
936 struct GNUNET_TESTBED_PeerCreateMessage,
937 NULL),
938 GNUNET_MQ_hd_fixed_size (peer_destroy,
939 GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
940 struct GNUNET_TESTBED_PeerDestroyMessage,
941 NULL),
942 GNUNET_MQ_hd_fixed_size (peer_start,
943 GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
944 struct GNUNET_TESTBED_PeerStartMessage,
945 NULL),
946 GNUNET_MQ_hd_fixed_size (peer_stop,
947 GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
948 struct GNUNET_TESTBED_PeerStopMessage,
949 NULL),
950 GNUNET_MQ_hd_fixed_size (peer_get_config,
951 GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION,
952 struct GNUNET_TESTBED_PeerGetConfigurationMessage,
953 NULL),
954 GNUNET_MQ_hd_var_size (manage_peer_service,
955 GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE,
956 struct GNUNET_TESTBED_ManagePeerServiceMessage,
957 NULL),
958 GNUNET_MQ_hd_fixed_size (shutdown_peers,
959 GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
960 struct GNUNET_TESTBED_ShutdownPeersMessage,
961 NULL),
962 GNUNET_MQ_hd_var_size (peer_reconfigure,
963 GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER,
964 struct GNUNET_TESTBED_PeerReconfigureMessage,
965 NULL),
966 GNUNET_MQ_hd_var_size (barrier_init,
967 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT,
968 struct GNUNET_TESTBED_BarrierInit,
969 NULL),
970 GNUNET_MQ_hd_var_size (barrier_cancel,
971 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL,
972 struct GNUNET_TESTBED_BarrierCancel,
973 NULL),
974 GNUNET_MQ_hd_var_size (barrier_status,
975 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
976 struct GNUNET_TESTBED_BarrierStatusMsg,
977 NULL),
978 GNUNET_MQ_handler_end ());
979
980
981/* end of gnunet-service-testbed.c */
diff --git a/src/testbed/gnunet-service-testbed.h b/src/testbed/gnunet-service-testbed.h
deleted file mode 100644
index 67dfbf253..000000000
--- a/src/testbed/gnunet-service-testbed.h
+++ /dev/null
@@ -1,899 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed.h
23 * @brief data structures shared amongst components of TESTBED service
24 * @author Sree Harsha Totakura
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30#include "gnunet_transport_service.h"
31#include "gnunet_core_service.h"
32
33#include "testbed.h"
34#include "testbed_api.h"
35#include "testbed_api_operations.h"
36#include "testbed_api_hosts.h"
37#include "gnunet_testing_lib.h"
38#include "gnunet-service-testbed_links.h"
39
40
41/**
42 * Generic logging
43 */
44#define LOG(kind, ...) \
45 GNUNET_log (kind, __VA_ARGS__)
46
47/**
48 * Debug logging
49 */
50#define LOG_DEBUG(...) \
51 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
52
53/**
54 * By how much should the arrays lists grow
55 */
56#define LIST_GROW_STEP 10
57
58
59/**
60 * A routing entry
61 */
62struct Route
63{
64 /**
65 * destination host
66 */
67 uint32_t dest;
68
69 /**
70 * The destination host is reachable thru
71 */
72 uint32_t thru;
73};
74
75
76/**
77 * Context information for operations forwarded to subcontrollers
78 */
79struct ForwardedOperationContext
80{
81 /**
82 * The next pointer for DLL
83 */
84 struct ForwardedOperationContext *next;
85
86 /**
87 * The prev pointer for DLL
88 */
89 struct ForwardedOperationContext *prev;
90
91 /**
92 * The generated operation context
93 */
94 struct OperationContext *opc;
95
96 /**
97 * The client to which we have to reply
98 */
99 struct GNUNET_SERVICE_Client *client;
100
101 /**
102 * Closure pointer
103 */
104 void *cls;
105
106 /**
107 * Task ID for the timeout task
108 */
109 struct GNUNET_SCHEDULER_Task *timeout_task;
110
111 /**
112 * The id of the operation that has been forwarded
113 */
114 uint64_t operation_id;
115
116 /**
117 * The type of the operation which is forwarded
118 */
119 enum OperationType type;
120};
121
122
123/**
124 * A DLL of host registrations to be made
125 */
126struct HostRegistration
127{
128 /**
129 * next registration in the DLL
130 */
131 struct HostRegistration *next;
132
133 /**
134 * previous registration in the DLL
135 */
136 struct HostRegistration *prev;
137
138 /**
139 * The callback to call after this registration's status is available
140 */
141 GNUNET_TESTBED_HostRegistrationCompletion cb;
142
143 /**
144 * The closure for the above callback
145 */
146 void *cb_cls;
147
148 /**
149 * The host that has to be registered
150 */
151 struct GNUNET_TESTBED_Host *host;
152};
153
154
155/**
156 * Context information used while linking controllers
157 */
158struct LinkControllersContext
159{
160 /**
161 * The client which initiated the link controller operation
162 */
163 struct GNUNET_SERVICE_Client *client;
164
165 /**
166 * The ID of the operation
167 */
168 uint64_t operation_id;
169};
170
171
172/**
173 * A peer
174 */
175struct Peer
176{
177 union
178 {
179 struct
180 {
181 /**
182 * The peer handle from testing API
183 */
184 struct GNUNET_TESTING_Peer *peer;
185
186 /**
187 * The modified (by GNUNET_TESTING_peer_configure) configuration this
188 * peer is configured with
189 */
190 struct GNUNET_CONFIGURATION_Handle *cfg;
191
192 /**
193 * Is the peer running
194 */
195 int is_running;
196 } local;
197
198 struct
199 {
200 /**
201 * The slave this peer is started through
202 */
203 struct Slave *slave;
204
205 /**
206 * The id of the remote host this peer is running on
207 */
208 uint32_t remote_host_id;
209 } remote;
210 } details;
211
212 /**
213 * Is this peer locally created?
214 */
215 int is_remote;
216
217 /**
218 * Our local reference id for this peer
219 */
220 uint32_t id;
221
222 /**
223 * References to peers are using in forwarded overlay contexts and remote
224 * overlay connect contexts. A peer can only be destroyed after all such
225 * contexts are destroyed. For this, we maintain a reference counter. When we
226 * use a peer in any such context, we increment this counter. We decrement it
227 * when we are destroying these contexts
228 */
229 uint32_t reference_cnt;
230
231 /**
232 * While destroying a peer, due to the fact that there could be references to
233 * this peer, we delay the peer destroy to a further time. We do this by using
234 * this flag to destroy the peer while destroying a context in which this peer
235 * has been used. When the flag is set to 1 and reference_cnt = 0 we destroy
236 * the peer
237 */
238 uint32_t destroy_flag;
239};
240
241
242/**
243 * The main context information associated with the client which started us
244 */
245struct Context
246{
247 /**
248 * The client handle associated with this context
249 */
250 struct GNUNET_SERVICE_Client *client;
251
252 /**
253 * The network address of the master controller
254 */
255 char *master_ip;
256
257 /**
258 * The TESTING system handle for starting peers locally
259 */
260 struct GNUNET_TESTING_System *system;
261
262 /**
263 * Our host id according to this context
264 */
265 uint32_t host_id;
266};
267
268
269/**
270 * The structure for identifying a shared service
271 */
272struct SharedService
273{
274 /**
275 * The name of the shared service
276 */
277 char *name;
278
279 /**
280 * Number of shared peers per instance of the shared service
281 */
282 uint32_t num_shared;
283
284 /**
285 * Number of peers currently sharing the service
286 */
287 uint32_t num_sharing;
288};
289
290
291struct RegisteredHostContext;
292
293
294/**
295 * Context information to used during operations which forward the overlay
296 * connect message
297 */
298struct ForwardedOverlayConnectContext
299{
300 /**
301 * next ForwardedOverlayConnectContext in the DLL
302 */
303 struct ForwardedOverlayConnectContext *next;
304
305 /**
306 * previous ForwardedOverlayConnectContext in the DLL
307 */
308 struct ForwardedOverlayConnectContext *prev;
309
310 /**
311 * Which host does this FOCC belong to?
312 */
313 struct RegisteredHostContext *rhc;
314
315 /**
316 * A copy of the original overlay connect message
317 */
318 struct GNUNET_MessageHeader *orig_msg;
319
320 /**
321 * The client handle
322 */
323 struct GNUNET_SERVICE_Client *client;
324
325 /**
326 * The id of the operation which created this context information
327 */
328 uint64_t operation_id;
329
330 /**
331 * the id of peer 1
332 */
333 uint32_t peer1;
334
335 /**
336 * The id of peer 2
337 */
338 uint32_t peer2;
339
340 /**
341 * Id of the host where peer2 is running
342 */
343 uint32_t peer2_host_id;
344};
345
346
347/**
348 * This context information will be created for each host that is registered at
349 * slave controllers during overlay connects.
350 */
351struct RegisteredHostContext
352{
353 /**
354 * The host which is being registered
355 */
356 struct GNUNET_TESTBED_Host *reg_host;
357
358 /**
359 * The host of the controller which has to connect to the above rhost
360 */
361 struct GNUNET_TESTBED_Host *host;
362
363 /**
364 * Head of the ForwardedOverlayConnectContext DLL
365 */
366 struct ForwardedOverlayConnectContext *focc_dll_head;
367
368 /**
369 * Tail of the ForwardedOverlayConnectContext DLL
370 */
371 struct ForwardedOverlayConnectContext *focc_dll_tail;
372
373 /**
374 * Enumeration of states for this context
375 */
376 enum RHCState
377 {
378 /**
379 * The initial state
380 */
381 RHC_INIT = 0,
382
383 /**
384 * State where we attempt to do the overlay connection again
385 */
386 RHC_DONE
387 } state;
388};
389
390
391/**
392 * Context data for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
393 */
394struct HandlerContext_ShutdownPeers
395{
396 /**
397 * The number of slave we expect to hear from since we forwarded the
398 * #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
399 */
400 unsigned int nslaves;
401
402 /**
403 * Did we observe a timeout with respect to this operation at any of the
404 * slaves
405 */
406 int timeout;
407};
408
409
410/**
411 * Our configuration
412 */
413extern struct GNUNET_CONFIGURATION_Handle *GST_config;
414
415/**
416 * The master context; generated with the first INIT message
417 */
418extern struct Context *GST_context;
419
420/**
421 * DLL head for forwarded operation contexts
422 */
423extern struct ForwardedOperationContext *fopcq_head;
424
425/**
426 * DLL tail for forwarded operation contexts
427 */
428extern struct ForwardedOperationContext *fopcq_tail;
429
430/**
431 * A list of peers we know about
432 */
433extern struct Peer **GST_peer_list;
434
435/**
436 * Array of hosts
437 */
438extern struct GNUNET_TESTBED_Host **GST_host_list;
439
440/**
441 * Operation queue for open file descriptors
442 */
443extern struct OperationQueue *GST_opq_openfds;
444
445/**
446 * Timeout for operations which may take some time
447 */
448extern struct GNUNET_TIME_Relative GST_timeout;
449
450/**
451 * The size of the peer list
452 */
453extern unsigned int GST_peer_list_size;
454
455/**
456 * The current number of peers running locally under this controller
457 */
458extern unsigned int GST_num_local_peers;
459
460/**
461 * The size of the host list
462 */
463extern unsigned int GST_host_list_size;
464
465/**
466 * The directory where to store load statistics data
467 */
468extern char *GST_stats_dir;
469
470/**
471 * Condition to check if host id is valid
472 */
473#define VALID_HOST_ID(id) \
474 (((id) < GST_host_list_size) && (NULL != GST_host_list[id]))
475
476/**
477 * Condition to check if peer id is valid
478 */
479#define VALID_PEER_ID(id) \
480 (((id) < GST_peer_list_size) && (NULL != GST_peer_list[id]))
481
482
483/**
484 * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
485 * several times we call it only once. The array is also made to grow in steps
486 * of LIST_GROW_STEP.
487 *
488 * @param ptr the array pointer to grow
489 * @param size the size of array
490 * @param accommodate_size the size which the array has to accommdate; after
491 * this call the array will be big enough to accommdate sizes up to
492 * accommodate_size
493 */
494#define GST_array_grow_large_enough(ptr, size, accommodate_size) \
495 do \
496 { \
497 unsigned int growth_size; \
498 GNUNET_assert (size <= accommodate_size); \
499 growth_size = size; \
500 while (growth_size <= accommodate_size) \
501 growth_size += LIST_GROW_STEP; \
502 GNUNET_array_grow (ptr, size, growth_size); \
503 GNUNET_assert (size > accommodate_size); \
504 } while (0)
505
506
507/**
508 * Function to destroy a peer
509 *
510 * @param peer the peer structure to destroy
511 */
512void
513GST_destroy_peer (struct Peer *peer);
514
515
516/**
517 * Stops and destroys all peers
518 */
519void
520GST_destroy_peers (void);
521
522
523/**
524 * Finds the route with directly connected host as destination through which
525 * the destination host can be reached
526 *
527 * @param host_id the id of the destination host
528 * @return the route with directly connected destination host; NULL if no route
529 * is found
530 */
531struct Route *
532GST_find_dest_route (uint32_t host_id);
533
534
535/**
536 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT messages
537 *
538 * @param cls identification of the client
539 * @param msg the actual message
540 */
541void
542handle_overlay_connect (void *cls,
543 const struct GNUNET_TESTBED_OverlayConnectMessage *msg);
544
545
546/**
547 * Adds a host registration's request to a slave's registration queue
548 *
549 * @param slave the slave controller at which the given host has to be
550 * registered
551 * @param cb the host registration completion callback
552 * @param cb_cls the closure for the host registration completion callback
553 * @param host the host which has to be registered
554 */
555void
556GST_queue_host_registration (struct Slave *slave,
557 GNUNET_TESTBED_HostRegistrationCompletion cb,
558 void *cb_cls, struct GNUNET_TESTBED_Host *host);
559
560
561/**
562 * Callback to relay the reply msg of a forwarded operation back to the client
563 *
564 * @param cls ForwardedOperationContext
565 * @param msg the message to relay
566 */
567void
568GST_forwarded_operation_reply_relay (void *cls,
569 const struct GNUNET_MessageHeader *msg);
570
571
572/**
573 * Task to free resources when forwarded operation has been timed out.
574 *
575 * @param cls the ForwardedOperationContext
576 */
577void
578GST_forwarded_operation_timeout (void *cls);
579
580
581/**
582 * Clears the forwarded operations queue
583 */
584void
585GST_clear_fopcq (void);
586
587
588/**
589 * Send operation failure message to client
590 *
591 * @param client the client to which the failure message has to be sent to
592 * @param operation_id the id of the failed operation
593 * @param emsg the error message; can be NULL
594 */
595void
596GST_send_operation_fail_msg (struct GNUNET_SERVICE_Client *client,
597 uint64_t operation_id,
598 const char *emsg);
599
600
601/**
602 * Notify OC subsystem that @a client disconnected.
603 *
604 * @param client the client that disconnected
605 */
606void
607GST_notify_client_disconnect_oc (struct GNUNET_SERVICE_Client *client);
608
609
610/**
611 * Notify peers subsystem that @a client disconnected.
612 *
613 * @param client the client that disconnected
614 */
615void
616GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client);
617
618
619/**
620 * Function to send generic operation success message to given client
621 *
622 * @param client the client to send the message to
623 * @param operation_id the id of the operation which was successful
624 */
625void
626GST_send_operation_success_msg (struct GNUNET_SERVICE_Client *client,
627 uint64_t operation_id);
628
629
630/**
631 * Check #GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT messages
632 *
633 * @param cls identification of the client
634 * @param msg the actual message
635 * @return #GNUNET_OK if @a msg is well-formed
636 */
637int
638check_remote_overlay_connect (void *cls,
639 const struct
640 GNUNET_TESTBED_RemoteOverlayConnectMessage *msg);
641
642
643/**
644 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT messages
645 *
646 * @param cls identification of the client
647 * @param msg the actual message
648 */
649void
650handle_remote_overlay_connect (void *cls,
651 const struct
652 GNUNET_TESTBED_RemoteOverlayConnectMessage *msg);
653
654
655/**
656 * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
657 *
658 * @param cls identification of the client
659 * @param msg the actual message
660 * @return #GNUNET_OK if @a msg is well-formed
661 */
662int
663check_peer_create (void *cls,
664 const struct GNUNET_TESTBED_PeerCreateMessage *msg);
665
666
667/**
668 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
669 *
670 * @param cls identification of the client
671 * @param msg the actual message
672 */
673void
674handle_peer_create (void *cls,
675 const struct GNUNET_TESTBED_PeerCreateMessage *msg);
676
677
678/**
679 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
680 *
681 * @param cls identification of the client
682 * @param msg the actual message
683 */
684void
685handle_peer_destroy (void *cls,
686 const struct GNUNET_TESTBED_PeerDestroyMessage *msg);
687
688
689/**
690 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_START_PEER messages
691 *
692 * @param cls identification of the client
693 * @param msg the actual message
694 */
695void
696handle_peer_start (void *cls,
697 const struct GNUNET_TESTBED_PeerStartMessage *msg);
698
699
700/**
701 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
702 *
703 * @param cls identification of the client
704 * @param msg the actual message
705 */
706void
707handle_peer_stop (void *cls,
708 const struct GNUNET_TESTBED_PeerStopMessage *msg);
709
710
711/**
712 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
713 *
714 * @param cls identification of the client
715 * @param msg the actual message
716 */
717void
718handle_peer_get_config (void *cls,
719 const struct
720 GNUNET_TESTBED_PeerGetConfigurationMessage *msg);
721
722
723/**
724 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
725 *
726 * @param cls identification of the client
727 * @param msg the actual message
728 */
729void
730handle_shutdown_peers (void *cls,
731 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg);
732
733
734/**
735 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
736 *
737 * @param cls identification of client
738 * @param msg the actual message
739 * @return #GNUNET_OK if @a msg is well-formed
740 */
741int
742check_manage_peer_service (void *cls,
743 const struct
744 GNUNET_TESTBED_ManagePeerServiceMessage *msg);
745
746
747/**
748 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE messages
749 *
750 * @param cls identification of client
751 * @param msg the actual message
752 */
753void
754handle_manage_peer_service (void *cls,
755 const struct
756 GNUNET_TESTBED_ManagePeerServiceMessage *msg);
757
758
759/**
760 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
761 *
762 * @param cls identification of the client
763 * @param msg the actual message
764 * @return #GNUNET_OK if @a msg is well-formed
765 */
766int
767check_peer_reconfigure (void *cls,
768 const struct
769 GNUNET_TESTBED_PeerReconfigureMessage *msg);
770
771
772/**
773 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
774 * Should stop the peer asynchronously, destroy it and create it again with the
775 * new configuration.
776 *
777 * @param cls identification of the client
778 * @param msg the actual message
779 */
780void
781handle_peer_reconfigure (void *cls,
782 const struct
783 GNUNET_TESTBED_PeerReconfigureMessage *msg);
784
785
786/**
787 * Frees the ManageServiceContext queue
788 */
789void
790GST_free_mctxq (void);
791
792
793/**
794 * Cleans up the queue used for forwarding link controllers requests
795 */
796void
797GST_free_lcf (void);
798
799
800/**
801 * Cleans up the route list
802 */
803void
804GST_route_list_clear (void);
805
806
807/**
808 * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
809 *
810 * @param rhc the RegisteredHostContext
811 */
812void
813GST_process_next_focc (struct RegisteredHostContext *rhc);
814
815
816/**
817 * Cleans up ForwardedOverlayConnectContext
818 *
819 * @param focc the ForwardedOverlayConnectContext to cleanup
820 */
821void
822GST_cleanup_focc (struct ForwardedOverlayConnectContext *focc);
823
824
825/**
826 * Clears all pending overlay connect contexts in queue
827 */
828void
829GST_free_occq (void);
830
831
832/**
833 * Clears all pending remote overlay connect contexts in queue
834 */
835void
836GST_free_roccq (void);
837
838
839/**
840 * Cleans up the Peer reconfigure context list
841 */
842void
843GST_free_prcq (void);
844
845
846/**
847 * Initializes the cache
848 *
849 * @param size the size of the cache
850 */
851void
852GST_cache_init (unsigned int size);
853
854
855/**
856 * Clear cache
857 */
858void
859GST_cache_clear (void);
860
861
862/**
863 * Looks up in the hello cache and returns the HELLO of the given peer
864 *
865 * @param peer_id the index of the peer whose HELLO has to be looked up
866 * @return the HELLO message; NULL if not found
867 */
868const struct GNUNET_MessageHeader *
869GST_cache_lookup_hello (const unsigned int peer_id);
870
871
872/**
873 * Caches the HELLO of the given peer. Updates the HELLO if it was already
874 * cached before
875 *
876 * @param peer_id the peer identity of the peer whose HELLO has to be cached
877 * @param hello the HELLO message
878 */
879void
880GST_cache_add_hello (const unsigned int peer_id,
881 const struct GNUNET_MessageHeader *hello);
882
883
884/**
885 * Initialize logging CPU and IO statisticfs. Checks the configuration for
886 * "STATS_DIR" and logs to a file in that directory. The file is name is
887 * generated from the hostname and the process's PID.
888 */
889void
890GST_stats_init (const struct GNUNET_CONFIGURATION_Handle *cfg);
891
892
893/**
894 * Shutdown the status calls module.
895 */
896void
897GST_stats_destroy (void);
898
899/* End of gnunet-service-testbed.h */
diff --git a/src/testbed/gnunet-service-testbed_barriers.c b/src/testbed/gnunet-service-testbed_barriers.c
deleted file mode 100644
index a7eba3201..000000000
--- a/src/testbed/gnunet-service-testbed_barriers.c
+++ /dev/null
@@ -1,929 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_barriers.c
23 * @brief barrier handling at the testbed controller
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet-service-testbed.h"
29#include "gnunet-service-testbed_barriers.h"
30#include "testbed_api.h"
31
32
33/**
34 * timeout for outgoing message transmissions in seconds
35 */
36#define MESSAGE_SEND_TIMEOUT(s) \
37 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, s)
38
39
40/**
41 * Test to see if local peers have reached the required quorum of a barrier
42 */
43#define LOCAL_QUORUM_REACHED(barrier) \
44 ((barrier->quorum * GST_num_local_peers) <= (barrier->nreached * 100))
45
46
47#ifdef LOG
48#undef LOG
49#endif
50
51/**
52 * Logging shorthand
53 */
54#define LOG(kind, ...) \
55 GNUNET_log_from (kind, "testbed-barriers", __VA_ARGS__)
56
57
58/**
59 * Barrier
60 */
61struct Barrier;
62
63
64/**
65 * Context to be associated with each client
66 */
67struct ClientCtx
68{
69 /**
70 * The barrier this client is waiting for
71 */
72 struct Barrier *barrier;
73
74 /**
75 * DLL next ptr
76 */
77 struct ClientCtx *next;
78
79 /**
80 * DLL prev ptr
81 */
82 struct ClientCtx *prev;
83
84 /**
85 * The client handle
86 */
87 struct GNUNET_SERVICE_Client *client;
88};
89
90
91/**
92 * Wrapper around Barrier handle
93 */
94struct WBarrier
95{
96 /**
97 * DLL next pointer
98 */
99 struct WBarrier *next;
100
101 /**
102 * DLL prev pointer
103 */
104 struct WBarrier *prev;
105
106 /**
107 * The local barrier associated with the creation of this wrapper
108 */
109 struct Barrier *barrier;
110
111 /**
112 * Handle to the slave controller where this wrapper creates a barrier
113 */
114 struct GNUNET_TESTBED_Controller *controller;
115
116 /**
117 * The barrier handle from API
118 */
119 struct GNUNET_TESTBED_Barrier *hbarrier;
120
121 /**
122 * Has this barrier been crossed?
123 */
124 uint8_t reached;
125};
126
127
128/**
129 * Barrier
130 */
131struct Barrier
132{
133 /**
134 * The hashcode of the barrier name
135 */
136 struct GNUNET_HashCode hash;
137
138 /**
139 * The client handle to the master controller
140 */
141 struct GNUNET_SERVICE_Client *mc;
142
143 /**
144 * The name of the barrier
145 */
146 char *name;
147
148 /**
149 * DLL head for the list of clients waiting for this barrier
150 */
151 struct ClientCtx *head;
152
153 /**
154 * DLL tail for the list of clients waiting for this barrier
155 */
156 struct ClientCtx *tail;
157
158 /**
159 * DLL head for the list of barrier handles
160 */
161 struct WBarrier *whead;
162
163 /**
164 * DLL tail for the list of barrier handles
165 */
166 struct WBarrier *wtail;
167
168 /**
169 * Identifier for the timeout task
170 */
171 struct GNUNET_SCHEDULER_Task *tout_task;
172
173 /**
174 * The status of this barrier
175 */
176 enum GNUNET_TESTBED_BarrierStatus status;
177
178 /**
179 * Number of barriers wrapped in the above DLL
180 */
181 unsigned int num_wbarriers;
182
183 /**
184 * Number of wrapped barriers reached so far
185 */
186 unsigned int num_wbarriers_reached;
187
188 /**
189 * Number of wrapped barrier initialised so far
190 */
191 unsigned int num_wbarriers_inited;
192
193 /**
194 * Number of peers which have reached this barrier
195 */
196 unsigned int nreached;
197
198 /**
199 * Number of slaves we have initialised this barrier
200 */
201 unsigned int nslaves;
202
203 /**
204 * Quorum percentage to be reached
205 */
206 uint8_t quorum;
207};
208
209
210/**
211 * Hashtable handle for storing initialised barriers
212 */
213static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
214
215/**
216 * Service context
217 */
218static struct GNUNET_SERVICE_Handle *ctx;
219
220
221/**
222 * Function to remove a barrier from the barrier map and cleanup resources
223 * occupied by a barrier
224 *
225 * @param barrier the barrier handle
226 */
227static void
228remove_barrier (struct Barrier *barrier)
229{
230 struct ClientCtx *ctx;
231
232 GNUNET_assert (GNUNET_YES ==
233 GNUNET_CONTAINER_multihashmap_remove (barrier_map,
234 &barrier->hash,
235 barrier));
236 while (NULL != (ctx = barrier->head))
237 {
238 GNUNET_CONTAINER_DLL_remove (barrier->head,
239 barrier->tail,
240 ctx);
241 ctx->barrier = NULL;
242 }
243 GNUNET_free (barrier->name);
244 GNUNET_free (barrier);
245}
246
247
248/**
249 * Cancels all subcontroller barrier handles
250 *
251 * @param barrier the local barrier
252 */
253static void
254cancel_wrappers (struct Barrier *barrier)
255{
256 struct WBarrier *wrapper;
257
258 while (NULL != (wrapper = barrier->whead))
259 {
260 GNUNET_TESTBED_barrier_cancel (wrapper->hbarrier);
261 GNUNET_CONTAINER_DLL_remove (barrier->whead,
262 barrier->wtail,
263 wrapper);
264 GNUNET_free (wrapper);
265 }
266}
267
268
269/**
270 * Send a status message about a barrier to the given client
271 *
272 * @param client the client to send the message to
273 * @param name the barrier name
274 * @param status the status of the barrier
275 * @param emsg the error message; should be non-NULL for
276 * status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
277 */
278static void
279send_client_status_msg (struct GNUNET_SERVICE_Client *client,
280 const char *name,
281 enum GNUNET_TESTBED_BarrierStatus status,
282 const char *emsg)
283{
284 struct GNUNET_MQ_Envelope *env;
285 struct GNUNET_TESTBED_BarrierStatusMsg *msg;
286 size_t name_len;
287 size_t err_len;
288
289 GNUNET_assert ((NULL == emsg) ||
290 (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status));
291 name_len = strlen (name) + 1;
292 err_len = ((NULL == emsg) ? 0 : (strlen (emsg) + 1));
293 env = GNUNET_MQ_msg_extra (msg,
294 name_len + err_len,
295 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
296 msg->status = htons (status);
297 msg->name_len = htons ((uint16_t) name_len - 1);
298 GNUNET_memcpy (msg->data,
299 name,
300 name_len);
301 GNUNET_memcpy (msg->data + name_len,
302 emsg,
303 err_len);
304 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
305 env);
306}
307
308
309/**
310 * Sends a barrier failed message
311 *
312 * @param barrier the corresponding barrier
313 * @param emsg the error message; should be non-NULL for
314 * status=GNUNET_TESTBED_BARRIERSTATUS_ERROR
315 */
316static void
317send_barrier_status_msg (struct Barrier *barrier,
318 const char *emsg)
319{
320 GNUNET_assert (0 != barrier->status);
321 send_client_status_msg (barrier->mc,
322 barrier->name,
323 barrier->status,
324 emsg);
325}
326
327
328/**
329 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages.
330 *
331 * @param cls identification of the client
332 * @param msg the actual message
333 */
334static int
335check_barrier_wait (void *cls,
336 const struct GNUNET_TESTBED_BarrierWait *msg)
337{
338 return GNUNET_OK; /* always well-formed */
339}
340
341
342/**
343 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages. This
344 * message should come from peers or a shared helper service using the
345 * testbed-barrier client API (@see gnunet_testbed_barrier_service.h)
346 *
347 * This handler is queued in the main service and will handle the messages sent
348 * either from the testbed driver or from a high level controller
349 *
350 * @param cls identification of the client
351 * @param msg the actual message
352 */
353static void
354handle_barrier_wait (void *cls,
355 const struct GNUNET_TESTBED_BarrierWait *msg)
356{
357 struct ClientCtx *client_ctx = cls;
358 struct Barrier *barrier;
359 char *name;
360 struct GNUNET_HashCode key;
361 size_t name_len;
362 uint16_t msize;
363
364 msize = ntohs (msg->header.size);
365 if (NULL == barrier_map)
366 {
367 GNUNET_break (0);
368 GNUNET_SERVICE_client_drop (client_ctx->client);
369 return;
370 }
371 name_len = msize - sizeof(struct GNUNET_TESTBED_BarrierWait);
372 name = GNUNET_malloc (name_len + 1);
373 name[name_len] = '\0';
374 GNUNET_memcpy (name,
375 msg->name,
376 name_len);
377 LOG_DEBUG ("Received BARRIER_WAIT for barrier `%s'\n",
378 name);
379 GNUNET_CRYPTO_hash (name,
380 name_len,
381 &key);
382 GNUNET_free (name);
383 if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key)))
384 {
385 GNUNET_break (0);
386 GNUNET_SERVICE_client_drop (client_ctx->client);
387 return;
388 }
389 if (NULL != client_ctx->barrier)
390 {
391 GNUNET_break (0);
392 GNUNET_SERVICE_client_drop (client_ctx->client);
393 return;
394 }
395 client_ctx->barrier = barrier;
396 GNUNET_CONTAINER_DLL_insert_tail (barrier->head,
397 barrier->tail,
398 client_ctx);
399 barrier->nreached++;
400 if ((barrier->num_wbarriers_reached == barrier->num_wbarriers) &&
401 (LOCAL_QUORUM_REACHED (barrier)))
402 {
403 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED;
404 send_barrier_status_msg (barrier,
405 NULL);
406 }
407 GNUNET_SERVICE_client_continue (client_ctx->client);
408}
409
410
411/**
412 * Function called when a client connects to the testbed-barrier service.
413 *
414 * @param cls NULL
415 * @param client the connecting client
416 * @param mq queue to talk to @a client
417 * @return our `struct ClientCtx`
418 */
419static void *
420connect_cb (void *cls,
421 struct GNUNET_SERVICE_Client *client,
422 struct GNUNET_MQ_Handle *mq)
423{
424 struct ClientCtx *client_ctx;
425
426 LOG_DEBUG ("Client connected to testbed-barrier service\n");
427 client_ctx = GNUNET_new (struct ClientCtx);
428 client_ctx->client = client;
429 return client_ctx;
430}
431
432
433/**
434 * Functions with this signature are called whenever a client
435 * is disconnected on the network level.
436 *
437 * @param cls closure
438 * @param client identification of the client; NULL
439 * for the last call when the server is destroyed
440 */
441static void
442disconnect_cb (void *cls,
443 struct GNUNET_SERVICE_Client *client,
444 void *app_ctx)
445{
446 struct ClientCtx *client_ctx = app_ctx;
447 struct Barrier *barrier = client_ctx->barrier;
448
449 if (NULL != barrier)
450 {
451 GNUNET_CONTAINER_DLL_remove (barrier->head,
452 barrier->tail,
453 client_ctx);
454 client_ctx->barrier = NULL;
455 }
456 GNUNET_free (client_ctx);
457 LOG_DEBUG ("Client disconnected from testbed-barrier service\n");
458}
459
460
461/**
462 * Function to initialise barriers component
463 *
464 * @param cfg the configuration to use for initialisation
465 */
466void
467GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
468{
469 struct GNUNET_MQ_MessageHandler message_handlers[] = {
470 GNUNET_MQ_hd_var_size (barrier_wait,
471 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT,
472 struct GNUNET_TESTBED_BarrierWait,
473 NULL),
474 GNUNET_MQ_handler_end ()
475 };
476
477 LOG_DEBUG ("Launching testbed-barrier service\n");
478 barrier_map = GNUNET_CONTAINER_multihashmap_create (3,
479 GNUNET_YES);
480 ctx = GNUNET_SERVICE_start ("testbed-barrier",
481 cfg,
482 &connect_cb,
483 &disconnect_cb,
484 NULL,
485 message_handlers);
486}
487
488
489/**
490 * Iterator over hash map entries.
491 *
492 * @param cls closure
493 * @param key current key code
494 * @param value value in the hash map
495 * @return #GNUNET_YES if we should continue to
496 * iterate,
497 * #GNUNET_NO if not.
498 */
499static int
500barrier_destroy_iterator (void *cls,
501 const struct GNUNET_HashCode *key,
502 void *value)
503{
504 struct Barrier *barrier = value;
505
506 GNUNET_assert (NULL != barrier);
507 cancel_wrappers (barrier);
508 remove_barrier (barrier);
509 return GNUNET_YES;
510}
511
512
513/**
514 * Function to stop the barrier service
515 */
516void
517GST_barriers_destroy ()
518{
519 GNUNET_assert (NULL != barrier_map);
520 GNUNET_assert (GNUNET_SYSERR !=
521 GNUNET_CONTAINER_multihashmap_iterate (barrier_map,
522 &
523 barrier_destroy_iterator,
524 NULL));
525 GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
526 GNUNET_assert (NULL != ctx);
527 GNUNET_SERVICE_stop (ctx);
528}
529
530
531/**
532 * Functions of this type are to be given as callback argument to
533 * GNUNET_TESTBED_barrier_init(). The callback will be called when status
534 * information is available for the barrier.
535 *
536 * @param cls the closure given to GNUNET_TESTBED_barrier_init()
537 * @param name the name of the barrier
538 * @param b_ the barrier handle
539 * @param status status of the barrier; #GNUNET_OK if the barrier is crossed;
540 * #GNUNET_SYSERR upon error
541 * @param emsg if the status were to be #GNUNET_SYSERR, this parameter has the
542 * error message
543 */
544static void
545wbarrier_status_cb (void *cls,
546 const char *name,
547 struct GNUNET_TESTBED_Barrier *b_,
548 enum GNUNET_TESTBED_BarrierStatus status,
549 const char *emsg)
550{
551 struct WBarrier *wrapper = cls;
552 struct Barrier *barrier = wrapper->barrier;
553
554 GNUNET_assert (b_ == wrapper->hbarrier);
555 switch (status)
556 {
557 case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
558 LOG (GNUNET_ERROR_TYPE_ERROR,
559 "Initialising barrier `%s' failed at a sub-controller: %s\n",
560 barrier->name,
561 (NULL != emsg) ? emsg : "NULL");
562 cancel_wrappers (barrier);
563 if (NULL == emsg)
564 emsg = "Initialisation failed at a sub-controller";
565 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_ERROR;
566 send_barrier_status_msg (barrier, emsg);
567 return;
568
569 case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
570 if (GNUNET_TESTBED_BARRIERSTATUS_INITIALISED != barrier->status)
571 {
572 GNUNET_break_op (0);
573 return;
574 }
575 barrier->num_wbarriers_reached++;
576 if ((barrier->num_wbarriers_reached == barrier->num_wbarriers)
577 && (LOCAL_QUORUM_REACHED (barrier)))
578 {
579 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_CROSSED;
580 send_barrier_status_msg (barrier, NULL);
581 }
582 return;
583
584 case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
585 if (0 != barrier->status)
586 {
587 GNUNET_break_op (0);
588 return;
589 }
590 barrier->num_wbarriers_inited++;
591 if (barrier->num_wbarriers_inited == barrier->num_wbarriers)
592 {
593 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED;
594 send_barrier_status_msg (barrier, NULL);
595 }
596 return;
597 }
598}
599
600
601/**
602 * Function called upon timeout while waiting for a response from the
603 * subcontrollers to barrier init message
604 *
605 * @param cls barrier
606 */
607static void
608fwd_tout_barrier_init (void *cls)
609{
610 struct Barrier *barrier = cls;
611
612 cancel_wrappers (barrier);
613 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_ERROR;
614 send_barrier_status_msg (barrier,
615 "Timedout while propagating barrier initialisation\n");
616 remove_barrier (barrier);
617}
618
619
620/**
621 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages.
622 *
623 * @param cls identification of the client
624 * @param msg the actual message
625 * @return #GNUNET_OK if @a msg is well-formed
626 */
627int
628check_barrier_init (void *cls,
629 const struct GNUNET_TESTBED_BarrierInit *msg)
630{
631 return GNUNET_OK; /* always well-formed */
632}
633
634
635/**
636 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages. This
637 * message should always come from a parent controller or the testbed API if we
638 * are the root controller.
639 *
640 * This handler is queued in the main service and will handle the messages sent
641 * either from the testbed driver or from a high level controller
642 *
643 * @param cls identification of the client
644 * @param msg the actual message
645 */
646void
647handle_barrier_init (void *cls,
648 const struct GNUNET_TESTBED_BarrierInit *msg)
649{
650 struct GNUNET_SERVICE_Client *client = cls;
651 char *name;
652 struct Barrier *barrier;
653 struct Slave *slave;
654 struct WBarrier *wrapper;
655 struct GNUNET_HashCode hash;
656 size_t name_len;
657 unsigned int cnt;
658 uint16_t msize;
659
660 if (NULL == GST_context)
661 {
662 GNUNET_break_op (0);
663 GNUNET_SERVICE_client_drop (client);
664 return;
665 }
666 if (client != GST_context->client)
667 {
668 GNUNET_break_op (0);
669 GNUNET_SERVICE_client_drop (client);
670 return;
671 }
672 msize = ntohs (msg->header.size);
673 name_len = (size_t) msize - sizeof(struct GNUNET_TESTBED_BarrierInit);
674 name = GNUNET_malloc (name_len + 1);
675 GNUNET_memcpy (name, msg->name, name_len);
676 GNUNET_CRYPTO_hash (name, name_len, &hash);
677 LOG_DEBUG ("Received BARRIER_INIT for barrier `%s'\n",
678 name);
679 if (GNUNET_YES ==
680 GNUNET_CONTAINER_multihashmap_contains (barrier_map,
681 &hash))
682 {
683 send_client_status_msg (client,
684 name,
685 GNUNET_TESTBED_BARRIERSTATUS_ERROR,
686 "A barrier with the same name already exists");
687 GNUNET_free (name);
688 GNUNET_SERVICE_client_continue (client);
689 return;
690 }
691 barrier = GNUNET_new (struct Barrier);
692 barrier->hash = hash;
693 barrier->quorum = msg->quorum;
694 barrier->name = name;
695 barrier->mc = client;
696 GNUNET_assert (GNUNET_OK ==
697 GNUNET_CONTAINER_multihashmap_put (barrier_map,
698 &barrier->hash,
699 barrier,
700 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
701 GNUNET_SERVICE_client_continue (client);
702 /* Propagate barrier init to subcontrollers */
703 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
704 {
705 if (NULL == (slave = GST_slave_list[cnt]))
706 continue;
707 if (NULL == slave->controller)
708 {
709 GNUNET_break (0); /* May happen when we are connecting to the controller */
710 continue;
711 }
712 wrapper = GNUNET_new (struct WBarrier);
713 wrapper->barrier = barrier;
714 wrapper->controller = slave->controller;
715 GNUNET_CONTAINER_DLL_insert_tail (barrier->whead,
716 barrier->wtail,
717 wrapper);
718 barrier->num_wbarriers++;
719 wrapper->hbarrier = GNUNET_TESTBED_barrier_init_ (wrapper->controller,
720 barrier->name,
721 barrier->quorum,
722 &wbarrier_status_cb,
723 wrapper,
724 GNUNET_NO);
725 }
726 if (NULL == barrier->whead) /* No further propagation */
727 {
728 barrier->status = GNUNET_TESTBED_BARRIERSTATUS_INITIALISED;
729 LOG_DEBUG (
730 "Sending GNUNET_TESTBED_BARRIERSTATUS_INITIALISED for barrier `%s'\n",
731 barrier->name);
732 send_barrier_status_msg (barrier, NULL);
733 }
734 else
735 barrier->tout_task = GNUNET_SCHEDULER_add_delayed (MESSAGE_SEND_TIMEOUT (
736 30),
737 &fwd_tout_barrier_init,
738 barrier);
739}
740
741
742/**
743 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages.
744 *
745 * @param cls identification of the client
746 * @param msg the actual message
747 * @return #GNUNET_OK if @a msg is well-formed
748 */
749int
750check_barrier_cancel (void *cls,
751 const struct GNUNET_TESTBED_BarrierCancel *msg)
752{
753 return GNUNET_OK; /* all are well-formed */
754}
755
756
757/**
758 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages. This
759 * message should always come from a parent controller or the testbed API if we
760 * are the root controller.
761 *
762 * This handler is queued in the main service and will handle the messages sent
763 * either from the testbed driver or from a high level controller
764 *
765 * @param cls identification of the client
766 * @param msg the actual message
767 */
768void
769handle_barrier_cancel (void *cls,
770 const struct GNUNET_TESTBED_BarrierCancel *msg)
771{
772 struct GNUNET_SERVICE_Client *client = cls;
773 char *name;
774 struct Barrier *barrier;
775 struct GNUNET_HashCode hash;
776 size_t name_len;
777 uint16_t msize;
778
779 if (NULL == GST_context)
780 {
781 GNUNET_break_op (0);
782 GNUNET_SERVICE_client_drop (client);
783 return;
784 }
785 if (client != GST_context->client)
786 {
787 GNUNET_break_op (0);
788 GNUNET_SERVICE_client_drop (client);
789 return;
790 }
791 msize = ntohs (msg->header.size);
792 name_len = msize - sizeof(struct GNUNET_TESTBED_BarrierCancel);
793 name = GNUNET_malloc (name_len + 1);
794 GNUNET_memcpy (name,
795 msg->name,
796 name_len);
797 LOG_DEBUG ("Received BARRIER_CANCEL for barrier `%s'\n",
798 name);
799 GNUNET_CRYPTO_hash (name,
800 name_len,
801 &hash);
802 if (GNUNET_NO ==
803 GNUNET_CONTAINER_multihashmap_contains (barrier_map,
804 &hash))
805 {
806 GNUNET_break_op (0);
807 GNUNET_free (name);
808 GNUNET_SERVICE_client_drop (client);
809 return;
810 }
811 barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
812 &hash);
813 GNUNET_assert (NULL != barrier);
814 cancel_wrappers (barrier);
815 remove_barrier (barrier);
816 GNUNET_free (name);
817 GNUNET_SERVICE_client_continue (client);
818}
819
820
821/**
822 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
823 *
824 * @param cls identification of the client
825 * @param msg the actual message
826 * @return #GNUNET_OK if @a msg is well-formed
827 */
828int
829check_barrier_status (void *cls,
830 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
831{
832 uint16_t msize;
833 uint16_t name_len;
834 const char *name;
835 enum GNUNET_TESTBED_BarrierStatus status;
836
837 msize = ntohs (msg->header.size) - sizeof(*msg);
838 status = ntohs (msg->status);
839 if (GNUNET_TESTBED_BARRIERSTATUS_CROSSED != status)
840 {
841 GNUNET_break_op (0); /* current we only expect BARRIER_CROSSED
842 status message this way */
843 return GNUNET_SYSERR;
844 }
845 name = msg->data;
846 name_len = ntohs (msg->name_len);
847 if ((name_len + 1) != msize)
848 {
849 GNUNET_break_op (0);
850 return GNUNET_SYSERR;
851 }
852 if ('\0' != name[name_len])
853 {
854 GNUNET_break_op (0);
855 return GNUNET_SYSERR;
856 }
857 return GNUNET_OK;
858}
859
860
861/**
862 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
863 * This handler is queued in the main service and will handle the messages sent
864 * either from the testbed driver or from a high level controller
865 *
866 * @param cls identification of the client
867 * @param msg the actual message
868 */
869void
870handle_barrier_status (void *cls,
871 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
872{
873 struct GNUNET_SERVICE_Client *client = cls;
874 struct Barrier *barrier;
875 struct ClientCtx *client_ctx;
876 struct WBarrier *wrapper;
877 const char *name;
878 struct GNUNET_HashCode key;
879 uint16_t name_len;
880 struct GNUNET_MQ_Envelope *env;
881
882 if (NULL == GST_context)
883 {
884 GNUNET_break_op (0);
885 GNUNET_SERVICE_client_drop (client);
886 return;
887 }
888 if (client != GST_context->client)
889 {
890 GNUNET_break_op (0);
891 GNUNET_SERVICE_client_drop (client);
892 return;
893 }
894 name = msg->data;
895 name_len = ntohs (msg->name_len);
896 LOG_DEBUG ("Received BARRIER_STATUS for barrier `%s'\n",
897 name);
898 GNUNET_CRYPTO_hash (name,
899 name_len,
900 &key);
901 barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map,
902 &key);
903 if (NULL == barrier)
904 {
905 GNUNET_break_op (0);
906 GNUNET_SERVICE_client_drop (client);
907 return;
908 }
909 GNUNET_SERVICE_client_continue (client);
910 for (client_ctx = barrier->head; NULL != client_ctx; client_ctx =
911 client_ctx->next) /* Notify peers */
912 {
913 env = GNUNET_MQ_msg_copy (&msg->header);
914 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client_ctx->client),
915 env);
916 }
917 /**
918 * The wrapper barriers do not echo the barrier status, so we have to do it
919 * here
920 */
921 for (wrapper = barrier->whead; NULL != wrapper; wrapper = wrapper->next)
922 {
923 GNUNET_TESTBED_queue_message_ (wrapper->controller,
924 GNUNET_copy_message (&msg->header));
925 }
926}
927
928
929/* end of gnunet-service-testbed_barriers.c */
diff --git a/src/testbed/gnunet-service-testbed_barriers.h b/src/testbed/gnunet-service-testbed_barriers.h
deleted file mode 100644
index aa2718777..000000000
--- a/src/testbed/gnunet-service-testbed_barriers.h
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_barriers.h
23 * @brief Interface for the barrier initialisation handler routine
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#ifndef GNUNET_SERVER_TESTBED_BARRIERS_H_
28#define GNUNET_SERVER_TESTBED_BARRIERS_H_
29
30/**
31 * Function to initialise barriers component
32 *
33 * @param cfg the configuration to use for initialisation
34 */
35void
36GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg);
37
38
39/**
40 * Function to stop the barrier service
41 */
42void
43GST_barriers_destroy (void);
44
45
46/**
47 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages.
48 *
49 * @param cls identification of the client
50 * @param msg the actual message
51 * @return #GNUNET_OK if @a msg is well-formed
52 */
53int
54check_barrier_init (void *cls,
55 const struct GNUNET_TESTBED_BarrierInit *msg);
56
57
58/**
59 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages. This
60 * message should always come from a parent controller or the testbed API if we
61 * are the root controller.
62 *
63 * This handler is queued in the main service and will handle the messages sent
64 * either from the testbed driver or from a high level controller
65 *
66 * @param cls identification of the client
67 * @param msg the actual message
68 */
69void
70handle_barrier_init (void *cls,
71 const struct GNUNET_TESTBED_BarrierInit *msg);
72
73
74/**
75 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages.
76 *
77 * @param cls identification of the client
78 * @param msg the actual message
79 * @return #GNUNET_OK if @a msg is well-formed
80 */
81int
82check_barrier_cancel (void *cls,
83 const struct GNUNET_TESTBED_BarrierCancel *msg);
84
85
86/**
87 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL messages. This
88 * message should always come from a parent controller or the testbed API if we
89 * are the root controller.
90 *
91 * This handler is queued in the main service and will handle the messages sent
92 * either from the testbed driver or from a high level controller
93 *
94 * @param cls identification of the client
95 * @param msg the actual message
96 */
97void
98handle_barrier_cancel (void *cls,
99 const struct GNUNET_TESTBED_BarrierCancel *msg);
100
101
102/**
103 * Check #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
104 *
105 * @param cls identification of the client
106 * @param msg the actual message
107 * @return #GNUNET_OK if @a msg is well-formed
108 */
109int
110check_barrier_status (void *cls,
111 const struct GNUNET_TESTBED_BarrierStatusMsg *msg);
112
113
114/**
115 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.
116 * This handler is queued in the main service and will handle the messages sent
117 * either from the testbed driver or from a high level controller
118 *
119 * @param cls identification of the client
120 * @param msg the actual message
121 */
122void
123handle_barrier_status (void *cls,
124 const struct GNUNET_TESTBED_BarrierStatusMsg *msg);
125
126#endif /* GNUNET_SERVER_TESTBED_BARRIERS_H_ */
127
128/* end of gnunet-service-testbed_barriers.h */
diff --git a/src/testbed/gnunet-service-testbed_cache.c b/src/testbed/gnunet-service-testbed_cache.c
deleted file mode 100644
index 5d5c2e297..000000000
--- a/src/testbed/gnunet-service-testbed_cache.c
+++ /dev/null
@@ -1,270 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_cache.c
23 * @brief testbed cache implementation
24 * @author Sree Harsha Totakura
25 */
26#include "platform.h"
27#include "gnunet-service-testbed.h"
28
29/**
30 * Redefine LOG with a changed log component string
31 */
32#ifdef LOG
33#undef LOG
34#endif
35#define LOG(kind, ...) \
36 GNUNET_log_from (kind, "testbed-cache", __VA_ARGS__)
37
38
39/**
40 * Cache entry
41 */
42struct CacheEntry
43{
44 /**
45 * DLL next ptr for least recently used cache entries
46 */
47 struct CacheEntry *next;
48
49 /**
50 * DLL prev ptr for least recently used cache entries
51 */
52 struct CacheEntry *prev;
53
54 /**
55 * The HELLO message
56 */
57 struct GNUNET_MessageHeader *hello;
58
59 /**
60 * The id of the peer this entry corresponds to
61 */
62 unsigned int peer_id;
63};
64
65
66/**
67 * Hashmap to maintain cache
68 */
69static struct GNUNET_CONTAINER_MultiHashMap32 *cache;
70
71/**
72 * DLL head for least recently used cache entries; least recently used
73 * cache items are at the head. The cache enties are added to this queue when
74 * their demand becomes zero. They are removed from the queue when they are
75 * needed by any operation.
76 */
77static struct CacheEntry *cache_head;
78
79/**
80 * DLL tail for least recently used cache entries; recently used cache
81 * items are at the tail.The cache enties are added to this queue when
82 * their demand becomes zero. They are removed from the queue when they are
83 * needed by any operation.
84 */
85static struct CacheEntry *cache_tail;
86
87/**
88 * Maximum number of elements to cache
89 */
90static unsigned int cache_size;
91
92
93/**
94 * Looks up in the cache and returns the entry
95 *
96 * @param peer_id the peer identity of the peer whose corresponding entry has to
97 * be looked up
98 * @return the HELLO message; NULL if not found
99 */
100static struct CacheEntry *
101cache_lookup (unsigned int peer_id)
102{
103 struct CacheEntry *entry;
104
105 GNUNET_assert (NULL != cache);
106 entry = GNUNET_CONTAINER_multihashmap32_get (cache, peer_id);
107 if (NULL == entry)
108 return NULL;
109 GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, entry);
110 GNUNET_CONTAINER_DLL_insert_tail (cache_head, cache_tail, entry);
111 return entry;
112}
113
114
115/**
116 * Free the resources occupied by a cache entry
117 *
118 * @param entry the cache entry to free
119 */
120static void
121free_entry (struct CacheEntry *entry)
122{
123 GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, entry);
124 GNUNET_free (entry->hello);
125 GNUNET_free (entry);
126}
127
128
129/**
130 * Creates a new cache entry and then puts it into the cache's hashtable.
131 *
132 * @param peer_id the index of the peer to tag the newly created entry
133 * @return the newly created entry
134 */
135static struct CacheEntry *
136add_entry (unsigned int peer_id)
137{
138 struct CacheEntry *entry;
139
140 GNUNET_assert (NULL != cache);
141 if (cache_size == GNUNET_CONTAINER_multihashmap32_size (cache))
142 {
143 /* remove the LRU head */
144 entry = cache_head;
145 GNUNET_assert (GNUNET_OK ==
146 GNUNET_CONTAINER_multihashmap32_remove (cache, (uint32_t)
147 entry->peer_id,
148 entry));
149 free_entry (entry);
150 }
151 entry = GNUNET_new (struct CacheEntry);
152 entry->peer_id = peer_id;
153 GNUNET_assert (GNUNET_OK ==
154 GNUNET_CONTAINER_multihashmap32_put (cache,
155 (uint32_t) peer_id,
156 entry,
157 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
158 GNUNET_CONTAINER_DLL_insert_tail (cache_head, cache_tail, entry);
159 return entry;
160}
161
162
163/**
164 * Iterator over hash map entries.
165 *
166 * @param cls closure
167 * @param key current key
168 * @param value value in the hash map
169 * @return GNUNET_YES if we should continue to
170 * iterate,
171 * GNUNET_NO if not.
172 */
173static int
174cache_clear_iterator (void *cls, uint32_t key, void *value)
175{
176 struct CacheEntry *entry = value;
177
178 GNUNET_assert (NULL != entry);
179 GNUNET_assert (GNUNET_YES ==
180 GNUNET_CONTAINER_multihashmap32_remove (cache, key, value));
181 free_entry (entry);
182 return GNUNET_YES;
183}
184
185
186/**
187 * Clear cache
188 */
189void
190GST_cache_clear ()
191{
192 if (NULL != cache)
193 {
194 GNUNET_CONTAINER_multihashmap32_iterate (cache, &cache_clear_iterator,
195 NULL);
196 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (cache));
197 GNUNET_CONTAINER_multihashmap32_destroy (cache);
198 cache = NULL;
199 }
200 cache_size = 0;
201 cache_head = NULL;
202 cache_tail = NULL;
203}
204
205
206/**
207 * Initializes the cache
208 *
209 * @param size the size of the cache
210 */
211void
212GST_cache_init (unsigned int size)
213{
214 if (0 == size)
215 return;
216 cache_size = size;
217 cache = GNUNET_CONTAINER_multihashmap32_create (cache_size);
218}
219
220
221/**
222 * Looks up in the hello cache and returns the HELLO of the given peer
223 *
224 * @param peer_id the index of the peer whose HELLO has to be looked up
225 * @return the HELLO message; NULL if not found
226 */
227const struct GNUNET_MessageHeader *
228GST_cache_lookup_hello (const unsigned int peer_id)
229{
230 struct CacheEntry *entry;
231
232 LOG_DEBUG ("Looking up HELLO for peer %u\n", peer_id);
233 if (NULL == cache)
234 {
235 LOG_DEBUG ("Caching disabled\n");
236 return NULL;
237 }
238 entry = cache_lookup (peer_id);
239 if (NULL == entry)
240 return NULL;
241 if (NULL != entry->hello)
242 LOG_DEBUG ("HELLO found for peer %u\n", peer_id);
243 return entry->hello;
244}
245
246
247/**
248 * Caches the HELLO of the given peer. Updates the HELLO if it was already
249 * cached before
250 *
251 * @param peer_id the peer identity of the peer whose HELLO has to be cached
252 * @param hello the HELLO message
253 */
254void
255GST_cache_add_hello (const unsigned int peer_id,
256 const struct GNUNET_MessageHeader *hello)
257{
258 struct CacheEntry *entry;
259
260 if (NULL == cache)
261 return;
262 entry = cache_lookup (peer_id);
263 if (NULL == entry)
264 entry = add_entry (peer_id);
265 GNUNET_free (entry->hello);
266 entry->hello = GNUNET_copy_message (hello);
267}
268
269
270/* end of gnunet-service-testbed_hc.c */
diff --git a/src/testbed/gnunet-service-testbed_connectionpool.c b/src/testbed/gnunet-service-testbed_connectionpool.c
deleted file mode 100644
index 64b6706a4..000000000
--- a/src/testbed/gnunet-service-testbed_connectionpool.c
+++ /dev/null
@@ -1,1045 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_connectionpool.c
23 * @brief connection pooling for connections to peers' services
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet-service-testbed.h"
29#include "gnunet-service-testbed_connectionpool.h"
30#include "testbed_api_operations.h"
31#include "gnunet_transport_service.h"
32
33/**
34 * Redefine LOG with a changed log component string
35 */
36#ifdef LOG
37#undef LOG
38#endif
39#define LOG(kind, ...) \
40 GNUNET_log_from (kind, "testbed-connectionpool", __VA_ARGS__)
41
42
43/**
44 * Time to expire a cache entry
45 */
46#define CACHE_EXPIRY \
47 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
48
49
50/**
51 * The request handle for obtaining a pooled connection
52 */
53struct GST_ConnectionPool_GetHandle;
54
55
56/**
57 * A pooled connection
58 */
59struct PooledConnection
60{
61 /**
62 * Next ptr for placing this object in the DLL of least recently used pooled
63 * connections
64 */
65 struct PooledConnection *next;
66
67 /**
68 * Prev ptr for placing this object in the DLL of the least recently used
69 * pooled connections
70 */
71 struct PooledConnection *prev;
72
73 /**
74 * The transport handle to the peer corresponding to this entry; can be NULL
75 */
76 struct GNUNET_TRANSPORT_CoreHandle *handle_transport;
77
78 /**
79 * The core handle to the peer corresponding to this entry; can be NULL
80 */
81 struct GNUNET_CORE_Handle *handle_core;
82
83 /**
84 * The ATS handle to the peer correspondign to this entry; can be NULL.
85 */
86 struct GNUNET_ATS_ConnectivityHandle *handle_ats_connectivity;
87
88 /**
89 * The operation handle for transport handle
90 */
91 struct GNUNET_TESTBED_Operation *op_transport;
92
93 /**
94 * The operation handle for core handle
95 */
96 struct GNUNET_TESTBED_Operation *op_core;
97
98 /**
99 * The operation handle for ATS handle
100 */
101 struct GNUNET_TESTBED_Operation *op_ats_connectivity;
102
103 /**
104 * The peer identity of this peer. Will be set upon opening a connection to
105 * the peers CORE service. Will be NULL until then and after the CORE
106 * connection is closed
107 */
108 struct GNUNET_PeerIdentity *peer_identity;
109
110 /**
111 * The configuration of the peer. Should be not NULL as long as the
112 * core_handle or transport_handle are valid
113 */
114 struct GNUNET_CONFIGURATION_Handle *cfg;
115
116 /**
117 * DLL head for the queue to serve notifications when a peer is connected
118 */
119 struct GST_ConnectionPool_GetHandle *head_notify;
120
121 /**
122 * DLL tail for the queue to serve notifications when a peer is connected
123 */
124 struct GST_ConnectionPool_GetHandle *tail_notify;
125
126 /**
127 * DLL head for the queue of #GST_ConnectionPool_GetHandle requests that are
128 * waiting for this connection to be opened
129 */
130 struct GST_ConnectionPool_GetHandle *head_waiting;
131
132 /**
133 * DLL tail for the queue of #GST_ConnectionPool_GetHandle requests that are
134 * waiting for this connection to be opened
135 */
136 struct GST_ConnectionPool_GetHandle *tail_waiting;
137
138 /**
139 * The task to expire this connection from the connection pool
140 */
141 struct GNUNET_SCHEDULER_Task *expire_task;
142
143 /**
144 * The task to notify a waiting #GST_ConnectionPool_GetHandle object
145 */
146 struct GNUNET_SCHEDULER_Task *notify_task;
147
148 /**
149 * Number of active requests using this pooled connection
150 */
151 unsigned int demand;
152
153 /**
154 * Is this entry in LRU
155 */
156 int in_lru;
157
158 /**
159 * Is this entry present in the connection pool
160 */
161 int in_pool;
162
163 /**
164 * The index of this peer
165 */
166 uint32_t index;
167};
168
169
170/**
171 * The request handle for obtaining a pooled connection
172 */
173struct GST_ConnectionPool_GetHandle
174{
175 /**
176 * The next ptr for inclusion in the notification DLLs. At first the object
177 * is placed in the waiting DLL of the corresponding #PooledConnection
178 * object. After the handle is opened it is moved to the notification DLL if
179 * @p connect_notify_cb and @p target are not NULL
180 */
181 struct GST_ConnectionPool_GetHandle *next;
182
183 /**
184 * The prev ptr for inclusion in the notification DLLs
185 */
186 struct GST_ConnectionPool_GetHandle *prev;
187
188 /**
189 * The pooled connection object this handle corresponds to
190 */
191 struct PooledConnection *entry;
192
193 /**
194 * The cache callback to call when a handle is available
195 */
196 GST_connection_pool_connection_ready_cb cb;
197
198 /**
199 * The closure for the above callback
200 */
201 void *cb_cls;
202
203 /**
204 * The peer identity of the target peer. When this target peer is connected,
205 * call the notify callback
206 */
207 const struct GNUNET_PeerIdentity *target;
208
209 /**
210 * The callback to be called for serving notification that the target peer is
211 * connected
212 */
213 GST_connection_pool_peer_connect_notify connect_notify_cb;
214
215 /**
216 * The closure for the notify callback
217 */
218 void *connect_notify_cb_cls;
219
220 /**
221 * The service we want to connect to
222 */
223 enum GST_ConnectionPool_Service service;
224
225 /**
226 * Did we call the pool_connection_ready_cb already?
227 */
228 int connection_ready_called;
229
230 /**
231 * Are we waiting for any peer connect notifications?
232 */
233 int notify_waiting;
234};
235
236
237/**
238 * A hashmap for quickly finding connections in the connection pool
239 */
240static struct GNUNET_CONTAINER_MultiHashMap32 *map;
241
242/**
243 * DLL head for maitaining the least recently used #PooledConnection objects.
244 * The head is the least recently used object.
245 */
246static struct PooledConnection *head_lru;
247
248/**
249 * DLL tail for maitaining the least recently used #PooledConnection objects
250 */
251static struct PooledConnection *tail_lru;
252
253/**
254 * DLL head for maintaining #PooledConnection objects that are not added into
255 * the connection pool as it was full at the time the object's creation
256 * FIXME
257 */
258static struct PooledConnection *head_not_pooled;
259
260/**
261 * DLL tail for maintaining #PooledConnection objects that are not added into
262 * the connection pool as it was full at the time the object's creation
263 */
264static struct PooledConnection *tail_not_pooled;
265
266/**
267 * The maximum number of entries that can be present in the connection pool
268 */
269static unsigned int max_size;
270
271
272/**
273 * Cancel the expiration task of the give #PooledConnection object
274 *
275 * @param entry the #PooledConnection object
276 */
277static void
278expire_task_cancel (struct PooledConnection *entry);
279
280
281/**
282 * Destroy a #PooledConnection object
283 *
284 * @param entry the #PooledConnection object
285 */
286static void
287destroy_pooled_connection (struct PooledConnection *entry)
288{
289 GNUNET_assert ((NULL == entry->head_notify) && (NULL == entry->tail_notify));
290 GNUNET_assert ((NULL == entry->head_waiting) &&
291 (NULL == entry->tail_waiting));
292 GNUNET_assert (0 == entry->demand);
293 expire_task_cancel (entry);
294 if (entry->in_lru)
295 GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
296 if (entry->in_pool)
297 GNUNET_assert (
298 GNUNET_OK ==
299 GNUNET_CONTAINER_multihashmap32_remove (map, entry->index, entry));
300 if (NULL != entry->notify_task)
301 {
302 GNUNET_SCHEDULER_cancel (entry->notify_task);
303 entry->notify_task = NULL;
304 }
305 LOG_DEBUG ("Cleaning up handles of a pooled connection\n");
306 if (NULL != entry->handle_transport)
307 GNUNET_assert (NULL != entry->op_transport);
308 if (NULL != entry->op_transport)
309 {
310 GNUNET_TESTBED_operation_done (entry->op_transport);
311 entry->op_transport = NULL;
312 }
313 if (NULL != entry->handle_ats_connectivity)
314 GNUNET_assert (NULL != entry->op_ats_connectivity);
315 if (NULL != entry->op_ats_connectivity)
316 {
317 GNUNET_TESTBED_operation_done (entry->op_ats_connectivity);
318 entry->op_ats_connectivity = NULL;
319 }
320 if (NULL != entry->op_core)
321 {
322 GNUNET_TESTBED_operation_done (entry->op_core);
323 entry->op_core = NULL;
324 }
325 GNUNET_assert (NULL == entry->handle_core);
326 GNUNET_assert (NULL == entry->handle_ats_connectivity);
327 GNUNET_assert (NULL == entry->handle_transport);
328 GNUNET_CONFIGURATION_destroy (entry->cfg);
329 GNUNET_free (entry);
330}
331
332
333/**
334 * Expire a #PooledConnection object
335 *
336 * @param cls the #PooledConnection object
337 */
338static void
339expire (void *cls)
340{
341 struct PooledConnection *entry = cls;
342
343 entry->expire_task = NULL;
344 destroy_pooled_connection (entry);
345}
346
347
348/**
349 * Cancel the expiration task of the give #PooledConnection object
350 *
351 * @param entry the #PooledConnection object
352 */
353static void
354expire_task_cancel (struct PooledConnection *entry)
355{
356 if (NULL != entry->expire_task)
357 {
358 GNUNET_SCHEDULER_cancel (entry->expire_task);
359 entry->expire_task = NULL;
360 }
361}
362
363
364/**
365 * Function to add a #PooledConnection object into LRU and begin the expiry task
366 *
367 * @param entry the #PooledConnection object
368 */
369static void
370add_to_lru (struct PooledConnection *entry)
371{
372 GNUNET_assert (0 == entry->demand);
373 GNUNET_assert (! entry->in_lru);
374 GNUNET_CONTAINER_DLL_insert_tail (head_lru, tail_lru, entry);
375 entry->in_lru = GNUNET_YES;
376 GNUNET_assert (NULL == entry->expire_task);
377 entry->expire_task =
378 GNUNET_SCHEDULER_add_delayed (CACHE_EXPIRY, &expire, entry);
379}
380
381
382/**
383 * Function to find a #GST_ConnectionPool_GetHandle which is waiting for one of
384 * the handles in given entry which are now available.
385 *
386 * @param entry the pooled connection whose active list has to be searched
387 * @param head the starting list element in the GSTCacheGetHandle where the
388 * search has to be begin
389 * @return a suitable GSTCacheGetHandle whose handle ready notify callback
390 * hasn't been called yet. NULL if no such suitable GSTCacheGetHandle
391 * is found
392 */
393static struct GST_ConnectionPool_GetHandle *
394search_waiting (const struct PooledConnection *entry,
395 struct GST_ConnectionPool_GetHandle *head)
396{
397 struct GST_ConnectionPool_GetHandle *gh;
398
399 for (gh = head; NULL != gh; gh = gh->next)
400 {
401 switch (gh->service)
402 {
403 case GST_CONNECTIONPOOL_SERVICE_CORE:
404 if (NULL == entry->handle_core)
405 continue;
406 if (NULL == entry->peer_identity)
407 continue; /* CORE connection isn't ready yet */
408 break;
409
410 case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
411 if (NULL == entry->handle_transport)
412 continue;
413 break;
414
415 case GST_CONNECTIONPOOL_SERVICE_ATS_CONNECTIVITY:
416 if (NULL == entry->handle_ats_connectivity)
417 continue;
418 break;
419 }
420 break;
421 }
422 return gh;
423}
424
425
426/**
427 * A handle in the #PooledConnection object pointed by @a cls is ready and there
428 * is a #GST_ConnectionPool_GetHandle object waiting in the waiting list. This
429 * function retrieves that object and calls the handle ready callback. It
430 * further schedules itself if there are similar waiting objects which can be
431 * notified.
432 *
433 * @param cls the #PooledConnection object
434 */
435static void
436connection_ready (void *cls)
437{
438 struct PooledConnection *entry = cls;
439 struct GST_ConnectionPool_GetHandle *gh;
440 struct GST_ConnectionPool_GetHandle *gh_next;
441
442 GNUNET_assert (NULL != entry->notify_task);
443 entry->notify_task = NULL;
444 gh = search_waiting (entry, entry->head_waiting);
445 GNUNET_assert (NULL != gh);
446 gh_next = NULL;
447 if (NULL != gh->next)
448 gh_next = search_waiting (entry, gh->next);
449 GNUNET_CONTAINER_DLL_remove (entry->head_waiting,
450 entry->tail_waiting,
451 gh);
452 gh->connection_ready_called = 1;
453 if (NULL != gh_next)
454 entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready,
455 entry);
456 if ((NULL != gh->target) && (NULL != gh->connect_notify_cb))
457 {
458 GNUNET_CONTAINER_DLL_insert_tail (entry->head_notify,
459 entry->tail_notify,
460 gh);
461 gh->notify_waiting = 1;
462 }
463 LOG_DEBUG ("Connection ready to %u for handle type %u\n",
464 (unsigned int) entry->index,
465 gh->service);
466 gh->cb (gh->cb_cls,
467 entry->handle_core,
468 entry->handle_transport,
469 entry->handle_ats_connectivity,
470 entry->peer_identity,
471 entry->cfg);
472}
473
474
475/**
476 * Function called from peer connect notify callbacks from CORE and TRANSPORT
477 * connections. This function calls the pending peer connect notify callbacks
478 * which are queued in an entry.
479 *
480 * @param cls the #PooledConnection object
481 * @param peer the peer that connected
482 * @param service the service where this notification has originated
483 */
484static void
485peer_connect_notify_cb (void *cls,
486 const struct GNUNET_PeerIdentity *peer,
487 const enum GST_ConnectionPool_Service service)
488{
489 struct PooledConnection *entry = cls;
490 struct GST_ConnectionPool_GetHandle *gh;
491 struct GST_ConnectionPool_GetHandle *gh_next;
492 GST_connection_pool_peer_connect_notify cb;
493 void *cb_cls;
494
495 for (gh = entry->head_notify; NULL != gh;)
496 {
497 GNUNET_assert (NULL != gh->target);
498 GNUNET_assert (NULL != gh->connect_notify_cb);
499 GNUNET_assert (gh->connection_ready_called);
500 if (service != gh->service)
501 {
502 gh = gh->next;
503 continue;
504 }
505 if (0 != memcmp (gh->target, peer, sizeof(struct GNUNET_PeerIdentity)))
506 {
507 gh = gh->next;
508 continue;
509 }
510 cb = gh->connect_notify_cb;
511 cb_cls = gh->connect_notify_cb_cls;
512 gh_next = gh->next;
513 GNUNET_CONTAINER_DLL_remove (entry->head_notify, entry->tail_notify, gh);
514 gh->notify_waiting = 0;
515 LOG_DEBUG ("Peer connected to peer %u at service %u\n",
516 entry->index,
517 gh->service);
518 gh = gh_next;
519 cb (cb_cls, peer);
520 }
521}
522
523
524/**
525 * Function called to notify transport users that another
526 * peer connected to us.
527 *
528 * @param cls the #PooledConnection object
529 * @param peer the peer that connected
530 * @param mq queue for sending data to @a peer
531 * @return NULL
532 */
533static void *
534transport_peer_connect_notify_cb (void *cls,
535 const struct GNUNET_PeerIdentity *peer,
536 struct GNUNET_MQ_Handle *mq)
537{
538 struct PooledConnection *entry = cls;
539
540 peer_connect_notify_cb (entry, peer, GST_CONNECTIONPOOL_SERVICE_TRANSPORT);
541 return NULL;
542}
543
544
545/**
546 * Function called when resources for opening a connection to TRANSPORT are
547 * available.
548 *
549 * @param cls the #PooledConnection object
550 */
551static void
552opstart_get_handle_transport (void *cls)
553{
554 struct PooledConnection *entry = cls;
555
556 GNUNET_assert (NULL != entry);
557 LOG_DEBUG ("Opening a transport connection to peer %u\n", entry->index);
558 entry->handle_transport =
559 GNUNET_TRANSPORT_core_connect (entry->cfg,
560 NULL,
561 NULL,
562 entry,
563 &transport_peer_connect_notify_cb,
564 NULL,
565 NULL);
566 if (NULL == entry->handle_transport)
567 {
568 GNUNET_break (0);
569 return;
570 }
571 if (0 == entry->demand)
572 return;
573 if (NULL != entry->notify_task)
574 return;
575 if (NULL != search_waiting (entry, entry->head_waiting))
576 {
577 entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
578 return;
579 }
580}
581
582
583/**
584 * Function called when the operation responsible for opening a TRANSPORT
585 * connection is marked as done.
586 *
587 * @param cls the cache entry
588 */
589static void
590oprelease_get_handle_transport (void *cls)
591{
592 struct PooledConnection *entry = cls;
593
594 if (NULL == entry->handle_transport)
595 return;
596 GNUNET_TRANSPORT_core_disconnect (entry->handle_transport);
597 entry->handle_transport = NULL;
598}
599
600
601/**
602 * Method called whenever a given peer connects at CORE level
603 *
604 * @param cls the #PooledConnection object
605 * @param peer peer identity this notification is about
606 * @param mq message queue for talking to @a peer
607 * @return peer
608 */
609static void *
610core_peer_connect_cb (void *cls,
611 const struct GNUNET_PeerIdentity *peer,
612 struct GNUNET_MQ_Handle *mq)
613{
614 struct PooledConnection *entry = cls;
615
616 peer_connect_notify_cb (entry, peer, GST_CONNECTIONPOOL_SERVICE_CORE);
617 return (void *) peer;
618}
619
620
621/**
622 * Function called after #GNUNET_CORE_connect() has succeeded (or failed
623 * for good). Note that the private key of the peer is intentionally
624 * not exposed here; if you need it, your process should try to read
625 * the private key file directly (which should work if you are
626 * authorized...). Implementations of this function must not call
627 * #GNUNET_CORE_disconnect() (other than by scheduling a new task to
628 * do this later).
629 *
630 * @param cls the #PooledConnection object
631 * @param my_identity ID of this peer, NULL if we failed
632 */
633static void
634core_startup_cb (void *cls,
635 const struct GNUNET_PeerIdentity *my_identity)
636{
637 struct PooledConnection *entry = cls;
638
639 if (NULL == my_identity)
640 {
641 GNUNET_break (0);
642 return;
643 }
644 GNUNET_assert (NULL == entry->peer_identity);
645 entry->peer_identity = GNUNET_new (struct GNUNET_PeerIdentity);
646 *entry->peer_identity = *my_identity;
647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
648 "Established CORE connection for peer %s (%u)\n",
649 GNUNET_i2s (my_identity),
650 (unsigned int) entry->index);
651 if (0 == entry->demand)
652 return;
653 if (NULL != entry->notify_task)
654 return;
655 if (NULL != search_waiting (entry, entry->head_waiting))
656 {
657 entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
658 return;
659 }
660}
661
662
663/**
664 * Function called when resources for opening a connection to CORE are
665 * available.
666 *
667 * @param cls the #PooledConnection object
668 */
669static void
670opstart_get_handle_core (void *cls)
671{
672 struct PooledConnection *entry = cls;
673
674 GNUNET_assert (NULL != entry);
675 LOG_DEBUG ("Opening a CORE connection to peer %u\n", entry->index);
676 entry->handle_core =
677 GNUNET_CORE_connect (entry->cfg,
678 entry, /* closure */
679 &core_startup_cb, /* core startup notify */
680 &core_peer_connect_cb, /* peer connect notify */
681 NULL, /* peer disconnect notify */
682 NULL);
683}
684
685
686/**
687 * Function called when the operation responsible for opening a CORE
688 * connection is marked as done.
689 *
690 * @param cls the #PooledConnection object
691 */
692static void
693oprelease_get_handle_core (void *cls)
694{
695 struct PooledConnection *entry = cls;
696
697 if (NULL == entry->handle_core)
698 return;
699 GNUNET_CORE_disconnect (entry->handle_core);
700 entry->handle_core = NULL;
701 GNUNET_free (entry->peer_identity);
702 entry->peer_identity = NULL;
703}
704
705
706/**
707 * Function called when resources for opening a connection to ATS are
708 * available.
709 *
710 * @param cls the #PooledConnection object
711 */
712static void
713opstart_get_handle_ats_connectivity (void *cls)
714{
715 struct PooledConnection *entry = cls;
716
717 entry->handle_ats_connectivity = GNUNET_ATS_connectivity_init (entry->cfg);
718}
719
720
721/**
722 * Function called when the operation responsible for opening a ATS
723 * connection is marked as done.
724 *
725 * @param cls the #PooledConnection object
726 */
727static void
728oprelease_get_handle_ats_connectivity (void *cls)
729{
730 struct PooledConnection *entry = cls;
731
732 if (NULL == entry->handle_ats_connectivity)
733 return;
734 GNUNET_ATS_connectivity_done (entry->handle_ats_connectivity);
735 entry->handle_ats_connectivity = NULL;
736}
737
738
739/**
740 * This function will be called for every #PooledConnection object in @p map
741 *
742 * @param cls NULL
743 * @param key current key code
744 * @param value the #PooledConnection object
745 * @return #GNUNET_YES if we should continue to
746 * iterate,
747 * #GNUNET_NO if not.
748 */
749static int
750cleanup_iterator (void *cls, uint32_t key, void *value)
751{
752 struct PooledConnection *entry = value;
753
754 GNUNET_assert (NULL != entry);
755 destroy_pooled_connection (entry);
756 return GNUNET_YES;
757}
758
759
760/**
761 * Initialise the connection pool.
762 *
763 * @param size the size of the connection pool. Each entry in the connection
764 * pool can handle a connection to each of the services enumerated in
765 * #GST_ConnectionPool_Service
766 */
767void
768GST_connection_pool_init (unsigned int size)
769{
770 max_size = size;
771 if (0 == max_size)
772 return;
773 GNUNET_assert (NULL == map);
774 map = GNUNET_CONTAINER_multihashmap32_create (((size * 3) / 4) + 1);
775}
776
777
778/**
779 * Cleanup the connection pool
780 */
781void
782GST_connection_pool_destroy ()
783{
784 struct PooledConnection *entry;
785
786 if (NULL != map)
787 {
788 GNUNET_assert (
789 GNUNET_SYSERR !=
790 GNUNET_CONTAINER_multihashmap32_iterate (map, &cleanup_iterator, NULL));
791 GNUNET_CONTAINER_multihashmap32_destroy (map);
792 map = NULL;
793 }
794 while (NULL != (entry = head_lru))
795 {
796 GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
797 destroy_pooled_connection (entry);
798 }
799 GNUNET_assert (NULL == head_not_pooled);
800}
801
802
803/**
804 * Get a connection handle to @a service. If the connection is opened before
805 * and the connection handle is present in the connection pool, it is returned
806 * through @a cb. @a peer_id is used for the lookup in the connection pool. If
807 * the connection handle is not present in the connection pool, a new connection
808 * handle is opened for the @a service using @a cfg. Additionally, @a target,
809 * @a connect_notify_cb can be specified to get notified when @a target is
810 * connected at @a service.
811 *
812 * @note @a connect_notify_cb will not be called if @a target is
813 * already connected @a service level. Use
814 * GNUNET_TRANSPORT_check_peer_connected() or a similar function from the
815 * respective @a service's API to check if the target peer is already connected
816 * or not. @a connect_notify_cb will be called only once or never (in case @a
817 * target cannot be connected or is already connected).
818 *
819 * @param peer_id the index of the peer
820 * @param cfg the configuration with which the transport handle has to be
821 * created if it was not present in the cache
822 * @param service the service of interest
823 * @param cb the callback to notify when the transport handle is available
824 * @param cb_cls the closure for @a cb
825 * @param target the peer identify of the peer whose connection to our TRANSPORT
826 * subsystem will be notified through the @a connect_notify_cb. Can be
827 * NULL
828 * @param connect_notify_cb the callback to call when the @a target peer is
829 * connected. This callback will only be called once or never again (in
830 * case the target peer cannot be connected). Can be NULL
831 * @param connect_notify_cb_cls the closure for @a connect_notify_cb
832 * @return the handle which can be used cancel or mark that the handle is no
833 * longer being used
834 */
835struct GST_ConnectionPool_GetHandle *
836GST_connection_pool_get_handle (
837 unsigned int peer_id,
838 const struct GNUNET_CONFIGURATION_Handle *cfg,
839 enum GST_ConnectionPool_Service service,
840 GST_connection_pool_connection_ready_cb cb,
841 void *cb_cls,
842 const struct GNUNET_PeerIdentity *target,
843 GST_connection_pool_peer_connect_notify connect_notify_cb,
844 void *connect_notify_cb_cls)
845{
846 struct GST_ConnectionPool_GetHandle *gh;
847 struct PooledConnection *entry;
848 struct GNUNET_TESTBED_Operation *op;
849 void *handle;
850 uint32_t peer_id32;
851
852 peer_id32 = (uint32_t) peer_id;
853 handle = NULL;
854 entry = NULL;
855 if (NULL != map)
856 entry = GNUNET_CONTAINER_multihashmap32_get (map, peer_id32);
857 if (NULL != entry)
858 {
859 if (entry->in_lru)
860 {
861 GNUNET_assert (0 == entry->demand);
862 expire_task_cancel (entry);
863 GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
864 entry->in_lru = GNUNET_NO;
865 }
866 switch (service)
867 {
868 case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
869 handle = entry->handle_transport;
870 if (NULL != handle)
871 LOG_DEBUG ("Found TRANSPORT handle for peer %u\n",
872 entry->index);
873 break;
874 case GST_CONNECTIONPOOL_SERVICE_CORE:
875 handle = entry->handle_core;
876 if (NULL != handle)
877 LOG_DEBUG ("Found CORE handle for peer %u\n",
878 entry->index);
879 break;
880 case GST_CONNECTIONPOOL_SERVICE_ATS_CONNECTIVITY:
881 handle = entry->handle_ats_connectivity;
882 if (NULL != handle)
883 LOG_DEBUG ("Found ATS CONNECTIVITY handle for peer %u\n",
884 entry->index);
885 break;
886 }
887 }
888 else
889 {
890 entry = GNUNET_new (struct PooledConnection);
891 entry->index = peer_id32;
892 if ((NULL != map) &&
893 (GNUNET_CONTAINER_multihashmap32_size (map) < max_size))
894 {
895 GNUNET_assert (GNUNET_OK ==
896 GNUNET_CONTAINER_multihashmap32_put (
897 map,
898 entry->index,
899 entry,
900 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
901 entry->in_pool = GNUNET_YES;
902 }
903 else
904 {
905 GNUNET_CONTAINER_DLL_insert_tail (head_not_pooled,
906 tail_not_pooled,
907 entry);
908 }
909 entry->cfg = GNUNET_CONFIGURATION_dup (cfg);
910 }
911 entry->demand++;
912 gh = GNUNET_new (struct GST_ConnectionPool_GetHandle);
913 gh->entry = entry;
914 gh->cb = cb;
915 gh->cb_cls = cb_cls;
916 gh->target = target;
917 gh->connect_notify_cb = connect_notify_cb;
918 gh->connect_notify_cb_cls = connect_notify_cb_cls;
919 gh->service = service;
920 GNUNET_CONTAINER_DLL_insert (entry->head_waiting,
921 entry->tail_waiting,
922 gh);
923 if (NULL != handle)
924 {
925 if (NULL == entry->notify_task)
926 {
927 if (NULL != search_waiting (entry, entry->head_waiting))
928 entry->notify_task =
929 GNUNET_SCHEDULER_add_now (&connection_ready, entry);
930 }
931 return gh;
932 }
933 op = NULL;
934 switch (gh->service)
935 {
936 case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
937 if (NULL != entry->op_transport)
938 return gh; /* Operation pending */
939 op = GNUNET_TESTBED_operation_create_ (entry,
940 &opstart_get_handle_transport,
941 &oprelease_get_handle_transport);
942 entry->op_transport = op;
943 break;
944
945 case GST_CONNECTIONPOOL_SERVICE_CORE:
946 if (NULL != entry->op_core)
947 return gh; /* Operation pending */
948 op = GNUNET_TESTBED_operation_create_ (entry,
949 &opstart_get_handle_core,
950 &oprelease_get_handle_core);
951 entry->op_core = op;
952 break;
953
954 case GST_CONNECTIONPOOL_SERVICE_ATS_CONNECTIVITY:
955 if (NULL != entry->op_ats_connectivity)
956 return gh; /* Operation pending */
957 op =
958 GNUNET_TESTBED_operation_create_ (entry,
959 &opstart_get_handle_ats_connectivity,
960 &oprelease_get_handle_ats_connectivity);
961 entry->op_ats_connectivity = op;
962 break;
963 }
964 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, op);
965 GNUNET_TESTBED_operation_begin_wait_ (op);
966 return gh;
967}
968
969
970/**
971 * Relinquish a #GST_ConnectionPool_GetHandle object. If the connection
972 * associated with the object is currently being used by other
973 * #GST_ConnectionPool_GetHandle objects, it is left in the connection pool. If
974 * no other objects are using the connection and the connection pool is not full
975 * then it is placed in a LRU queue. If the connection pool is full, then
976 * connections from the LRU queue are evicted and closed to create place for
977 * this connection. If the connection pool if full and the LRU queue is empty,
978 * then the connection is closed.
979 *
980 * @param gh the handle
981 */
982void
983GST_connection_pool_get_handle_done (struct GST_ConnectionPool_GetHandle *gh)
984{
985 struct PooledConnection *entry;
986
987 if (NULL == gh)
988 return;
989 entry = gh->entry;
990 LOG_DEBUG ("Cleaning up get handle %p for service %u, peer %u\n",
991 gh,
992 gh->service,
993 entry->index);
994 if (! gh->connection_ready_called)
995 {
996 GNUNET_CONTAINER_DLL_remove (entry->head_waiting, entry->tail_waiting, gh);
997 if ((NULL == search_waiting (entry, entry->head_waiting)) &&
998 (NULL != entry->notify_task))
999 {
1000 GNUNET_SCHEDULER_cancel (entry->notify_task);
1001 entry->notify_task = NULL;
1002 }
1003 }
1004 if (gh->notify_waiting)
1005 {
1006 GNUNET_CONTAINER_DLL_remove (entry->head_notify, entry->tail_notify, gh);
1007 gh->notify_waiting = 0;
1008 }
1009 GNUNET_free (gh);
1010 gh = NULL;
1011 GNUNET_assert (! entry->in_lru);
1012 if (! entry->in_pool)
1013 GNUNET_CONTAINER_DLL_remove (head_not_pooled, tail_not_pooled, entry);
1014 if (NULL != map)
1015 {
1016 if (GNUNET_YES ==
1017 GNUNET_CONTAINER_multihashmap32_contains (map, entry->index))
1018 goto unallocate;
1019 if (GNUNET_CONTAINER_multihashmap32_size (map) == max_size)
1020 {
1021 if (NULL == head_lru)
1022 goto unallocate;
1023 destroy_pooled_connection (head_lru);
1024 }
1025 GNUNET_assert (GNUNET_OK ==
1026 GNUNET_CONTAINER_multihashmap32_put (
1027 map,
1028 entry->index,
1029 entry,
1030 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1031 entry->in_pool = GNUNET_YES;
1032 }
1033
1034unallocate:
1035 GNUNET_assert (0 < entry->demand);
1036 entry->demand--;
1037 if (0 != entry->demand)
1038 return;
1039 if (entry->in_pool)
1040 {
1041 add_to_lru (entry);
1042 return;
1043 }
1044 destroy_pooled_connection (entry);
1045}
diff --git a/src/testbed/gnunet-service-testbed_connectionpool.h b/src/testbed/gnunet-service-testbed_connectionpool.h
deleted file mode 100644
index cbab151be..000000000
--- a/src/testbed/gnunet-service-testbed_connectionpool.h
+++ /dev/null
@@ -1,172 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2015 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_connectionpool.h
23 * @brief Interface for connection pooling subroutines
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26#include "gnunet_ats_service.h"
27#include "gnunet_core_service.h"
28#include "gnunet_transport_service.h"
29
30/**
31 * The request handle for obtaining a pooled connection
32 */
33struct GST_ConnectionPool_GetHandle;
34
35
36/**
37 * The type of service
38 */
39enum GST_ConnectionPool_Service
40{
41 /**
42 * Transport service
43 */
44 GST_CONNECTIONPOOL_SERVICE_TRANSPORT = 1,
45
46 /**
47 * Core service
48 */
49 GST_CONNECTIONPOOL_SERVICE_CORE,
50
51 /**
52 * ATS service
53 */
54 GST_CONNECTIONPOOL_SERVICE_ATS_CONNECTIVITY
55};
56
57
58/**
59 * Initialise the connection pool.
60 *
61 * @param size the size of the connection pool. Each entry in the connection
62 * pool can handle a connection to each of the services enumerated in
63 * #GST_ConnectionPool_Service
64 */
65void
66GST_connection_pool_init (unsigned int size);
67
68
69/**
70 * Cleanup the connection pool
71 */
72void
73GST_connection_pool_destroy (void);
74
75/**
76 * Functions of this type are called when the needed handle is available for
77 * usage. These functions are to be registered with the function
78 * GST_connection_pool_get_handle(). The corresponding handles will be set upon
79 * success. If they are not set, then it signals an error while opening the
80 * handles.
81 *
82 * @param cls the closure passed to GST_connection_pool_get_handle()
83 * @param ch the handle to CORE. Can be NULL if it is not requested
84 * @param th the handle to TRANSPORT. Can be NULL if it is not requested
85 * @param ac the handle to ATS, can be NULL if it is not requested
86 * @param peer_id the identity of the peer. Will be NULL if ch is NULL. In other
87 * cases, its value being NULL means that CORE connection has failed.
88 * @param cfg configuration of the peer
89 */
90typedef void (*GST_connection_pool_connection_ready_cb) (
91 void *cls,
92 struct GNUNET_CORE_Handle *ch,
93 struct GNUNET_TRANSPORT_CoreHandle *th,
94 struct GNUNET_ATS_ConnectivityHandle *ac,
95 const struct GNUNET_PeerIdentity *peer_id,
96 const struct GNUNET_CONFIGURATION_Handle *cfg);
97
98
99/**
100 * Callback to notify when the target peer given to
101 * GST_connection_pool_get_handle() is connected.
102 *
103 * @param cls the closure given to GST_connection_pool_get_handle() for this
104 * callback
105 * @param target the peer identity of the target peer
106 */
107typedef void (*GST_connection_pool_peer_connect_notify) (
108 void *cls,
109 const struct GNUNET_PeerIdentity *target);
110
111
112/**
113 * Get a connection handle to @a service. If the connection is opened before
114 * and the connection handle is present in the connection pool, it is returned
115 * through @a cb. @a peer_id is used for the lookup in the connection pool. If
116 * the connection handle is not present in the connection pool, a new connection
117 * handle is opened for the @a service using @a cfg. Additionally, @a target,
118 * @a connect_notify_cb can be specified to get notified when @a target is
119 * connected at @a service.
120 *
121 * @note @a connect_notify_cb will not be called if @a target is
122 * already connected @a service level. Use
123 * GNUNET_TRANSPORT_check_peer_connected() or a similar function from the
124 * respective @a service's API to check if the target peer is already connected
125 * or not. @a connect_notify_cb will be called only once or never (in case @a
126 * target cannot be connected or is already connected).
127 *
128 * @param peer_id the index of the peer
129 * @param cfg the configuration with which the transport handle has to be
130 * created if it was not present in the cache
131 * @param service the service of interest
132 * @param cb the callback to notify when the transport handle is available
133 * @param cb_cls the closure for @a cb
134 * @param target the peer identify of the peer whose connection to our TRANSPORT
135 * subsystem will be notified through the @a connect_notify_cb. Can be
136 * NULL
137 * @param connect_notify_cb the callback to call when the @a target peer is
138 * connected. This callback will only be called once or never again (in
139 * case the target peer cannot be connected). Can be NULL
140 * @param connect_notify_cb_cls the closure for @a connect_notify_cb
141 * @return the handle which can be used cancel or mark that the handle is no
142 * longer being used
143 */
144struct GST_ConnectionPool_GetHandle *
145GST_connection_pool_get_handle (
146 unsigned int peer_id,
147 const struct GNUNET_CONFIGURATION_Handle *cfg,
148 enum GST_ConnectionPool_Service service,
149 GST_connection_pool_connection_ready_cb cb,
150 void *cb_cls,
151 const struct GNUNET_PeerIdentity *target,
152 GST_connection_pool_peer_connect_notify connect_notify_cb,
153 void *connect_notify_cb_cls);
154
155
156/**
157 * Relinquish a #GST_ConnectionPool_GetHandle object. If the connection
158 * associated with the object is currently being used by other
159 * #GST_ConnectionPool_GetHandle objects, it is left in the connection pool. If
160 * no other objects are using the connection and the connection pool is not full
161 * then it is placed in a LRU queue. If the connection pool is full, then
162 * connections from the LRU queue are evicted and closed to create place for
163 * this connection. If the connection pool if full and the LRU queue is empty,
164 * then the connection is closed.
165 *
166 * @param gh the handle
167 */
168void
169GST_connection_pool_get_handle_done (struct GST_ConnectionPool_GetHandle *gh);
170
171
172/* End of gnunet-service-testbed_connectionpool.h */
diff --git a/src/testbed/gnunet-service-testbed_cpustatus.c b/src/testbed/gnunet-service-testbed_cpustatus.c
deleted file mode 100644
index 5b9528ba3..000000000
--- a/src/testbed/gnunet-service-testbed_cpustatus.c
+++ /dev/null
@@ -1,664 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_cpustatus.c
23 * @brief calls to determine current CPU load
24 * @author Tzvetan Horozov
25 * @author Christian Grothoff
26 * @author Igor Wronsky
27 * @author Alex Harper (OS X portion)
28 * @author Sree Harsha Totakura
29 */
30
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet-service-testbed_meminfo.h"
34
35#if SOLARIS
36#if HAVE_KSTAT_H
37#include <kstat.h>
38#endif
39#if HAVE_SYS_SYSINFO_H
40#include <sys/sysinfo.h>
41#endif
42#if HAVE_KVM_H
43#include <kvm.h>
44#endif
45#endif
46#ifdef BSD
47#if HAVE_KVM_H
48#include <kvm.h>
49#endif
50#endif
51
52#ifdef OSX
53#include <mach/mach.h>
54
55static processor_cpu_load_info_t prev_cpu_load;
56#endif
57
58#define DEBUG_STATUSCALLS GNUNET_NO
59
60#ifdef __linux__
61static FILE *proc_stat;
62#endif
63
64/**
65 * Current CPU load, as percentage of CPU cycles not idle or
66 * blocked on IO.
67 */
68static int currentCPULoad;
69
70static double agedCPULoad = -1;
71
72/**
73 * Current IO load, as percentage of CPU cycles blocked on IO.
74 */
75static int currentIOLoad;
76
77static double agedIOLoad = -1;
78
79
80/**
81 * handle to the file to write the load statistics to
82 */
83struct GNUNET_BIO_WriteHandle *bw;
84
85struct GNUNET_SCHEDULER_Task *sample_load_task_id;
86
87
88#ifdef OSX
89static int
90initMachCpuStats ()
91{
92 unsigned int cpu_count;
93 processor_cpu_load_info_t cpu_load;
94 mach_msg_type_number_t cpu_msg_count;
95 kern_return_t kret;
96 int i, j;
97
98 kret = host_processor_info (mach_host_self (),
99 PROCESSOR_CPU_LOAD_INFO,
100 &cpu_count,
101 (processor_info_array_t *) &cpu_load,
102 &cpu_msg_count);
103 if (kret != KERN_SUCCESS)
104 {
105 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
106 return GNUNET_SYSERR;
107 }
108 prev_cpu_load = GNUNET_malloc (cpu_count * sizeof(*prev_cpu_load));
109 for (i = 0; i < cpu_count; i++)
110 {
111 for (j = 0; j < CPU_STATE_MAX; j++)
112 {
113 prev_cpu_load[i].cpu_ticks[j] = cpu_load[i].cpu_ticks[j];
114 }
115 }
116 vm_deallocate (mach_task_self (),
117 (vm_address_t) cpu_load,
118 (vm_size_t) (cpu_msg_count * sizeof(*cpu_load)));
119 return GNUNET_OK;
120}
121
122
123#endif
124
125/**
126 * Update the currentCPU and currentIO load (and on Linux, memory) values.
127 *
128 * Before its first invocation the method initStatusCalls() must be called.
129 * If there is an error the method returns -1.
130 */
131static int
132updateUsage ()
133{
134 currentIOLoad = -1;
135 currentCPULoad = -1;
136#ifdef __linux__
137 /* under linux, first try %idle/usage using /proc/stat;
138 if that does not work, disable /proc/stat for the future
139 by closing the file and use the next-best method. */
140 if (proc_stat != NULL)
141 {
142 static unsigned long long last_cpu_results[5] = { 0, 0, 0, 0, 0 };
143 static int have_last_cpu = GNUNET_NO;
144 int ret;
145 char line[256];
146 unsigned long long user_read, system_read, nice_read, idle_read,
147 iowait_read;
148 unsigned long long user, system, nice, idle, iowait;
149 unsigned long long usage_time = 0, total_time = 1;
150
151 /* Get the first line with the data */
152 rewind (proc_stat);
153 fflush (proc_stat);
154 if (NULL == fgets (line, 256, proc_stat))
155 {
156 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
157 "fgets", "/proc/stat");
158 proc_stat = NULL; /* don't try again */
159 }
160 else
161 {
162 iowait_read = 0;
163 ret = sscanf (line, "%*s %llu %llu %llu %llu %llu",
164 &user_read,
165 &system_read, &nice_read, &idle_read, &iowait_read);
166 if (ret < 4)
167 {
168 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
169 "fgets-sscanf", "/proc/stat");
170 fclose (proc_stat);
171 proc_stat = NULL; /* don't try again */
172 have_last_cpu = GNUNET_NO;
173 }
174 else
175 {
176 /* Store the current usage */
177 user = user_read - last_cpu_results[0];
178 system = system_read - last_cpu_results[1];
179 nice = nice_read - last_cpu_results[2];
180 idle = idle_read - last_cpu_results[3];
181 iowait = iowait_read - last_cpu_results[4];
182 /* Calculate the % usage */
183 usage_time = user + system + nice;
184 total_time = usage_time + idle + iowait;
185 if ((total_time > 0) && (have_last_cpu == GNUNET_YES))
186 {
187 currentCPULoad = (int) (100L * usage_time / total_time);
188 if (ret > 4)
189 currentIOLoad = (int) (100L * iowait / total_time);
190 else
191 currentIOLoad = -1; /* 2.4 kernel */
192 }
193 /* Store the values for the next calculation */
194 last_cpu_results[0] = user_read;
195 last_cpu_results[1] = system_read;
196 last_cpu_results[2] = nice_read;
197 last_cpu_results[3] = idle_read;
198 last_cpu_results[4] = iowait_read;
199 have_last_cpu = GNUNET_YES;
200 return GNUNET_OK;
201 }
202 }
203 }
204#endif
205
206#ifdef OSX
207 {
208 unsigned int cpu_count;
209 processor_cpu_load_info_t cpu_load;
210 mach_msg_type_number_t cpu_msg_count;
211 unsigned long long t_sys, t_user, t_nice, t_idle, t_total;
212 unsigned long long t_idle_all, t_total_all;
213 kern_return_t kret;
214 int i, j;
215
216 t_idle_all = t_total_all = 0;
217 kret = host_processor_info (mach_host_self (), PROCESSOR_CPU_LOAD_INFO,
218 &cpu_count,
219 (processor_info_array_t *) &cpu_load,
220 &cpu_msg_count);
221 if (kret == KERN_SUCCESS)
222 {
223 for (i = 0; i < cpu_count; i++)
224 {
225 if (cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] >=
226 prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM])
227 {
228 t_sys = cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM]
229 - prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM];
230 }
231 else
232 {
233 t_sys = cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM]
234 + (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM]
235 + 1);
236 }
237
238 if (cpu_load[i].cpu_ticks[CPU_STATE_USER] >=
239 prev_cpu_load[i].cpu_ticks[CPU_STATE_USER])
240 {
241 t_user = cpu_load[i].cpu_ticks[CPU_STATE_USER]
242 - prev_cpu_load[i].cpu_ticks[CPU_STATE_USER];
243 }
244 else
245 {
246 t_user = cpu_load[i].cpu_ticks[CPU_STATE_USER]
247 + (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_USER]
248 + 1);
249 }
250
251 if (cpu_load[i].cpu_ticks[CPU_STATE_NICE] >=
252 prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE])
253 {
254 t_nice = cpu_load[i].cpu_ticks[CPU_STATE_NICE]
255 - prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE];
256 }
257 else
258 {
259 t_nice = cpu_load[i].cpu_ticks[CPU_STATE_NICE]
260 + (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE]
261 + 1);
262 }
263
264 if (cpu_load[i].cpu_ticks[CPU_STATE_IDLE] >=
265 prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE])
266 {
267 t_idle = cpu_load[i].cpu_ticks[CPU_STATE_IDLE]
268 - prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE];
269 }
270 else
271 {
272 t_idle = cpu_load[i].cpu_ticks[CPU_STATE_IDLE]
273 + (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE]
274 + 1);
275 }
276 t_total = t_sys + t_user + t_nice + t_idle;
277 t_idle_all += t_idle;
278 t_total_all += t_total;
279 }
280 for (i = 0; i < cpu_count; i++)
281 {
282 for (j = 0; j < CPU_STATE_MAX; j++)
283 {
284 prev_cpu_load[i].cpu_ticks[j] = cpu_load[i].cpu_ticks[j];
285 }
286 }
287 if (t_total_all > 0)
288 currentCPULoad = 100 - (100 * t_idle_all) / t_total_all;
289 else
290 currentCPULoad = -1;
291 vm_deallocate (mach_task_self (),
292 (vm_address_t) cpu_load,
293 (vm_size_t) (cpu_msg_count * sizeof(*cpu_load)));
294 currentIOLoad = -1; /* FIXME-OSX! */
295 return GNUNET_OK;
296 }
297 else
298 {
299 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
300 return GNUNET_SYSERR;
301 }
302 }
303#endif
304 /* try kstat (Solaris only) */
305#if SOLARIS && HAVE_KSTAT_H && HAVE_SYS_SYSINFO_H
306 {
307 static long long last_idlecount;
308 static long long last_totalcount;
309 static int kstat_once; /* if open fails, don't keep
310 trying */
311 kstat_ctl_t *kc;
312 kstat_t *khelper;
313 long long idlecount;
314 long long totalcount;
315 long long deltaidle;
316 long long deltatotal;
317
318 if (kstat_once == 1)
319 goto ABORT_KSTAT;
320 kc = kstat_open ();
321 if (kc == NULL)
322 {
323 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");
324 goto ABORT_KSTAT;
325 }
326
327 idlecount = 0;
328 totalcount = 0;
329 for (khelper = kc->kc_chain; khelper != NULL; khelper = khelper->ks_next)
330 {
331 cpu_stat_t stats;
332
333 if (0 != strncmp (khelper->ks_name, "cpu_stat", strlen ("cpu_stat")))
334 continue;
335 if (khelper->ks_data_size > sizeof(cpu_stat_t))
336 continue; /* better save then sorry! */
337 if (-1 != kstat_read (kc, khelper, &stats))
338 {
339 idlecount += stats.cpu_sysinfo.cpu[CPU_IDLE];
340 totalcount
341 += stats.cpu_sysinfo.cpu[CPU_IDLE]
342 + stats.cpu_sysinfo.cpu[CPU_USER]
343 + stats.cpu_sysinfo.cpu[CPU_KERNEL]
344 + stats.cpu_sysinfo.cpu[CPU_WAIT];
345 }
346 }
347 if (0 != kstat_close (kc))
348 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");
349 if ((idlecount == 0) && (totalcount == 0))
350 goto ABORT_KSTAT; /* no stats found => abort */
351 deltaidle = idlecount - last_idlecount;
352 deltatotal = totalcount - last_totalcount;
353 if ((deltatotal > 0) && (last_totalcount > 0))
354 {
355 currentCPULoad = (unsigned int) (100.0 * deltaidle / deltatotal);
356 if (currentCPULoad > 100)
357 currentCPULoad = 100; /* odd */
358 if (currentCPULoad < 0)
359 currentCPULoad = 0; /* odd */
360 currentCPULoad = 100 - currentCPULoad; /* computed idle-load before! */
361 }
362 else
363 currentCPULoad = -1;
364 currentIOLoad = -1; /* FIXME-SOLARIS! */
365 last_idlecount = idlecount;
366 last_totalcount = totalcount;
367 return GNUNET_OK;
368ABORT_KSTAT:
369 kstat_once = 1; /* failed, don't try again */
370 return GNUNET_SYSERR;
371 }
372#endif
373
374 /* insert methods better than getloadavg for
375 other platforms HERE! */
376
377 /* ok, maybe we have getloadavg on this platform */
378#if HAVE_GETLOADAVG
379 {
380 static int warnOnce = 0;
381 double loadavg;
382 if (1 != getloadavg (&loadavg, 1))
383 {
384 /* only warn once, if there is a problem with
385 getloadavg, we're going to hit it frequently... */
386 if (warnOnce == 0)
387 {
388 warnOnce = 1;
389 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getloadavg");
390 }
391 return GNUNET_SYSERR;
392 }
393 else
394 {
395 /* success with getloadavg */
396 currentCPULoad = (int) (100 * loadavg);
397 currentIOLoad = -1; /* FIXME */
398 return GNUNET_OK;
399 }
400 }
401#endif
402
403 /* loadaverage not defined and no platform
404 specific alternative defined
405 => default: error
406 */
407 return GNUNET_SYSERR;
408}
409
410
411/**
412 * Update load values (if enough time has expired),
413 * including computation of averages. Code assumes
414 * that lock has already been obtained.
415 */
416static void
417updateAgedLoad ()
418{
419 static struct GNUNET_TIME_Absolute lastCall;
420 struct GNUNET_TIME_Relative age;
421
422 age = GNUNET_TIME_absolute_get_duration (lastCall);
423 if ((agedCPULoad == -1)
424 || (age.rel_value_us > 500000))
425 {
426 /* use smoothing, but do NOT update lastRet at frequencies higher
427 than 500ms; this makes the smoothing (mostly) independent from
428 the frequency at which getCPULoad is called (and we don't spend
429 more time measuring CPU than actually computing something). */
430 lastCall = GNUNET_TIME_absolute_get ();
431 updateUsage ();
432 if (currentCPULoad == -1)
433 {
434 agedCPULoad = -1;
435 }
436 else
437 {
438 if (agedCPULoad == -1)
439 {
440 agedCPULoad = currentCPULoad;
441 }
442 else
443 {
444 /* for CPU, we don't do the 'fast increase' since CPU is much
445 more jitterish to begin with */
446 agedCPULoad = (agedCPULoad * 31 + currentCPULoad) / 32;
447 }
448 }
449 if (currentIOLoad == -1)
450 {
451 agedIOLoad = -1;
452 }
453 else
454 {
455 if (agedIOLoad == -1)
456 {
457 agedIOLoad = currentIOLoad;
458 }
459 else
460 {
461 /* for IO, we don't do the 'fast increase' since IO is much
462 more jitterish to begin with */
463 agedIOLoad = (agedIOLoad * 31 + currentIOLoad) / 32;
464 }
465 }
466 }
467}
468
469
470/**
471 * Get the load of the CPU relative to what is allowed.
472 * @return the CPU load as a percentage of allowed
473 * (100 is equivalent to full load)
474 */
475static int
476cpu_get_load ()
477{
478 updateAgedLoad ();
479 return (int) agedCPULoad;
480}
481
482
483/**
484 * Get the load of the CPU relative to what is allowed.
485 * @return the CPU load as a percentage of allowed
486 * (100 is equivalent to full load)
487 */
488static int
489disk_get_load ()
490{
491 updateAgedLoad ();
492 return (int) agedIOLoad;
493}
494
495
496/**
497 * Get the percentage of memory used
498 *
499 * @return the percentage of memory used
500 */
501static unsigned int
502mem_get_usage ()
503{
504 double percentage;
505
506 meminfo ();
507 percentage = (((double) kb_main_used) / ((double) kb_main_total) * 100.0);
508 return (unsigned int) percentage;
509}
510
511
512#ifdef __linux__
513#include <dirent.h>
514/**
515 * Returns the number of processes
516 *
517 * @return the number of processes
518 */
519static unsigned int
520get_nproc ()
521{
522 DIR *dir;
523 struct dirent *ent;
524 unsigned int nproc;
525
526 dir = opendir ("/proc");
527 if (NULL == dir)
528 return 0;
529 nproc = 0;
530 while (NULL != (ent = readdir (dir)))
531 {
532 if ((*ent->d_name > '0') && (*ent->d_name <= '9'))
533 nproc++;
534 }
535 closedir (dir);
536 return nproc;
537}
538
539
540#endif
541
542
543static void
544sample_load_task (void *cls)
545{
546 struct GNUNET_TIME_Absolute now;
547 char *str;
548 int nbs;
549 int ld_cpu;
550 int ld_disk;
551 unsigned int mem_usage;
552 unsigned int nproc;
553
554 sample_load_task_id = NULL;
555 ld_cpu = cpu_get_load ();
556 ld_disk = disk_get_load ();
557 if ((-1 == ld_cpu) || (-1 == ld_disk))
558 goto reschedule;
559 mem_usage = mem_get_usage ();
560#ifdef __linux__
561 nproc = get_nproc ();
562#else
563 nproc = 0;
564#endif
565 now = GNUNET_TIME_absolute_get ();
566 nbs = GNUNET_asprintf (&str, "%llu %d %d %u %u\n", now.abs_value_us / 1000LL
567 / 1000LL,
568 ld_cpu, ld_disk, mem_usage, nproc);
569 if (0 < nbs)
570 {
571 GNUNET_BIO_write (bw, "sample load task", str, nbs);
572 }
573 else
574 GNUNET_break (0);
575 GNUNET_free (str);
576
577reschedule:
578 sample_load_task_id =
579 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
580 &sample_load_task, NULL);
581}
582
583
584/**
585 * Initialize logging CPU and IO statisticfs. Checks the configuration for
586 * "STATS_DIR" and logs to a file in that directory. The file is name is
587 * generated from the hostname and the process's PID.
588 */
589void
590GST_stats_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
591{
592 char *hostname;
593 char *stats_dir;
594 char *fn;
595 size_t len;
596
597 if (GNUNET_OK !=
598 GNUNET_CONFIGURATION_get_value_filename (cfg, "testbed",
599 "STATS_DIR", &stats_dir))
600 return;
601 len = GNUNET_OS_get_hostname_max_length ();
602 hostname = GNUNET_malloc (len);
603 if (0 != gethostname (hostname, len))
604 {
605 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "gethostname");
606 GNUNET_free (stats_dir);
607 GNUNET_free (hostname);
608 return;
609 }
610 fn = NULL;
611 (void) GNUNET_asprintf (&fn, "%s/%.*s-%jd.dat", stats_dir, (int)len,
612 hostname, (intmax_t) getpid ());
613 GNUNET_free (stats_dir);
614 GNUNET_free (hostname);
615 if (NULL == (bw = GNUNET_BIO_write_open_file (fn)))
616 {
617 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
618 _ ("Cannot open %s for writing load statistics. "
619 "Not logging load statistics\n"), fn);
620 GNUNET_free (fn);
621 return;
622 }
623 GNUNET_free (fn);
624 sample_load_task_id = GNUNET_SCHEDULER_add_now (&sample_load_task, NULL);
625#ifdef __linux__
626 proc_stat = fopen ("/proc/stat", "r");
627 if (NULL == proc_stat)
628 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
629 "fopen", "/proc/stat");
630#elif OSX
631 initMachCpuStats ();
632#endif
633 updateUsage (); /* initialize */
634}
635
636
637/**
638 * Shutdown the status calls module.
639 */
640void
641GST_stats_destroy ()
642{
643 if (NULL == bw)
644 return;
645#ifdef __linux__
646 if (proc_stat != NULL)
647 {
648 fclose (proc_stat);
649 proc_stat = NULL;
650 }
651#elif OSX
652 GNUNET_free (prev_cpu_load);
653#endif
654 if (NULL != sample_load_task_id)
655 {
656 GNUNET_SCHEDULER_cancel (sample_load_task_id);
657 sample_load_task_id = NULL;
658 }
659 GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bw, NULL));
660 bw = NULL;
661}
662
663
664/* end of cpustatus.c */
diff --git a/src/testbed/gnunet-service-testbed_links.c b/src/testbed/gnunet-service-testbed_links.c
deleted file mode 100644
index f4c27ffa2..000000000
--- a/src/testbed/gnunet-service-testbed_links.c
+++ /dev/null
@@ -1,1468 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_links.c
23 * @brief TESTBED service components that deals with starting slave controllers
24 * and establishing lateral links between controllers
25 * @author Sree Harsha Totakura
26 */
27
28#include "platform.h"
29#include "gnunet-service-testbed.h"
30
31/**
32 * Redefine LOG with a changed log component string
33 */
34#ifdef LOG
35#undef LOG
36#endif
37#define LOG(kind, ...) \
38 GNUNET_log_from (kind, "testbed-links", __VA_ARGS__)
39
40/**
41 * The event mask for the events we listen from sub-controllers
42 */
43#define EVENT_MASK (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED)
44
45
46/**
47 * States of LCFContext
48 */
49enum LCFContextState
50{
51 /**
52 * The Context has been initialized; Nothing has been done on it
53 */
54 INIT,
55
56 /**
57 * Delegated host has been registered at the forwarding controller
58 */
59 DELEGATED_HOST_REGISTERED,
60
61 /**
62 * The slave host has been registered at the forwarding controller
63 */
64 SLAVE_HOST_REGISTERED,
65
66 /**
67 * The context has been finished (may have error)
68 */
69 FINISHED
70};
71
72
73/**
74 * Link controllers request forwarding context
75 */
76struct LCFContext
77{
78 /**
79 * The LCFContext
80 */
81 struct LCFContext *next;
82
83 /**
84 * The LCFContext
85 */
86 struct LCFContext *prev;
87
88 /**
89 * The gateway which will pass the link message to delegated host
90 */
91 struct Slave *gateway;
92
93 /**
94 * The client which has asked to perform this operation
95 */
96 struct GNUNET_SERVICE_Client *client;
97
98 /**
99 * Handle for operations which are forwarded while linking controllers
100 */
101 struct GNUNET_TESTBED_Operation *op;
102
103 /**
104 * The timeout task
105 */
106 struct GNUNET_SCHEDULER_Task *timeout_task;
107
108 /**
109 * The id of the operation which created this context
110 */
111 uint64_t operation_id;
112
113 /**
114 * should the slave controller start the delegated controller?
115 */
116 int is_subordinate;
117
118 /**
119 * The state of this context
120 */
121 enum LCFContextState state;
122
123 /**
124 * The delegated host
125 */
126 uint32_t delegated_host_id;
127
128 /**
129 * The slave host
130 */
131 uint32_t slave_host_id;
132};
133
134
135/**
136 * Notification context to be used to notify when connection to the neighbour's
137 * controller is opened
138 */
139struct NeighbourConnectNotification
140{
141 /**
142 * DLL next for inclusion in neighbour's list of notification requests
143 */
144 struct NeighbourConnectNotification *next;
145
146 /**
147 * DLL prev
148 */
149 struct NeighbourConnectNotification *prev;
150
151 /**
152 * The neighbour
153 */
154 struct Neighbour *n;
155
156 /**
157 * The notification callback to call when we are connect to neighbour
158 */
159 GST_NeighbourConnectNotifyCallback cb;
160
161 /**
162 * The closure for the above callback
163 */
164 void *cb_cls;
165};
166
167
168/**
169 * A connected controller which is not our child
170 */
171struct Neighbour
172{
173 /**
174 * The controller handle
175 */
176 struct GNUNET_TESTBED_Controller *controller;
177
178 /**
179 * Operation handle for opening a lateral connection to another controller.
180 * Will be NULL if the slave controller is started by this controller
181 */
182 struct GNUNET_TESTBED_Operation *conn_op;
183
184 /**
185 * DLL head for the list of notification requests
186 */
187 struct NeighbourConnectNotification *nl_head;
188
189 /**
190 * DLL tail for the list of notification requests
191 */
192 struct NeighbourConnectNotification *nl_tail;
193
194 /**
195 * Task id for the task to call notifications from the notification list
196 */
197 struct GNUNET_SCHEDULER_Task *notify_task;
198
199 /**
200 * How many references are present currently to this neighbour's connection
201 */
202 unsigned int reference_cnt;
203
204 /**
205 * Is the conn_op inactivated?
206 */
207 unsigned int inactive;
208
209 /**
210 * The id of the host this controller is running on
211 */
212 uint32_t host_id;
213};
214
215
216/**
217 * The neighbour list
218 */
219static struct Neighbour **neighbour_list;
220
221/**
222 * The size of the neighbour list
223 */
224static unsigned int neighbour_list_size;
225
226
227/**
228 * Context information for establishing a link to neighbour (Used is
229 * GST_handle_link_controllers()
230 */
231struct NeighbourConnectCtxt
232{
233 /**
234 * DLL next for inclusion in the corresponding context list
235 */
236 struct NeighbourConnectCtxt *next;
237
238 /**
239 * DLL tail
240 */
241 struct NeighbourConnectCtxt *prev;
242
243 /**
244 * The neighbour to whom connection should be made
245 */
246 struct Neighbour *n;
247
248 /**
249 * The client requesting the connection
250 */
251 struct GNUNET_SERVICE_Client *client;
252
253 /**
254 * Task to be run upon timeout
255 */
256 struct GNUNET_SCHEDULER_Task *timeout_task;
257
258 /**
259 * The notification handle associated with the neighbour's connection request
260 */
261 struct NeighbourConnectNotification *nh;
262
263 /**
264 * The id of the link-controllers operation responsible for creating this
265 * context
266 */
267 uint64_t op_id;
268};
269
270/**
271 * DLL head for the list of neighbour connect contexts
272 */
273struct NeighbourConnectCtxt *ncc_head;
274
275/**
276 * DLL tail for the list of neighbour connect contexts
277 */
278struct NeighbourConnectCtxt *ncc_tail;
279
280/**
281 * A list of directly linked neighbours
282 */
283struct Slave **GST_slave_list;
284
285/**
286 * The size of directly linked neighbours list
287 */
288unsigned int GST_slave_list_size;
289
290/**
291 * A list of routes
292 */
293static struct Route **route_list;
294
295/**
296 * The LCF queue
297 */
298static struct LCFContext *lcf_head;
299
300/**
301 * The tail for the LCF queue
302 */
303static struct LCFContext *lcf_tail;
304
305/**
306 * The lcf_task handle
307 */
308static struct GNUNET_SCHEDULER_Task *lcf_proc_task_id;
309
310/**
311 * The size of the route list
312 */
313static unsigned int route_list_size;
314
315
316/**
317 * Adds a slave to the slave array
318 *
319 * @param slave the slave controller to add
320 */
321static void
322slave_list_add (struct Slave *slave)
323{
324 if (slave->host_id >= GST_slave_list_size)
325 GST_array_grow_large_enough (GST_slave_list,
326 GST_slave_list_size,
327 slave->host_id);
328 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
329 GST_slave_list[slave->host_id] = slave;
330}
331
332
333/**
334 * Clean up all forwarded operation overlay context matching the
335 * client given in @a cls.
336 *
337 * @param cls a `struct GNUNET_SERVICE_Client *` to match
338 * @param key unused
339 * @param value the `struct RegisteredHostContext` to search for @a cls
340 * @return #GNUNET_OK (continue iterating)
341 */
342static int
343drop_client_entries (void *cls,
344 const struct GNUNET_HashCode *key,
345 void *value)
346{
347 struct GNUNET_SERVICE_Client *client = cls;
348 struct RegisteredHostContext *rhc = value;
349 struct ForwardedOverlayConnectContext *focc;
350 struct ForwardedOverlayConnectContext *foccn;
351
352 for (focc = rhc->focc_dll_head; NULL != focc; focc = foccn)
353 {
354 foccn = focc->next;
355 if (focc->client == client)
356 GST_cleanup_focc (focc);
357 }
358 return GNUNET_OK;
359}
360
361
362/**
363 * Adds a route to the route list
364 *
365 * @param route the route to add
366 */
367static void
368route_list_add (struct Route *route)
369{
370 if (route->dest >= route_list_size)
371 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
372 GNUNET_assert (NULL == route_list[route->dest]);
373 route_list[route->dest] = route;
374}
375
376
377/**
378 * Add a neighbour to the neighbour list. Grows the neighbour list
379 * automatically.
380 *
381 * @param n the neighbour to add
382 */
383static void
384neighbour_list_add (struct Neighbour *n)
385{
386 if (n->host_id >= neighbour_list_size)
387 GST_array_grow_large_enough (neighbour_list, neighbour_list_size,
388 n->host_id);
389 GNUNET_assert (NULL == neighbour_list[n->host_id]);
390 neighbour_list[n->host_id] = n;
391}
392
393
394/**
395 * Cleans up the route list
396 */
397void
398GST_route_list_clear ()
399{
400 unsigned int id;
401
402 for (id = 0; id < route_list_size; id++)
403 if (NULL != route_list[id])
404 GNUNET_free (route_list[id]);
405 GNUNET_free (route_list);
406 route_list = NULL;
407}
408
409
410/**
411 * Iterator for freeing hash map entries in a slave's reghost_map
412 *
413 * @param cls handle to the slave
414 * @param key current key code
415 * @param value value in the hash map
416 * @return #GNUNET_YES if we should continue to iterate,
417 * #GNUNET_NO if not.
418 */
419static int
420reghost_free_iterator (void *cls,
421 const struct GNUNET_HashCode *key,
422 void *value)
423{
424 struct Slave *slave = cls;
425 struct RegisteredHostContext *rhc = value;
426 struct ForwardedOverlayConnectContext *focc;
427
428 GNUNET_assert (GNUNET_YES ==
429 GNUNET_CONTAINER_multihashmap_remove (slave->reghost_map, key,
430 value));
431 while (NULL != (focc = rhc->focc_dll_head))
432 GST_cleanup_focc (focc);
433 GNUNET_free (value);
434 return GNUNET_YES;
435}
436
437
438/**
439 * Kill a #Slave object
440 *
441 * @param slave the #Slave object
442 */
443static void
444kill_slave (struct Slave *slave)
445{
446 struct HostRegistration *hr_entry;
447
448 while (NULL != (hr_entry = slave->hr_dll_head))
449 {
450 GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head, slave->hr_dll_tail,
451 hr_entry);
452 GNUNET_free (hr_entry);
453 }
454 if (NULL != slave->rhandle)
455 GNUNET_TESTBED_cancel_registration (slave->rhandle);
456 GNUNET_assert (GNUNET_SYSERR !=
457 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
458 reghost_free_iterator,
459 slave));
460 GNUNET_CONTAINER_multihashmap_destroy (slave->reghost_map);
461 if (NULL != slave->controller)
462 GNUNET_TESTBED_controller_disconnect (slave->controller);
463 if (NULL != slave->controller_proc)
464 {
465 LOG_DEBUG ("Stopping a slave\n");
466 GNUNET_TESTBED_controller_kill_ (slave->controller_proc);
467 }
468}
469
470
471/**
472 * Destroy a #Slave object
473 *
474 * @param slave the #Slave object
475 */
476static void
477destroy_slave (struct Slave *slave)
478{
479 if (NULL != slave->controller_proc)
480 {
481 GNUNET_TESTBED_controller_destroy_ (slave->controller_proc);
482 LOG_DEBUG ("Slave stopped\n");
483 }
484 GST_slave_list[slave->host_id] = NULL;
485 GNUNET_free (slave);
486}
487
488
489/**
490 * Cleans up the slave list
491 */
492void
493GST_slave_list_clear ()
494{
495 struct Slave *slave;
496 unsigned int id;
497
498 for (id = 0; id < GST_slave_list_size; id++)
499 {
500 slave = GST_slave_list[id];
501 if (NULL == slave)
502 continue;
503 kill_slave (slave);
504 }
505 for (id = 0; id < GST_slave_list_size; id++)
506 {
507 slave = GST_slave_list[id];
508 if (NULL == slave)
509 continue;
510 destroy_slave (slave);
511 }
512 GNUNET_free (GST_slave_list);
513 GST_slave_list = NULL;
514}
515
516
517/**
518 * Finds the route with directly connected host as destination through which
519 * the destination host can be reached
520 *
521 * @param host_id the id of the destination host
522 * @return the route with directly connected destination host; NULL if no route
523 * is found
524 */
525struct Route *
526GST_find_dest_route (uint32_t host_id)
527{
528 struct Route *route;
529
530 if (route_list_size <= host_id)
531 return NULL;
532 while (NULL != (route = route_list[host_id]))
533 {
534 if (route->thru == GST_context->host_id)
535 break;
536 host_id = route->thru;
537 }
538 return route;
539}
540
541
542/**
543 * Function to send a failure response for controller link operation
544 *
545 * @param client the client to send the message to
546 * @param operation_id the operation ID of the controller link request
547 * @param cfg the configuration with which the delegated controller is started.
548 * Can be NULL if the delegated controller is not started but just
549 * linked to.
550 * @param emsg set to an error message explaining why the controller link
551 * failed. Setting this to NULL signifies success. !This should be
552 * NULL if cfg is set!
553 */
554static void
555send_controller_link_response (struct GNUNET_SERVICE_Client *client,
556 uint64_t operation_id,
557 const struct GNUNET_CONFIGURATION_Handle *cfg,
558 const char *emsg)
559{
560 struct GNUNET_MQ_Envelope *env;
561 struct GNUNET_TESTBED_ControllerLinkResponse *msg;
562 char *xconfig;
563 size_t config_size;
564 size_t xconfig_size;
565 uint16_t msize;
566
567 GNUNET_assert ((NULL == cfg) || (NULL == emsg));
568 xconfig = NULL;
569 xconfig_size = 0;
570 config_size = 0;
571 msize = 0;
572 if (NULL != cfg)
573 {
574 xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
575 &config_size,
576 &xconfig_size);
577 msize += xconfig_size;
578 }
579 if (NULL != emsg)
580 msize += strlen (emsg);
581 env = GNUNET_MQ_msg_extra (msg,
582 msize,
583 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
584 if (NULL == emsg)
585 msg->success = htons (GNUNET_YES);
586 msg->operation_id = GNUNET_htonll (operation_id);
587 msg->config_size = htons ((uint16_t) config_size);
588 if (NULL != xconfig)
589 {
590 GNUNET_memcpy (&msg[1],
591 xconfig,
592 xconfig_size);
593 GNUNET_free (xconfig);
594 }
595 if (NULL != emsg)
596 GNUNET_memcpy (&msg[1],
597 emsg,
598 strlen (emsg));
599 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
600 env);
601}
602
603
604/**
605 * The Link Controller forwarding task
606 *
607 * @param cls the LCFContext
608 */
609static void
610lcf_proc_task (void *cls);
611
612
613/**
614 * Completion callback for host registrations while forwarding Link Controller messages
615 *
616 * @param cls the LCFContext
617 * @param emsg the error message; NULL if host registration is successful
618 */
619static void
620lcf_proc_cc (void *cls,
621 const char *emsg)
622{
623 struct LCFContext *lcf = cls;
624
625 GNUNET_assert (NULL == lcf_proc_task_id);
626 switch (lcf->state)
627 {
628 case INIT:
629 if (NULL != emsg)
630 goto registration_error;
631 lcf->state = DELEGATED_HOST_REGISTERED;
632 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
633 break;
634
635 case DELEGATED_HOST_REGISTERED:
636 if (NULL != emsg)
637 goto registration_error;
638 lcf->state = SLAVE_HOST_REGISTERED;
639 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
640 break;
641
642 default:
643 GNUNET_assert (0); /* Shouldn't reach here */
644 }
645 return;
646
647registration_error:
648 LOG (GNUNET_ERROR_TYPE_WARNING,
649 "Host registration failed with message: %s\n",
650 emsg);
651 lcf->state = FINISHED;
652 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
653 lcf);
654}
655
656
657/**
658 * The Link Controller forwarding task
659 *
660 * @param cls the LCFContext
661 */
662static void
663lcf_proc_task (void *cls);
664
665
666/**
667 * Task to free resources when forwarded link controllers has been timedout
668 *
669 * @param cls the LCFContext
670 */
671static void
672lcf_forwarded_operation_timeout (void *cls)
673{
674 struct LCFContext *lcf = cls;
675
676 lcf->timeout_task = NULL;
677 // GST_forwarded_operation_timeout (lcf->fopc, tc);
678 LOG (GNUNET_ERROR_TYPE_WARNING,
679 "A forwarded controller link operation has timed out\n");
680 send_controller_link_response (lcf->client,
681 lcf->operation_id,
682 NULL,
683 "A forwarded controller link operation has timed out\n");
684 GNUNET_assert (NULL == lcf_proc_task_id);
685 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
686 lcf);
687}
688
689
690/**
691 * The Link Controller forwarding task
692 *
693 * @param cls the LCFContext
694 */
695static void
696lcf_proc_task (void *cls)
697{
698 struct LCFContext *lcf = cls;
699
700 lcf_proc_task_id = NULL;
701 switch (lcf->state)
702 {
703 case INIT:
704 if (GNUNET_NO ==
705 GNUNET_TESTBED_is_host_registered_ (GST_host_list
706 [lcf->delegated_host_id],
707 lcf->gateway->controller))
708 {
709 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
710 GST_host_list[lcf->delegated_host_id]);
711 }
712 else
713 {
714 lcf->state = DELEGATED_HOST_REGISTERED;
715 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
716 }
717 break;
718
719 case DELEGATED_HOST_REGISTERED:
720 if (GNUNET_NO ==
721 GNUNET_TESTBED_is_host_registered_ (GST_host_list[lcf->slave_host_id],
722 lcf->gateway->controller))
723 {
724 GST_queue_host_registration (lcf->gateway, lcf_proc_cc, lcf,
725 GST_host_list[lcf->slave_host_id]);
726 }
727 else
728 {
729 lcf->state = SLAVE_HOST_REGISTERED;
730 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
731 }
732 break;
733
734 case SLAVE_HOST_REGISTERED:
735 lcf->op = GNUNET_TESTBED_controller_link (lcf,
736 lcf->gateway->controller,
737 GST_host_list[lcf->
738 delegated_host_id],
739 GST_host_list[lcf->slave_host_id],
740 lcf->is_subordinate);
741 lcf->timeout_task =
742 GNUNET_SCHEDULER_add_delayed (GST_timeout,
743 &lcf_forwarded_operation_timeout,
744 lcf);
745 lcf->state = FINISHED;
746 break;
747
748 case FINISHED:
749 if (NULL != lcf->op)
750 GNUNET_TESTBED_operation_done (lcf->op);
751 GNUNET_CONTAINER_DLL_remove (lcf_head,
752 lcf_tail,
753 lcf);
754 GNUNET_free (lcf);
755 if (NULL != lcf_head)
756 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
757 lcf_head);
758 }
759}
760
761
762/**
763 * Callback for event from slave controllers
764 *
765 * @param cls NULL
766 * @param event information about the event
767 */
768static void
769slave_event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
770{
771 struct LCFContext *lcf;
772
773 /* We currently only get here when working on LCFContexts */
774 GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
775 lcf = event->op_cls;
776 GNUNET_assert (lcf->op == event->op);
777 GNUNET_TESTBED_operation_done (lcf->op);
778 lcf->op = NULL;
779 GNUNET_assert (FINISHED == lcf->state);
780 GNUNET_assert (NULL != lcf->timeout_task);
781 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
782 if (NULL == event->details.operation_finished.emsg)
783 send_controller_link_response (lcf->client, lcf->operation_id,
784 GNUNET_TESTBED_host_get_cfg_
785 (GST_host_list[lcf->delegated_host_id]),
786 NULL);
787 else
788 send_controller_link_response (lcf->client, lcf->operation_id,
789 NULL,
790 event->details.operation_finished.emsg);
791 GNUNET_assert (NULL == lcf_proc_task_id);
792 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
793 return;
794}
795
796
797/**
798 * Callback to signal successful startup of the controller process
799 *
800 * @param cls the handle to the slave whose status is to be found here
801 * @param cfg the configuration with which the controller has been started;
802 * NULL if status is not #GNUNET_OK
803 * @param status #GNUNET_OK if the startup is successful; #GNUNET_SYSERR if not,
804 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
805 */
806static void
807slave_status_cb (void *cls,
808 const struct GNUNET_CONFIGURATION_Handle *cfg,
809 int status)
810{
811 struct Slave *slave = cls;
812 struct LinkControllersContext *lcc;
813
814 lcc = slave->lcc;
815 if (GNUNET_SYSERR == status)
816 {
817 slave->controller_proc = NULL;
818 /* Stop all link controller forwarding tasks since we shutdown here anyway
819 and as these tasks they depend on the operation queues which are created
820 through GNUNET_TESTBED_controller_connect() and in kill_slave() we call
821 the destructor function GNUNET_TESTBED_controller_disconnect() */
822 GST_free_lcf ();
823 kill_slave (slave);
824 destroy_slave (slave);
825 slave = NULL;
826 LOG (GNUNET_ERROR_TYPE_WARNING, "Unexpected slave shutdown\n");
827 GNUNET_SCHEDULER_shutdown (); /* We too shutdown */
828 goto clean_lcc;
829 }
830 slave->controller =
831 GNUNET_TESTBED_controller_connect (GST_host_list[slave->host_id],
832 EVENT_MASK, &slave_event_cb,
833 slave);
834 if (NULL != slave->controller)
835 {
836 send_controller_link_response (lcc->client, lcc->operation_id, cfg, NULL);
837 }
838 else
839 {
840 send_controller_link_response (lcc->client, lcc->operation_id, NULL,
841 "Could not connect to delegated controller");
842 kill_slave (slave);
843 destroy_slave (slave);
844 slave = NULL;
845 }
846
847clean_lcc:
848 if (NULL != lcc)
849 {
850 if (NULL != lcc->client)
851 {
852 GNUNET_SERVICE_client_continue (lcc->client);
853 lcc->client = NULL;
854 }
855 GNUNET_free (lcc);
856 }
857 if (NULL != slave)
858 slave->lcc = NULL;
859}
860
861
862/**
863 * Trigger notification task if there are notification requests currently
864 * waiting in the given neighbour. Also activates the neighbour connect operation
865 * if it was previously inactivated so that the connection to the neighbour can
866 * be re-used
867 *
868 * @param n the neighbour
869 */
870static void
871trigger_notifications (struct Neighbour *n);
872
873
874/**
875 * Task to call the notification queued in the notifications list of the given
876 * neighbour
877 *
878 * @param cls the neighbour
879 */
880static void
881neighbour_connect_notify_task (void *cls)
882{
883 struct Neighbour *n = cls;
884 struct NeighbourConnectNotification *h;
885
886 GNUNET_assert (NULL != (h = n->nl_head));
887 GNUNET_assert (NULL != n->notify_task);
888 n->notify_task = NULL;
889 GNUNET_assert (NULL != n->controller);
890 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
891 trigger_notifications (n);
892 h->cb (h->cb_cls, n->controller);
893 GNUNET_free (h);
894}
895
896
897/**
898 * Trigger notification task if there are notification requests currently
899 * waiting in the given neighbour. Also activates the neighbour connect operation
900 * if it was previously inactivated so that the connection to the neighbour can
901 * be re-used
902 *
903 * @param n the neighbour
904 */
905static void
906trigger_notifications (struct Neighbour *n)
907{
908 GNUNET_assert (NULL != n->conn_op);
909 if (NULL == n->nl_head)
910 return;
911 if (NULL == n->controller)
912 return;
913 if (NULL != n->notify_task)
914 return;
915 if (1 == n->inactive)
916 {
917 GNUNET_assert (0 == n->reference_cnt);
918 GNUNET_TESTBED_operation_activate_ (n->conn_op);
919 n->inactive = 0;
920 }
921 n->reference_cnt++;
922 n->notify_task =
923 GNUNET_SCHEDULER_add_now (&neighbour_connect_notify_task, n);
924}
925
926
927/**
928 * Callback to be called when the neighbour connect operation is started. The
929 * connection to the neighbour is opened here and any pending notifications are
930 * trigger.
931 *
932 * @param cls the neighbour
933 */
934static void
935opstart_neighbour_conn (void *cls)
936{
937 struct Neighbour *n = cls;
938
939 GNUNET_assert (NULL != n->conn_op);
940 GNUNET_assert (NULL == n->controller);
941 LOG_DEBUG ("Opening connection to controller on host %u\n", n->host_id);
942 n->controller = GNUNET_TESTBED_controller_connect (GST_host_list[n->host_id],
943 EVENT_MASK,
944 &slave_event_cb,
945 NULL);
946 trigger_notifications (n);
947}
948
949
950/**
951 * Callback to be called when the neighbour connect operation is released
952 *
953 * @param cls the neighbour
954 */
955static void
956oprelease_neighbour_conn (void *cls)
957{
958 struct Neighbour *n = cls;
959
960 GNUNET_assert (0 == n->reference_cnt);
961 GNUNET_assert (NULL == n->notify_task);
962 GNUNET_assert (NULL == n->nl_head);
963 if (NULL != n->controller)
964 {
965 LOG_DEBUG ("Closing connection to controller on host %u\n", n->host_id);
966 GNUNET_TESTBED_controller_disconnect (n->controller);
967 n->controller = NULL;
968 }
969 n->conn_op = NULL;
970 n->inactive = 0;
971}
972
973
974/**
975 * Try to open a connection to the given neighbour. If the connection is open
976 * already, then it is re-used. If not, the request is queued in the operation
977 * queues responsible for bounding the total number of file descriptors. The
978 * actual connection will happen when the operation queue marks the
979 * corresponding operation as active.
980 *
981 * @param n the neighbour to open a connection to
982 * @param cb the notification callback to call when the connection is opened
983 * @param cb_cls the closure for the above callback
984 */
985struct NeighbourConnectNotification *
986GST_neighbour_get_connection (struct Neighbour *n,
987 GST_NeighbourConnectNotifyCallback cb,
988 void *cb_cls)
989{
990 struct NeighbourConnectNotification *h;
991
992 GNUNET_assert (NULL != cb);
993 LOG_DEBUG ("Attempting to get connection to controller on host %u\n",
994 n->host_id);
995 h = GNUNET_new (struct NeighbourConnectNotification);
996 h->n = n;
997 h->cb = cb;
998 h->cb_cls = cb_cls;
999 GNUNET_CONTAINER_DLL_insert_tail (n->nl_head, n->nl_tail, h);
1000 if (NULL == n->conn_op)
1001 {
1002 GNUNET_assert (NULL == n->controller);
1003 n->conn_op = GNUNET_TESTBED_operation_create_ (n, &opstart_neighbour_conn,
1004 &oprelease_neighbour_conn);
1005 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, n->conn_op);
1006 GNUNET_TESTBED_operation_begin_wait_ (n->conn_op);
1007 return h;
1008 }
1009 trigger_notifications (n);
1010 return h;
1011}
1012
1013
1014/**
1015 * Cancel the request for opening a connection to the neighbour
1016 *
1017 * @param h the notification handle
1018 */
1019void
1020GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h)
1021{
1022 struct Neighbour *n;
1023 int cleanup_task;
1024
1025 n = h->n;
1026 cleanup_task = (h == n->nl_head) ? GNUNET_YES : GNUNET_NO;
1027 GNUNET_CONTAINER_DLL_remove (n->nl_head, n->nl_tail, h);
1028 GNUNET_free (h);
1029 if (GNUNET_NO == cleanup_task)
1030 return;
1031 if (NULL == n->notify_task)
1032 return;
1033 GNUNET_assert (0 < n->reference_cnt);
1034 n->reference_cnt--;
1035 GNUNET_SCHEDULER_cancel (n->notify_task);
1036 n->notify_task = NULL;
1037 if (NULL == n->nl_head)
1038 {
1039 if ((0 == n->reference_cnt) && (0 == n->inactive))
1040 {
1041 n->inactive = 1;
1042 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1043 }
1044 return;
1045 }
1046 trigger_notifications (n);
1047}
1048
1049
1050/**
1051 * Release the connection to the neighbour. The actual connection will be
1052 * closed if connections to other neighbour are waiting (to maintain a bound on
1053 * the total number of connections that are open).
1054 *
1055 * @param n the neighbour whose connection can be closed
1056 */
1057void
1058GST_neighbour_release_connection (struct Neighbour *n)
1059{
1060 GNUNET_assert (0 == n->inactive);
1061 GNUNET_assert (0 < n->reference_cnt);
1062 n->reference_cnt--;
1063 if (0 == n->reference_cnt)
1064 {
1065 n->inactive = 1;
1066 GNUNET_TESTBED_operation_inactivate_ (n->conn_op);
1067 }
1068}
1069
1070
1071/**
1072 * Cleanup neighbour connect contexts
1073 *
1074 * @param ncc the neighbour connect context to cleanup
1075 */
1076static void
1077cleanup_ncc (struct NeighbourConnectCtxt *ncc)
1078{
1079 if (NULL != ncc->nh)
1080 GST_neighbour_get_connection_cancel (ncc->nh);
1081 if (NULL != ncc->timeout_task)
1082 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1083 GNUNET_CONTAINER_DLL_remove (ncc_head,
1084 ncc_tail,
1085 ncc);
1086 GNUNET_free (ncc);
1087}
1088
1089
1090/**
1091 * Cleans up the neighbour list
1092 */
1093void
1094GST_neighbour_list_clean ()
1095{
1096 struct Neighbour *n;
1097 unsigned int id;
1098
1099 for (id = 0; id < neighbour_list_size; id++)
1100 {
1101 if (NULL == (n = neighbour_list[id]))
1102 continue;
1103 if (NULL != n->conn_op)
1104 GNUNET_TESTBED_operation_release_ (n->conn_op);
1105 GNUNET_free (n);
1106 neighbour_list[id] = NULL;
1107 }
1108 GNUNET_free (neighbour_list);
1109}
1110
1111
1112/**
1113 * Get a neighbour from the neighbour list
1114 *
1115 * @param id the index of the neighbour in the neighbour list
1116 * @return the Neighbour; NULL if the given index in invalid (index greater than
1117 * the list size or neighbour at that index is NULL)
1118 */
1119struct Neighbour *
1120GST_get_neighbour (uint32_t id)
1121{
1122 if (neighbour_list_size <= id)
1123 return NULL;
1124 return neighbour_list[id];
1125}
1126
1127
1128/**
1129 * Function to cleanup the neighbour connect contexts
1130 */
1131void
1132GST_free_nccq ()
1133{
1134 while (NULL != ncc_head)
1135 cleanup_ncc (ncc_head);
1136}
1137
1138
1139/**
1140 * Task to be run upon timeout while attempting to connect to the neighbour
1141 *
1142 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1143 */
1144static void
1145timeout_neighbour_connect (void *cls)
1146{
1147 struct NeighbourConnectCtxt *ncc = cls;
1148
1149 ncc->timeout_task = NULL;
1150 send_controller_link_response (ncc->client,
1151 ncc->op_id,
1152 NULL,
1153 "Could not connect to delegated controller");
1154 cleanup_ncc (ncc);
1155}
1156
1157
1158/**
1159 * Callback called when a connection to the neighbour is made
1160 *
1161 * @param cls the NeighbourConnectCtxt created in GST_handle_link_controllers()
1162 * @param c the handle the neighbour's controller
1163 */
1164static void
1165neighbour_connect_cb (void *cls,
1166 struct GNUNET_TESTBED_Controller *c)
1167{
1168 struct NeighbourConnectCtxt *ncc = cls;
1169
1170 GNUNET_SCHEDULER_cancel (ncc->timeout_task);
1171 ncc->timeout_task = NULL;
1172 ncc->nh = NULL;
1173 GST_neighbour_release_connection (ncc->n);
1174 send_controller_link_response (ncc->client,
1175 ncc->op_id,
1176 NULL,
1177 NULL);
1178 cleanup_ncc (ncc);
1179}
1180
1181
1182/**
1183 * Function to create a neighbour and add it into the neighbour list
1184 *
1185 * @param host the host of the neighbour
1186 */
1187struct Neighbour *
1188GST_create_neighbour (struct GNUNET_TESTBED_Host *host)
1189{
1190 struct Neighbour *n;
1191
1192 n = GNUNET_new (struct Neighbour);
1193 n->host_id = GNUNET_TESTBED_host_get_id_ (host);
1194 neighbour_list_add (n); /* just add; connect on-demand */
1195 return n;
1196}
1197
1198
1199/**
1200 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
1201 *
1202 * @param cls identification of the client
1203 * @param msg the actual message
1204 */
1205void
1206handle_link_controllers (void *cls,
1207 const struct GNUNET_TESTBED_ControllerLinkRequest *msg)
1208{
1209 struct GNUNET_SERVICE_Client *client = cls;
1210 struct LCFContext *lcf;
1211 struct Route *route;
1212 struct Route *new_route;
1213 uint64_t op_id;
1214 uint32_t delegated_host_id;
1215 uint32_t slave_host_id;
1216
1217 if (NULL == GST_context)
1218 {
1219 GNUNET_break (0);
1220 GNUNET_SERVICE_client_drop (client);
1221 return;
1222 }
1223 delegated_host_id = ntohl (msg->delegated_host_id);
1224 if (delegated_host_id == GST_context->host_id)
1225 {
1226 GNUNET_break (0);
1227 LOG (GNUNET_ERROR_TYPE_WARNING,
1228 "Trying to link ourselves\n");
1229 GNUNET_SERVICE_client_drop (client);
1230 return;
1231 }
1232 if ((delegated_host_id >= GST_host_list_size) ||
1233 (NULL == GST_host_list[delegated_host_id]))
1234 {
1235 LOG (GNUNET_ERROR_TYPE_WARNING,
1236 "Delegated host %u not registered with us\n",
1237 delegated_host_id);
1238 GNUNET_SERVICE_client_drop (client);
1239 return;
1240 }
1241 slave_host_id = ntohl (msg->slave_host_id);
1242 if ((slave_host_id >= GST_host_list_size) ||
1243 (NULL == GST_host_list[slave_host_id]))
1244 {
1245 LOG (GNUNET_ERROR_TYPE_WARNING,
1246 "Slave host %u not registered with us\n",
1247 slave_host_id);
1248 GNUNET_SERVICE_client_drop (client);
1249 return;
1250 }
1251 if (slave_host_id == delegated_host_id)
1252 {
1253 LOG (GNUNET_ERROR_TYPE_WARNING,
1254 "Slave and delegated host are same\n");
1255 GNUNET_SERVICE_client_drop (client);
1256 return;
1257 }
1258 op_id = GNUNET_ntohll (msg->operation_id);
1259 if (slave_host_id == GST_context->host_id) /* Link from us */
1260 {
1261 struct Slave *slave;
1262 struct LinkControllersContext *lcc;
1263
1264 if (1 != msg->is_subordinate)
1265 {
1266 struct Neighbour *n;
1267 struct NeighbourConnectCtxt *ncc;
1268
1269 if ((delegated_host_id < neighbour_list_size) &&
1270 (NULL != neighbour_list[delegated_host_id]))
1271 {
1272 GNUNET_break (0);
1273 GNUNET_SERVICE_client_drop (client);
1274 return;
1275 }
1276 LOG_DEBUG ("Received request to establish a link to host %u\n",
1277 delegated_host_id);
1278 n = GST_create_neighbour (GST_host_list[delegated_host_id]);
1279 ncc = GNUNET_new (struct NeighbourConnectCtxt);
1280 ncc->n = n;
1281 ncc->op_id = op_id;
1282 ncc->client = client;
1283 ncc->nh = GST_neighbour_get_connection (n,
1284 &neighbour_connect_cb,
1285 ncc);
1286 ncc->timeout_task
1287 = GNUNET_SCHEDULER_add_delayed (GST_timeout,
1288 &timeout_neighbour_connect,
1289 ncc);
1290 GNUNET_CONTAINER_DLL_insert_tail (ncc_head,
1291 ncc_tail,
1292 ncc);
1293 GNUNET_SERVICE_client_continue (client);
1294 return;
1295 }
1296 if ((delegated_host_id < GST_slave_list_size) &&
1297 (NULL != GST_slave_list[delegated_host_id]))
1298 {
1299 GNUNET_break (0);
1300 GNUNET_SERVICE_client_drop (client);
1301 return;
1302 }
1303 LOG_DEBUG ("Received request to start and establish a link to host %u\n",
1304 delegated_host_id);
1305 slave = GNUNET_new (struct Slave);
1306 slave->host_id = delegated_host_id;
1307 slave->reghost_map = GNUNET_CONTAINER_multihashmap_create (100,
1308 GNUNET_NO);
1309 slave_list_add (slave);
1310 lcc = GNUNET_new (struct LinkControllersContext);
1311 lcc->operation_id = op_id;
1312 lcc->client = client;
1313 slave->lcc = lcc;
1314 slave->controller_proc
1315 = GNUNET_TESTBED_controller_start (GST_context->master_ip,
1316 GST_host_list[slave->host_id],
1317 &slave_status_cb,
1318 slave);
1319 new_route = GNUNET_new (struct Route);
1320 new_route->dest = delegated_host_id;
1321 new_route->thru = GST_context->host_id;
1322 route_list_add (new_route);
1323 return;
1324 }
1325
1326 /* Route the request */
1327 if (slave_host_id >= route_list_size)
1328 {
1329 LOG (GNUNET_ERROR_TYPE_WARNING,
1330 "No route towards slave host");
1331 GNUNET_SERVICE_client_drop (client);
1332 return;
1333 }
1334 lcf = GNUNET_new (struct LCFContext);
1335 lcf->delegated_host_id = delegated_host_id;
1336 lcf->slave_host_id = slave_host_id;
1337 route = GST_find_dest_route (slave_host_id);
1338 GNUNET_assert (NULL != route); /* because we add routes carefully */
1339 GNUNET_assert (route->dest < GST_slave_list_size);
1340 GNUNET_assert (NULL != GST_slave_list[route->dest]);
1341 lcf->is_subordinate = msg->is_subordinate;
1342 lcf->state = INIT;
1343 lcf->operation_id = op_id;
1344 lcf->gateway = GST_slave_list[route->dest];
1345 lcf->client = client;
1346 if (NULL == lcf_head)
1347 {
1348 GNUNET_assert (NULL == lcf_proc_task_id);
1349 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1350 lcf_tail,
1351 lcf);
1352 lcf_proc_task_id = GNUNET_SCHEDULER_add_now (&lcf_proc_task,
1353 lcf);
1354 }
1355 else
1356 {
1357 GNUNET_CONTAINER_DLL_insert_tail (lcf_head,
1358 lcf_tail,
1359 lcf);
1360 }
1361 /* FIXME: Adding a new route should happen after the controllers are linked
1362 * successfully */
1363 if (1 != msg->is_subordinate)
1364 {
1365 GNUNET_SERVICE_client_continue (client);
1366 return;
1367 }
1368 if ((delegated_host_id < route_list_size) &&
1369 (NULL != route_list[delegated_host_id]))
1370 {
1371 GNUNET_break_op (0); /* Are you trying to link delegated host twice
1372 * with is subordinate flag set to GNUNET_YES? */
1373 GNUNET_SERVICE_client_drop (client);
1374 return;
1375 }
1376 new_route = GNUNET_new (struct Route);
1377 new_route->dest = delegated_host_id;
1378 new_route->thru = route->dest;
1379 route_list_add (new_route);
1380 GNUNET_SERVICE_client_continue (client);
1381}
1382
1383
1384/**
1385 * Clean up @a client handle if we stored any via #handle_link_controllers(),
1386 * the given client disconnected.
1387 *
1388 * @param client the client that is history
1389 */
1390void
1391GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client)
1392{
1393 struct NeighbourConnectCtxt *ncc;
1394 struct NeighbourConnectCtxt *nccn;
1395 struct LCFContext *lcf;
1396 struct LCFContext *lcfn;
1397
1398 for (ncc = ncc_head; NULL != ncc; ncc = nccn)
1399 {
1400 nccn = ncc->next;
1401 if (ncc->client == client)
1402 cleanup_ncc (ncc);
1403 }
1404 for (unsigned int i = 0; i < GST_slave_list_size; i++)
1405 {
1406 struct Slave *slave = GST_slave_list[i];
1407 struct LinkControllersContext *lcc;
1408
1409 if (NULL == slave)
1410 continue;
1411 GNUNET_CONTAINER_multihashmap_iterate (slave->reghost_map,
1412 &drop_client_entries,
1413 client);
1414 lcc = slave->lcc;
1415 if (NULL == lcc)
1416 continue;
1417 if (lcc->client == client)
1418 {
1419 slave->lcc = NULL;
1420 GNUNET_free (lcc);
1421 }
1422 }
1423 for (lcf = lcf_head; NULL != lcf; lcf = lcfn)
1424 {
1425 lcfn = lcf->next;
1426 if ((NULL != lcf) &&
1427 (client == lcf->client))
1428 {
1429 if (NULL != lcf->op)
1430 GNUNET_TESTBED_operation_done (lcf->op);
1431 GNUNET_CONTAINER_DLL_remove (lcf_head,
1432 lcf_tail,
1433 lcf);
1434 GNUNET_free (lcf);
1435 }
1436 }
1437}
1438
1439
1440/**
1441 * Cleans up the queue used for forwarding link controllers requests
1442 */
1443void
1444GST_free_lcf ()
1445{
1446 struct LCFContext *lcf;
1447
1448 if (NULL != lcf_head)
1449 {
1450 if (NULL != lcf_proc_task_id)
1451 {
1452 GNUNET_SCHEDULER_cancel (lcf_proc_task_id);
1453 lcf_proc_task_id = NULL;
1454 }
1455 }
1456 GNUNET_assert (NULL == lcf_proc_task_id);
1457 for (lcf = lcf_head; NULL != lcf; lcf = lcf_head)
1458 {
1459 if (NULL != lcf->op)
1460 GNUNET_TESTBED_operation_done (lcf->op);
1461 if (NULL != lcf->timeout_task)
1462 GNUNET_SCHEDULER_cancel (lcf->timeout_task);
1463 GNUNET_CONTAINER_DLL_remove (lcf_head,
1464 lcf_tail,
1465 lcf);
1466 GNUNET_free (lcf);
1467 }
1468}
diff --git a/src/testbed/gnunet-service-testbed_links.h b/src/testbed/gnunet-service-testbed_links.h
deleted file mode 100644
index 74db0bd47..000000000
--- a/src/testbed/gnunet-service-testbed_links.h
+++ /dev/null
@@ -1,209 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_links.h
23 * @brief TESTBED service components that deals with starting slave controllers
24 * and establishing lateral links between controllers
25 * @author Sree Harsha Totakura
26 */
27
28
29/**
30 * A connected controller which is not our child
31 */
32struct Neighbour;
33
34
35/**
36 * Structure representing a connected(directly-linked) controller
37 */
38struct Slave
39{
40 /**
41 * The controller process handle if we had started the controller
42 */
43 struct GNUNET_TESTBED_ControllerProc *controller_proc;
44
45 /**
46 * The controller handle
47 */
48 struct GNUNET_TESTBED_Controller *controller;
49
50 /**
51 * handle to lcc which is associated with this slave startup. Should be set to
52 * NULL when the slave has successfully started up
53 */
54 struct LinkControllersContext *lcc;
55
56 /**
57 * Head of the host registration DLL
58 */
59 struct HostRegistration *hr_dll_head;
60
61 /**
62 * Tail of the host registration DLL
63 */
64 struct HostRegistration *hr_dll_tail;
65
66 /**
67 * The current host registration handle
68 */
69 struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
70
71 /**
72 * Hashmap to hold Registered host contexts
73 */
74 struct GNUNET_CONTAINER_MultiHashMap *reghost_map;
75
76 /**
77 * The id of the host this controller is running on
78 */
79 uint32_t host_id;
80};
81
82/**
83 * A list of directly linked neighbours
84 */
85extern struct Slave **GST_slave_list;
86
87/**
88 * The size of directly linked neighbours list
89 */
90extern unsigned int GST_slave_list_size;
91
92
93/**
94 * Cleans up the neighbour list
95 */
96void
97GST_neighbour_list_clean (void);
98
99
100/**
101 * Get a neighbour from the neighbour list
102 *
103 * @param id the index of the neighbour in the neighbour list
104 * @return the Neighbour; NULL if the given index in invalid (index greater than
105 * the list size or neighbour at that index is NULL)
106 */
107struct Neighbour *
108GST_get_neighbour (uint32_t id);
109
110
111/**
112 * Function to cleanup the neighbour connect contexts
113 */
114void
115GST_free_nccq (void);
116
117
118/**
119 * Notification context to be used to notify when connection to the neighbour's
120 * controller is opened
121 */
122struct NeighbourConnectNotification;
123
124
125/**
126 * The notification callback to call when we are connect to neighbour
127 *
128 * @param cls the closure given to GST_neighbour_get_connection()
129 * @param controller the controller handle to the neighbour
130 */
131typedef void
132(*GST_NeighbourConnectNotifyCallback) (void *cls,
133 struct GNUNET_TESTBED_Controller *
134 controller);
135
136
137/**
138 * Try to open a connection to the given neighbour. If the connection is open
139 * already, then it is re-used. If not, the request is queued in the operation
140 * queues responsible for bounding the total number of file descriptors. The
141 * actual connection will happen when the operation queue marks the
142 * corresponding operation as active.
143 *
144 * @param n the neighbour to open a connection to
145 * @param cb the notification callback to call when the connection is opened
146 * @param cb_cls the closure for the above callback
147 */
148struct NeighbourConnectNotification *
149GST_neighbour_get_connection (struct Neighbour *n,
150 GST_NeighbourConnectNotifyCallback cb,
151 void *cb_cls);
152
153
154/**
155 * Cancel the request for opening a connection to the neighbour
156 *
157 * @param h the notification handle
158 */
159void
160GST_neighbour_get_connection_cancel (struct NeighbourConnectNotification *h);
161
162
163/**
164 * Release the connection to the neighbour. The actual connection will be
165 * closed if connections to other neighbour are waiting (to maintain a bound on
166 * the total number of connections that are open).
167 *
168 * @param n the neighbour whose connection can be closed
169 */
170void
171GST_neighbour_release_connection (struct Neighbour *n);
172
173
174/**
175 * Function to create a neighbour and add it into the neighbour list
176 *
177 * @param host the host of the neighbour
178 */
179struct Neighbour *
180GST_create_neighbour (struct GNUNET_TESTBED_Host *host);
181
182
183/**
184 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LCONTROLLERS message
185 *
186 * @param cls identification of the client
187 * @param msg the actual message
188 */
189void
190handle_link_controllers (void *cls,
191 const struct
192 GNUNET_TESTBED_ControllerLinkRequest *msg);
193
194
195/**
196 * Clean up @a client handle if we stored any via #handle_link_controllers(),
197 * the given client disconnected.
198 *
199 * @param client the client that is history
200 */
201void
202GST_link_notify_disconnect (struct GNUNET_SERVICE_Client *client);
203
204
205/**
206 * Cleans up the slave list
207 */
208void
209GST_slave_list_clear (void);
diff --git a/src/testbed/gnunet-service-testbed_meminfo.c b/src/testbed/gnunet-service-testbed_meminfo.c
deleted file mode 100644
index 1646b8d19..000000000
--- a/src/testbed/gnunet-service-testbed_meminfo.c
+++ /dev/null
@@ -1,279 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21#include "platform.h"
22#include "gnunet_util_lib.h"
23
24/*
25 * File for parsing top-level /proc entities.
26 * Copyright Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm@redhat.com
27 * Copyright 1998-2003 Albert Cahalan
28 * June 2003, Fabian Frederick, disk and slab info
29 *
30 * This library is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU Lesser General Public
32 * License as published by the Free Software Foundation; either
33 * version 2.1 of the License, or (at your option) any later version.
34 *
35 * This library is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 * Lesser General Public License for more details.
39 *
40 * You should have received a copy of the GNU Lesser General Public
41 * License along with this library; if not, write to the Free Software
42 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
43 */
44
45#define BAD_OPEN_MESSAGE \
46 "Error: /proc must be mounted\n" \
47 " To mount /proc at boot you need an /etc/fstab line like:\n" \
48 " proc /proc proc defaults\n" \
49 " In the meantime, run \"mount proc /proc -t proc\"\n"
50
51#define STAT_FILE "/proc/stat"
52// static int stat_fd = -1;
53#define UPTIME_FILE "/proc/uptime"
54// static int uptime_fd = -1;
55#define LOADAVG_FILE "/proc/loadavg"
56// static int loadavg_fd = -1;
57#define MEMINFO_FILE "/proc/meminfo"
58static int meminfo_fd = -1;
59#define VMINFO_FILE "/proc/vmstat"
60// static int vminfo_fd = -1;
61
62// As of 2.6.24 /proc/meminfo seems to need 888 on 64-bit,
63// and would need 1258 if the obsolete fields were there.
64static char buf[2048];
65
66/* This macro opens filename only if necessary and seeks to 0 so
67 * that successive calls to the functions are more efficient.
68 * It also reads the current contents of the file into the global buf.
69 */
70#define FILE_TO_BUF(filename, fd) do { \
71 static int local_n; \
72 if (fd == -1 && (fd = open (filename, O_RDONLY)) == -1) { \
73 fputs (BAD_OPEN_MESSAGE, stderr); \
74 fflush (NULL); \
75 _exit (102); \
76 } \
77 lseek (fd, 0L, SEEK_SET); \
78 if ((local_n = read (fd, buf, sizeof buf - 1)) < 0) { \
79 perror (filename); \
80 fflush (NULL); \
81 _exit (103); \
82 } \
83 buf[local_n] = '\0'; \
84} while (0)
85
86
87/***********************************************************************/
88/*
89 * Copyright 1999 by Albert Cahalan; all rights reserved.
90 * This file may be used subject to the terms and conditions of the
91 * GNU Library General Public License Version 2, or any later version
92 * at your option, as published by the Free Software Foundation.
93 * This program is distributed in the hope that it will be useful,
94 * but WITHOUT ANY WARRANTY; without even the implied warranty of
95 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96 * GNU Library General Public License for more details.
97 */
98
99typedef struct mem_table_struct
100{
101 const char *name; /* memory type name */
102 unsigned long *slot; /* slot in return struct */
103} mem_table_struct;
104
105static int
106compare_mem_table_structs (const void *a, const void *b)
107{
108 return strcmp (((const mem_table_struct *) a)->name, ((const
109 mem_table_struct *) b)
110 ->
111 name);
112}
113
114
115/* example data, following junk, with comments added:
116 *
117 * MemTotal: 61768 kB old
118 * MemFree: 1436 kB old
119 * MemShared: 0 kB old (now always zero; not calculated)
120 * Buffers: 1312 kB old
121 * Cached: 20932 kB old
122 * Active: 12464 kB new
123 * Inact_dirty: 7772 kB new
124 * Inact_clean: 2008 kB new
125 * Inact_target: 0 kB new
126 * Inact_laundry: 0 kB new, and might be missing too
127 * HighTotal: 0 kB
128 * HighFree: 0 kB
129 * LowTotal: 61768 kB
130 * LowFree: 1436 kB
131 * SwapTotal: 122580 kB old
132 * SwapFree: 60352 kB old
133 * Inactive: 20420 kB 2.5.41+
134 * Dirty: 0 kB 2.5.41+
135 * Writeback: 0 kB 2.5.41+
136 * Mapped: 9792 kB 2.5.41+
137 * Slab: 4564 kB 2.5.41+
138 * Committed_AS: 8440 kB 2.5.41+
139 * PageTables: 304 kB 2.5.41+
140 * ReverseMaps: 5738 2.5.41+
141 * SwapCached: 0 kB 2.5.??+
142 * HugePages_Total: 220 2.5.??+
143 * HugePages_Free: 138 2.5.??+
144 * Hugepagesize: 4096 kB 2.5.??+
145 */
146
147/* obsolete */
148unsigned long kb_main_shared;
149/* old but still kicking -- the important stuff */
150unsigned long kb_main_buffers;
151unsigned long kb_main_cached;
152unsigned long kb_main_free;
153unsigned long kb_main_total;
154unsigned long kb_swap_free;
155unsigned long kb_swap_total;
156/* recently introduced */
157unsigned long kb_high_free;
158unsigned long kb_high_total;
159unsigned long kb_low_free;
160unsigned long kb_low_total;
161/* 2.4.xx era */
162unsigned long kb_active;
163unsigned long kb_inact_laundry;
164unsigned long kb_inact_dirty;
165unsigned long kb_inact_clean;
166unsigned long kb_inact_target;
167unsigned long kb_swap_cached; /* late 2.4 and 2.6+ only */
168/* derived values */
169unsigned long kb_swap_used;
170unsigned long kb_main_used;
171/* 2.5.41+ */
172unsigned long kb_writeback;
173unsigned long kb_slab;
174unsigned long nr_reversemaps;
175unsigned long kb_committed_as;
176unsigned long kb_dirty;
177unsigned long kb_inactive;
178unsigned long kb_mapped;
179unsigned long kb_pagetables;
180// seen on a 2.6.x kernel:
181static unsigned long kb_vmalloc_chunk;
182static unsigned long kb_vmalloc_total;
183static unsigned long kb_vmalloc_used;
184// seen on 2.6.24-rc6-git12
185static unsigned long kb_anon_pages;
186static unsigned long kb_bounce;
187static unsigned long kb_commit_limit;
188static unsigned long kb_nfs_unstable;
189static unsigned long kb_swap_reclaimable;
190static unsigned long kb_swap_unreclaimable;
191
192void
193meminfo (void)
194{
195 char namebuf[16]; /* big enough to hold any row name */
196 mem_table_struct findme = { namebuf, NULL };
197 mem_table_struct *found;
198 char *head;
199 char *tail;
200 static const mem_table_struct mem_table[] = {
201 { "Active", &kb_active }, // important
202 { "AnonPages", &kb_anon_pages },
203 { "Bounce", &kb_bounce },
204 { "Buffers", &kb_main_buffers }, // important
205 { "Cached", &kb_main_cached }, // important
206 { "CommitLimit", &kb_commit_limit },
207 { "Committed_AS", &kb_committed_as },
208 { "Dirty", &kb_dirty }, // kB version of vmstat nr_dirty
209 { "HighFree", &kb_high_free },
210 { "HighTotal", &kb_high_total },
211 { "Inact_clean", &kb_inact_clean },
212 { "Inact_dirty", &kb_inact_dirty },
213 { "Inact_laundry", &kb_inact_laundry },
214 { "Inact_target", &kb_inact_target },
215 { "Inactive", &kb_inactive }, // important
216 { "LowFree", &kb_low_free },
217 { "LowTotal", &kb_low_total },
218 { "Mapped", &kb_mapped }, // kB version of vmstat nr_mapped
219 { "MemFree", &kb_main_free }, // important
220 { "MemShared", &kb_main_shared }, // important, but now gone!
221 { "MemTotal", &kb_main_total }, // important
222 { "NFS_Unstable", &kb_nfs_unstable },
223 { "PageTables", &kb_pagetables }, // kB version of vmstat nr_page_table_pages
224 { "ReverseMaps", &nr_reversemaps }, // same as vmstat nr_page_table_pages
225 { "SReclaimable", &kb_swap_reclaimable }, // "swap reclaimable" (dentry and inode structures)
226 { "SUnreclaim", &kb_swap_unreclaimable },
227 { "Slab", &kb_slab }, // kB version of vmstat nr_slab
228 { "SwapCached", &kb_swap_cached },
229 { "SwapFree", &kb_swap_free }, // important
230 { "SwapTotal", &kb_swap_total }, // important
231 { "VmallocChunk", &kb_vmalloc_chunk },
232 { "VmallocTotal", &kb_vmalloc_total },
233 { "VmallocUsed", &kb_vmalloc_used },
234 { "Writeback", &kb_writeback }, // kB version of vmstat nr_writeback
235 };
236 const int mem_table_count = sizeof(mem_table) / sizeof(mem_table_struct);
237
238 FILE_TO_BUF (MEMINFO_FILE, meminfo_fd);
239
240 kb_inactive = ~0UL;
241
242 head = buf;
243 for (;;)
244 {
245 tail = strchr (head, ':');
246 if (! tail)
247 break;
248 *tail = '\0';
249 if (strlen (head) >= sizeof(namebuf))
250 {
251 head = tail + 1;
252 goto nextline;
253 }
254 strcpy (namebuf, head);
255 found = bsearch (&findme, mem_table, mem_table_count,
256 sizeof(mem_table_struct), compare_mem_table_structs
257 );
258 head = tail + 1;
259 if (! found)
260 goto nextline;
261 *(found->slot) = (unsigned long) strtoull (head, &tail, 10);
262nextline:
263 tail = strchr (head, '\n');
264 if (! tail)
265 break;
266 head = tail + 1;
267 }
268 if (! kb_low_total) /* low==main except with large-memory support */
269 {
270 kb_low_total = kb_main_total;
271 kb_low_free = kb_main_free;
272 }
273 if (kb_inactive == ~0UL)
274 {
275 kb_inactive = kb_inact_dirty + kb_inact_clean + kb_inact_laundry;
276 }
277 kb_swap_used = kb_swap_total - kb_swap_free;
278 kb_main_used = kb_main_total - kb_main_free;
279}
diff --git a/src/testbed/gnunet-service-testbed_meminfo.h b/src/testbed/gnunet-service-testbed_meminfo.h
deleted file mode 100644
index b993a8a97..000000000
--- a/src/testbed/gnunet-service-testbed_meminfo.h
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/* obsolete */
22extern unsigned long kb_main_shared;
23/* old but still kicking -- the important stuff */
24extern unsigned long kb_main_buffers;
25extern unsigned long kb_main_cached;
26extern unsigned long kb_main_free;
27extern unsigned long kb_main_total;
28extern unsigned long kb_swap_free;
29extern unsigned long kb_swap_total;
30/* recently introduced */
31extern unsigned long kb_high_free;
32extern unsigned long kb_high_total;
33extern unsigned long kb_low_free;
34extern unsigned long kb_low_total;
35/* 2.4.xx era */
36extern unsigned long kb_active;
37extern unsigned long kb_inact_laundry; // grrr...
38extern unsigned long kb_inact_dirty;
39extern unsigned long kb_inact_clean;
40extern unsigned long kb_inact_target;
41extern unsigned long kb_swap_cached; /* late 2.4+ */
42/* derived values */
43extern unsigned long kb_swap_used;
44extern unsigned long kb_main_used;
45/* 2.5.41+ */
46extern unsigned long kb_writeback;
47extern unsigned long kb_slab;
48extern unsigned long nr_reversemaps;
49extern unsigned long kb_committed_as;
50extern unsigned long kb_dirty;
51extern unsigned long kb_inactive;
52extern unsigned long kb_mapped;
53extern unsigned long kb_pagetables;
54
55extern void meminfo (void);
diff --git a/src/testbed/gnunet-service-testbed_oc.c b/src/testbed/gnunet-service-testbed_oc.c
deleted file mode 100644
index 54a566e89..000000000
--- a/src/testbed/gnunet-service-testbed_oc.c
+++ /dev/null
@@ -1,1997 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-service-testbed_oc.c
23 * @brief code for handling overlay connect operations
24 * @author Sree Harsha Totakura
25 */
26
27#include "platform.h"
28#include "gnunet-service-testbed.h"
29#include "gnunet-service-testbed_connectionpool.h"
30#include "gnunet_transport_hello_service.h"
31
32/**
33 * Redefine LOG with a changed log component string
34 */
35#ifdef LOG
36#undef LOG
37#endif
38#define LOG(kind, ...) \
39 GNUNET_log_from (kind, "testbed-OC", __VA_ARGS__)
40
41
42/**
43 * Context information for requesting ATS to connect to a peer
44 */
45struct ConnectivitySuggestContext
46{
47 /**
48 * The transport handle obtained from cache. Do NOT close/disconnect.
49 */
50 struct GNUNET_TRANSPORT_CoreHandle *th_;
51
52 /**
53 * Configuration of the peer from cache. Do not free!
54 */
55 const struct GNUNET_CONFIGURATION_Handle *cfg;
56
57 /**
58 * The GetCacheHandle for the peer2's transport handle
59 * (used to offer the HELLO to the peer).
60 */
61 struct GST_ConnectionPool_GetHandle *cgh_p2_th;
62
63 /**
64 * The GetCacheHandle for the peer2's ATS handle.
65 */
66 struct GST_ConnectionPool_GetHandle *cgh_p2_ats;
67
68 /**
69 * The ATS handle for the connectivity suggestion.
70 */
71 struct GNUNET_ATS_ConnectivitySuggestHandle *csh;
72};
73
74
75/**
76 * Types for context information we create for overlay connect requests
77 */
78enum OverlayConnectContextType
79{
80 /**
81 * This type is used if the overlay connection is local i.e. the connection
82 * has to be made between local peers
83 */
84 OCC_TYPE_LOCAL,
85
86 /**
87 * Type to be used when the first peer is local and the other peer is on a slave
88 * controller started by us
89 */
90 OCC_TYPE_REMOTE_SLAVE,
91
92 /**
93 * Type to be used when the first peer is local and the other peer is on a
94 * controller which is not started by us.
95 */
96 OCC_TYPE_REMOTE_LATERAL
97};
98
99
100/**
101 * Context data for operations on second peer in local overlay connection
102 * contexts
103 */
104struct LocalPeer2Context
105{
106 /**
107 * The handle for offering the HELLO of the first peer to the second
108 * peer.
109 */
110 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
111
112 /**
113 * The transport ConnectivitySuggestContext
114 */
115 struct ConnectivitySuggestContext tcc;
116};
117
118
119/**
120 * Context data for operations on second peer in remote overlay connection
121 * contexts
122 */
123struct RemotePeer2Context
124{
125 /**
126 * Controller of peer 2; If #OCC_TYPE_REMOTE_LATERAL is the type of overlay
127 * connection then this can be NULL until the connection to the controller is
128 * established
129 */
130 struct GNUNET_TESTBED_Controller *p2c;
131
132 /**
133 * Operation context for the suboperation we start to get the identity of the
134 * second peer
135 */
136 struct OperationContext *opc;
137
138 /**
139 * Notification handle acquire to connect to a remote controller. Only used
140 * if the type of overlay connection is #OCC_TYPE_REMOTE_LATERAL.
141 */
142 struct NeighbourConnectNotification *ncn;
143
144 /**
145 * The neighbour handle. Only used if the type of overlay connection is
146 * #OCC_TYPE_REMOTE_LATERAL.
147 */
148 struct Neighbour *p2n;
149};
150
151/**
152 * Context information for connecting 2 peers in overlay.
153 */
154struct OverlayConnectContext
155{
156 /**
157 * The next pointer for maintaining a DLL of all OverlayConnectContexts
158 */
159 struct OverlayConnectContext *next;
160
161 /**
162 * The prev pointer for maintaining a DLL of all OverlayConnectContexts
163 */
164 struct OverlayConnectContext *prev;
165
166 /**
167 * The client which has requested for overlay connection. This is used to send
168 * either a success of failure message
169 */
170 struct GNUNET_SERVICE_Client *client;
171
172 /**
173 * the first peer which is to expect an overlay connection from the second peer.
174 */
175 struct Peer *peer;
176
177 /**
178 * Transport handle of the first peer obtained from cache to get its HELLO. Do
179 * NOT close/disconnect.
180 */
181 struct GNUNET_TRANSPORT_CoreHandle *p1th_;
182
183 /**
184 * The #GST_ConnectionPool_GetHandle for the peer1's transport handle
185 */
186 struct GST_ConnectionPool_GetHandle *cgh_p1th;
187
188 /**
189 * The #GST_ConnectionPool_GetHandle for registering callback to notify CORE
190 * level peer connects and to get our identity.
191 */
192 struct GST_ConnectionPool_GetHandle *cgh_ch;
193
194 /**
195 * HELLO of the first peer. This should be sent to the second peer.
196 */
197 struct GNUNET_MessageHeader *hello;
198
199 /**
200 * Get GetHelloHandle to acquire a HELLO of the first peer
201 */
202 struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
203
204 /**
205 * The error message we send if this overlay connect operation has timed out
206 */
207 char *emsg;
208
209 /**
210 * Context information for operations on the second peer
211 */
212 union
213 {
214 /**
215 * Context information to be used if the second peer is local
216 */
217 struct LocalPeer2Context local;
218
219 /**
220 * Context information to be used if the second peer is remote
221 */
222 struct RemotePeer2Context remote;
223 } p2ctx;
224
225 /**
226 * The peer identity of the first peer
227 */
228 struct GNUNET_PeerIdentity peer_identity;
229
230 /**
231 * The peer identity of the other peer
232 */
233 struct GNUNET_PeerIdentity other_peer_identity;
234
235 /**
236 * The id of the operation responsible for creating this context
237 */
238 uint64_t op_id;
239
240 /**
241 * The id of the task for sending HELLO of peer 2 to peer 1 and ask peer 1 to
242 * connect to peer 2
243 */
244 struct GNUNET_SCHEDULER_Task *send_hello_task;
245
246 /**
247 * The id of the overlay connect timeout task
248 */
249 struct GNUNET_SCHEDULER_Task *timeout_task;
250
251 /**
252 * The id of the cleanup task
253 */
254 struct GNUNET_SCHEDULER_Task *cleanup_task;
255
256 /**
257 * The type of this context information
258 */
259 enum OverlayConnectContextType type;
260
261 /**
262 * The id of the second peer which has to connect to the first peer
263 */
264 uint32_t other_peer_id;
265};
266
267
268/**
269 * Context information for remote overlay connect operations. Remote overlay
270 * connections are used when peers A and B reside on different hosts. In these
271 * operations the host controller for peer B is asked by the host controller of
272 * peer A to make peer B connect to peer A by sending the controller of peer B
273 * the HELLO of peer A.
274 */
275struct RemoteOverlayConnectCtx
276{
277 /**
278 * the next pointer for DLL
279 */
280 struct RemoteOverlayConnectCtx *next;
281
282 /**
283 * the prev pointer for DLL
284 */
285 struct RemoteOverlayConnectCtx *prev;
286
287 /**
288 * The peer handle of peer B
289 */
290 struct Peer *peer;
291
292 /**
293 * Peer A's HELLO
294 */
295 struct GNUNET_MessageHeader *hello;
296
297 /**
298 * The handle for offering HELLO
299 */
300 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh;
301
302 /**
303 * The transport try connect context
304 */
305 struct ConnectivitySuggestContext tcc;
306
307 /**
308 * The peer identity of peer A
309 */
310 struct GNUNET_PeerIdentity a_id;
311
312 /**
313 * Task for offering HELLO of A to B and doing try_connect
314 */
315 struct GNUNET_SCHEDULER_Task *attempt_connect_task_id;
316
317 /**
318 * Task to timeout RequestOverlayConnect
319 */
320 struct GNUNET_SCHEDULER_Task *timeout_rocc_task_id;
321
322 /**
323 * The id of the operation responsible for creating this context
324 */
325 uint64_t op_id;
326};
327
328
329/**
330 * DLL head for OverlayConnectContext DLL - to be used to clean up during shutdown
331 */
332static struct OverlayConnectContext *occq_head;
333
334/**
335 * DLL tail for OverlayConnectContext DLL
336 */
337static struct OverlayConnectContext *occq_tail;
338
339/**
340 * DLL head for RequectOverlayConnectContext DLL - to be used to clean up during
341 * shutdown
342 */
343static struct RemoteOverlayConnectCtx *roccq_head;
344
345/**
346 * DLL tail for RequectOverlayConnectContext DLL
347 */
348static struct RemoteOverlayConnectCtx *roccq_tail;
349
350
351/**
352 * Cleans up ForwardedOverlayConnectContext
353 *
354 * @param focc the ForwardedOverlayConnectContext to cleanup
355 */
356void
357GST_cleanup_focc (struct ForwardedOverlayConnectContext *focc)
358{
359 struct RegisteredHostContext *rhc = focc->rhc;
360
361 GNUNET_CONTAINER_DLL_remove (rhc->focc_dll_head,
362 rhc->focc_dll_tail,
363 focc);
364 GNUNET_free (focc->orig_msg);
365 GNUNET_free (focc);
366}
367
368
369/**
370 * Timeout task for cancelling a forwarded overlay connect connect
371 *
372 * @param cls the `struct ForwardedOperationContext`
373 */
374static void
375forwarded_overlay_connect_timeout (void *cls)
376{
377 struct ForwardedOperationContext *fopc = cls;
378 struct RegisteredHostContext *rhc;
379 struct ForwardedOverlayConnectContext *focc;
380
381 fopc->timeout_task = NULL;
382 rhc = fopc->cls;
383 focc = rhc->focc_dll_head;
384 LOG_DEBUG ("Overlay linking between peers %u and %u failed\n",
385 focc->peer1,
386 focc->peer2);
387 GST_cleanup_focc (focc);
388 GST_forwarded_operation_timeout (fopc);
389 if (NULL != rhc->focc_dll_head)
390 GST_process_next_focc (rhc);
391}
392
393
394/**
395 * Callback to be called when forwarded overlay connection operation has a reply
396 * from the sub-controller successful. We have to relay the reply msg back to
397 * the client
398 *
399 * @param cls ForwardedOperationContext
400 * @param msg the peer create success message
401 */
402static void
403forwarded_overlay_connect_listener (void *cls,
404 const struct GNUNET_MessageHeader *msg)
405{
406 struct ForwardedOperationContext *fopc = cls;
407 struct RegisteredHostContext *rhc;
408 struct ForwardedOverlayConnectContext *focc;
409
410 rhc = fopc->cls;
411 GST_forwarded_operation_reply_relay (cls, msg);
412 focc = rhc->focc_dll_head;
413 GST_cleanup_focc (focc);
414 if (NULL != rhc->focc_dll_head)
415 GST_process_next_focc (rhc);
416}
417
418
419/**
420 * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
421 *
422 * @param rhc the RegisteredHostContext
423 */
424void
425GST_process_next_focc (struct RegisteredHostContext *rhc)
426{
427 struct ForwardedOperationContext *fopc;
428 struct ForwardedOverlayConnectContext *focc;
429 struct Peer *peer;
430 struct Slave *slave;
431
432 focc = rhc->focc_dll_head;
433 GNUNET_assert (NULL != focc);
434 GNUNET_assert (RHC_DONE == rhc->state);
435 GNUNET_assert (VALID_PEER_ID (focc->peer1));
436 peer = GST_peer_list[focc->peer1];
437 GNUNET_assert (GNUNET_YES == peer->is_remote);
438 GNUNET_assert (NULL != (slave = peer->details.remote.slave));
439 fopc = GNUNET_new (struct ForwardedOperationContext);
440 fopc->client = focc->client;
441 fopc->operation_id = focc->operation_id;
442 fopc->cls = rhc;
443 fopc->type = OP_OVERLAY_CONNECT;
444 fopc->opc =
445 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
446 focc->operation_id,
447 focc->orig_msg,
448 &forwarded_overlay_connect_listener,
449 fopc);
450 GNUNET_free (focc->orig_msg);
451 focc->orig_msg = NULL;
452 fopc->timeout_task = GNUNET_SCHEDULER_add_delayed (GST_timeout,
453 &
454 forwarded_overlay_connect_timeout,
455 fopc);
456 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
457 fopcq_tail,
458 fopc);
459}
460
461
462/**
463 * Cleans up any used handles in local peer2 context
464 *
465 * @param lp2c the local peer2 context information
466 */
467static void
468cleanup_occ_lp2c (struct LocalPeer2Context *lp2c)
469{
470 if (NULL != lp2c->ohh)
471 {
472 GNUNET_TRANSPORT_offer_hello_cancel (lp2c->ohh);
473 lp2c->ohh = NULL;
474 }
475 if (NULL != lp2c->tcc.cgh_p2_th)
476 {
477 GST_connection_pool_get_handle_done (lp2c->tcc.cgh_p2_th);
478 lp2c->tcc.cgh_p2_th = NULL;
479 }
480 if (NULL != lp2c->tcc.cgh_p2_ats)
481 {
482 GST_connection_pool_get_handle_done (lp2c->tcc.cgh_p2_ats);
483 lp2c->tcc.cgh_p2_ats = NULL;
484 }
485 if (NULL != lp2c->tcc.csh)
486 {
487 GNUNET_ATS_connectivity_suggest_cancel (lp2c->tcc.csh);
488 lp2c->tcc.csh = NULL;
489 }
490}
491
492
493/**
494 * Cleans up any used handles in remote peer2 context. Relinquishes the
495 * remote controller connection if it has been established on-demand.
496 *
497 * @param rp2c the remote peer2 context information
498 */
499static void
500cleanup_occ_rp2c (struct RemotePeer2Context *rp2c)
501{
502 if (NULL != rp2c->opc)
503 {
504 GNUNET_TESTBED_forward_operation_msg_cancel_ (rp2c->opc);
505 rp2c->opc = NULL;
506 }
507 if (NULL != rp2c->ncn)
508 {
509 GST_neighbour_get_connection_cancel (rp2c->ncn);
510 rp2c->ncn = NULL;
511 }
512 if ((NULL != rp2c->p2c) && (NULL != rp2c->p2n))
513 {
514 GST_neighbour_release_connection (rp2c->p2n);
515 rp2c->p2n = NULL;
516 }
517}
518
519
520/**
521 * Condition for checking if given peer is ready to be destroyed
522 *
523 * @param peer the peer to check
524 */
525#define PEER_EXPIRED(peer) \
526 ((GNUNET_YES == peer->destroy_flag) && (0 == peer->reference_cnt))
527
528/**
529 * Cleanup overlay connect context structure
530 *
531 * @param occ the overlay connect context
532 */
533static void
534cleanup_occ (struct OverlayConnectContext *occ)
535{
536 struct Peer *peer2;
537
538 LOG_DEBUG ("0x%llx: Cleaning up occ\n",
539 (unsigned long long) occ->op_id);
540 GNUNET_free (occ->emsg);
541 GNUNET_free (occ->hello);
542 if (NULL != occ->send_hello_task)
543 GNUNET_SCHEDULER_cancel (occ->send_hello_task);
544 if (NULL != occ->cleanup_task)
545 GNUNET_SCHEDULER_cancel (occ->cleanup_task);
546 if (NULL != occ->timeout_task)
547 GNUNET_SCHEDULER_cancel (occ->timeout_task);
548 if (NULL != occ->cgh_ch)
549 GST_connection_pool_get_handle_done (occ->cgh_ch);
550 if (NULL != occ->ghh)
551 GNUNET_TRANSPORT_hello_get_cancel (occ->ghh);
552 GST_connection_pool_get_handle_done (occ->cgh_p1th);
553 GNUNET_assert (NULL != GST_peer_list);
554 GNUNET_assert (occ->peer->reference_cnt > 0);
555 occ->peer->reference_cnt--;
556 if (PEER_EXPIRED (occ->peer))
557 GST_destroy_peer (occ->peer);
558 switch (occ->type)
559 {
560 case OCC_TYPE_LOCAL:
561 peer2 = GST_peer_list[occ->other_peer_id];
562 GNUNET_assert (peer2->reference_cnt > 0);
563 peer2->reference_cnt--;
564 if (PEER_EXPIRED (peer2))
565 GST_destroy_peer (peer2);
566 cleanup_occ_lp2c (&occ->p2ctx.local);
567 break;
568
569 case OCC_TYPE_REMOTE_SLAVE:
570 case OCC_TYPE_REMOTE_LATERAL:
571 cleanup_occ_rp2c (&occ->p2ctx.remote);
572 break;
573 }
574 GNUNET_CONTAINER_DLL_remove (occq_head,
575 occq_tail,
576 occ);
577 GNUNET_free (occ);
578}
579
580
581/**
582 * Task for cleaning up overlay connect context structure
583 *
584 * @param cls the overlay connect context
585 */
586static void
587do_cleanup_occ (void *cls)
588{
589 struct OverlayConnectContext *occ = cls;
590
591 occ->cleanup_task = NULL;
592 cleanup_occ (occ);
593}
594
595
596/**
597 * Task which will be run when overlay connect request has been timed out
598 *
599 * @param cls the OverlayConnectContext
600 */
601static void
602timeout_overlay_connect (void *cls)
603{
604 struct OverlayConnectContext *occ = cls;
605
606 GNUNET_assert (NULL != occ->timeout_task);
607 occ->timeout_task = NULL;
608 /* LOG (GNUNET_ERROR_TYPE_WARNING, */
609 /* "0x%llx: Timeout while connecting peers %u and %u: %s\n", occ->op_id, */
610 /* occ->peer->id, occ->other_peer_id, occ->emsg); */
611 GST_send_operation_fail_msg (occ->client,
612 occ->op_id,
613 occ->emsg);
614 cleanup_occ (occ);
615}
616
617
618/**
619 * Notify OC subsystem that @a client disconnected.
620 *
621 * @param client the client that disconnected
622 */
623void
624GST_notify_client_disconnect_oc (struct GNUNET_SERVICE_Client *client)
625{
626 struct ForwardedOperationContext *fopc;
627 struct ForwardedOperationContext *fopcn;
628 struct OverlayConnectContext *occ;
629 struct OverlayConnectContext *occn;
630
631 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
632 {
633 fopcn = fopc->next;
634 if (fopc->client == client)
635 {
636 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
637 GST_forwarded_operation_timeout (fopc);
638 }
639 }
640 for (occ = occq_head; NULL != occ; occ = occn)
641 {
642 occn = occ->next;
643 if (occ->client == client)
644 cleanup_occ (occ);
645 }
646 // FIXME: implement clean up for client_keep replacements!
647}
648
649
650/**
651 * FIXME.
652 */
653static void
654send_overlay_connect_success_msg (struct OverlayConnectContext *occ)
655{
656 struct GNUNET_MQ_Envelope *env;
657 struct GNUNET_TESTBED_ConnectionEventMessage *msg;
658
659 LOG_DEBUG ("0x%llx: Peers connected - Sending overlay connect success\n",
660 (unsigned long long) occ->op_id);
661 env = GNUNET_MQ_msg (msg,
662 GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT);
663 msg->event_type = htonl (GNUNET_TESTBED_ET_CONNECT);
664 msg->peer1 = htonl (occ->peer->id);
665 msg->peer2 = htonl (occ->other_peer_id);
666 msg->operation_id = GNUNET_htonll (occ->op_id);
667 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (occ->client),
668 env);
669}
670
671
672/**
673 * Function called to notify transport users that another
674 * peer connected to us.
675 *
676 * @param cls closure
677 * @param new_peer the peer that connected
678 */
679static void
680overlay_connect_notify (void *cls,
681 const struct GNUNET_PeerIdentity *new_peer)
682{
683 struct OverlayConnectContext *occ = cls;
684 char *new_peer_str;
685 char *other_peer_str;
686
687 LOG_DEBUG ("Overlay connect notify\n");
688 if (0 ==
689 GNUNET_memcmp (new_peer,
690 &occ->peer_identity))
691 return;
692 new_peer_str = GNUNET_strdup (GNUNET_i2s (new_peer));
693 other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
694 if (0 !=
695 GNUNET_memcmp (new_peer,
696 &occ->other_peer_identity))
697 {
698 LOG_DEBUG ("Unexpected peer %s connected when expecting peer %s\n",
699 new_peer_str,
700 other_peer_str);
701 GNUNET_free (new_peer_str);
702 GNUNET_free (other_peer_str);
703 return;
704 }
705 GNUNET_free (new_peer_str);
706 LOG_DEBUG ("0x%llx: Peer %s connected to peer %s\n",
707 (unsigned long long) occ->op_id,
708 other_peer_str,
709 GNUNET_i2s (&occ->peer_identity));
710 GNUNET_free (other_peer_str);
711 if (NULL != occ->send_hello_task)
712 {
713 GNUNET_SCHEDULER_cancel (occ->send_hello_task);
714 occ->send_hello_task = NULL;
715 }
716 GNUNET_assert (NULL != occ->timeout_task);
717 GNUNET_SCHEDULER_cancel (occ->timeout_task);
718 occ->timeout_task = NULL;
719 switch (occ->type)
720 {
721 case OCC_TYPE_LOCAL:
722 cleanup_occ_lp2c (&occ->p2ctx.local);
723 break;
724
725 case OCC_TYPE_REMOTE_SLAVE:
726 case OCC_TYPE_REMOTE_LATERAL:
727 cleanup_occ_rp2c (&occ->p2ctx.remote);
728 break;
729 }
730 GNUNET_free (occ->emsg);
731 occ->emsg = NULL;
732 send_overlay_connect_success_msg (occ);
733 occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ,
734 occ);
735}
736
737
738/**
739 * Callback from cache with needed ATS handle set
740 *
741 * @param cls a `struct OverlayConnectCtx *`
742 * @param ch the handle to CORE. Can be NULL if it is not requested
743 * @param th the handle to TRANSPORT. Can be NULL if it is not requested
744 * @param ac the handle to ATS. Can be NULL if it is not requested
745 * @param my_identity the identity of our peer
746 * @param cfg configuration of the peer
747 */
748static void
749occ_cache_get_handle_ats_occ_cb (void *cls,
750 struct GNUNET_CORE_Handle *ch,
751 struct GNUNET_TRANSPORT_CoreHandle *th,
752 struct GNUNET_ATS_ConnectivityHandle *ac,
753 const struct GNUNET_PeerIdentity *my_identity,
754 const struct GNUNET_CONFIGURATION_Handle *cfg)
755{
756 struct OverlayConnectContext *occ = cls;
757 struct LocalPeer2Context *lp2c;
758
759 GNUNET_assert (OCC_TYPE_LOCAL == occ->type);
760 GNUNET_assert (NULL != occ->timeout_task);
761 GNUNET_free (occ->emsg);
762 if (NULL == ac)
763 {
764 GNUNET_asprintf (&occ->emsg,
765 "0x%llx: Failed to connect to ATS of peer with id: %u",
766 (unsigned long long) occ->op_id,
767 occ->peer->id);
768 GNUNET_SCHEDULER_cancel (occ->timeout_task);
769 occ->timeout_task =
770 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect,
771 occ);
772 return;
773 }
774 occ->emsg = NULL;
775
776 GNUNET_asprintf (&occ->emsg,
777 "0x%llx: Timeout during GNUNET_ATS_connectivity_suggest() at peer %s",
778 (unsigned long long) occ->op_id,
779 GNUNET_i2s (&occ->other_peer_identity));
780
781 lp2c = &occ->p2ctx.local;
782 lp2c->tcc.csh =
783 GNUNET_ATS_connectivity_suggest (ac,
784 &occ->peer_identity,
785 1);
786}
787
788
789/**
790 * Callback from cache with needed ATS handle set
791 *
792 * @param cls a `struct RemoteOverlayConnectCtx *`
793 * @param ch the handle to CORE. Can be NULL if it is not requested
794 * @param th the handle to TRANSPORT. Can be NULL if it is not requested
795 * @param ac the handle to ATS. Can be NULL if it is not requested
796 * @param my_identity the identity of our peer
797 */
798static void
799occ_cache_get_handle_ats_rocc_cb (void *cls,
800 struct GNUNET_CORE_Handle *ch,
801 struct GNUNET_TRANSPORT_CoreHandle *th,
802 struct GNUNET_ATS_ConnectivityHandle *ac,
803 const struct GNUNET_PeerIdentity *my_identity,
804 const struct GNUNET_CONFIGURATION_Handle *cfg)
805{
806 struct RemoteOverlayConnectCtx *rocc = cls;
807
808 rocc->tcc.csh =
809 GNUNET_ATS_connectivity_suggest (ac,
810 &rocc->a_id,
811 1);
812}
813
814
815/**
816 * Task to offer HELLO of peer 1 to peer 2 and try to make peer 2 to connect to
817 * peer 1.
818 *
819 * @param cls the OverlayConnectContext
820 */
821static void
822send_hello (void *cls);
823
824
825/**
826 * Task that is run when hello has been sent If tc->reason =
827 * #GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
828 * #GNUNET_SCHEDULER_REASON_READ_READY is succeeded
829 *
830 * @param cls the overlay connect context
831 */
832static void
833occ_hello_sent_cb (void *cls)
834{
835 struct OverlayConnectContext *occ = cls;
836 struct LocalPeer2Context *lp2c;
837 struct Peer *peer2;
838
839 GNUNET_assert (OCC_TYPE_LOCAL == occ->type);
840 GNUNET_assert (NULL != occ->timeout_task);
841 lp2c = &occ->p2ctx.local;
842 lp2c->ohh = NULL;
843
844 GNUNET_assert (NULL == occ->send_hello_task);
845 GNUNET_free (occ->emsg);
846
847 GNUNET_asprintf (&occ->emsg,
848 "0x%llx: Timeout while acquiring ATS of %s from cache",
849 (unsigned long long) occ->op_id,
850 GNUNET_i2s (&occ->other_peer_identity));
851 GNUNET_assert (NULL != (peer2 = GST_peer_list[occ->other_peer_id]));
852 lp2c->tcc.cgh_p2_ats =
853 GST_connection_pool_get_handle (occ->other_peer_id,
854 peer2->details.local.cfg,
855 GST_CONNECTIONPOOL_SERVICE_ATS_CONNECTIVITY,
856 &occ_cache_get_handle_ats_occ_cb,
857 occ, NULL, NULL, NULL);
858}
859
860
861/**
862 * Sends the HELLO of peer1 to peer2's controller through remote overlay connect
863 * request.
864 *
865 * @param occ the overlay connect context. Its type must be either
866 * #OCC_TYPE_REMOTE_SLAVE or #OCC_TYPE_REMOTE_LATERAL
867 */
868static void
869send_hello_thru_rocc (struct OverlayConnectContext *occ)
870{
871 struct GNUNET_TESTBED_RemoteOverlayConnectMessage *msg;
872 char *other_peer_str;
873 uint16_t msize;
874 uint16_t hello_size;
875
876 GNUNET_assert (OCC_TYPE_LOCAL != occ->type);
877 GNUNET_assert (NULL != occ->hello);
878 other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
879 LOG_DEBUG (
880 "0x%llx: Offering HELLO of %s (size: %u) to %s via Remote Overlay Request\n",
881 (unsigned long long) occ->op_id,
882 GNUNET_i2s (&occ->peer_identity),
883 ntohs (occ->hello->size),
884 other_peer_str);
885 GNUNET_free (other_peer_str);
886 hello_size = ntohs (occ->hello->size);
887 msize = sizeof(struct GNUNET_TESTBED_RemoteOverlayConnectMessage)
888 + hello_size;
889 msg = GNUNET_malloc (msize);
890 msg->header.type =
891 htons (GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT);
892 msg->header.size = htons (msize);
893 msg->peer = htonl (occ->other_peer_id);
894 msg->operation_id = GNUNET_htonll (occ->op_id);
895 msg->peer_identity = occ->peer_identity;
896 GNUNET_memcpy (msg->hello,
897 occ->hello,
898 hello_size);
899 GNUNET_TESTBED_queue_message_ (occ->p2ctx.remote.p2c,
900 &msg->header);
901}
902
903
904/**
905 * Task to offer HELLO of peer 1 to peer 2. If peer2 is local it is offered
906 * using its TRANSPORT connection; if remote the HELLO is sent remotely by using
907 * send_hello_thru_rocc()
908 *
909 * @param cls the OverlayConnectContext
910 */
911static void
912send_hello (void *cls)
913{
914 struct OverlayConnectContext *occ = cls;
915 struct LocalPeer2Context *lp2c;
916 char *other_peer_str;
917
918 occ->send_hello_task = NULL;
919 GNUNET_assert (NULL != occ->timeout_task);
920 GNUNET_assert (NULL != occ->hello);
921 if (OCC_TYPE_LOCAL != occ->type)
922 {
923 send_hello_thru_rocc (occ);
924 return;
925 }
926 lp2c = &occ->p2ctx.local;
927 other_peer_str = GNUNET_strdup (GNUNET_i2s (&occ->other_peer_identity));
928 LOG_DEBUG ("0x%llx: Offering HELLO of %s to %s\n",
929 (unsigned long long) occ->op_id,
930 GNUNET_i2s (&occ->peer_identity),
931 other_peer_str);
932 GNUNET_free (other_peer_str);
933 lp2c->ohh =
934 GNUNET_TRANSPORT_offer_hello (lp2c->tcc.cfg,
935 occ->hello,
936 &occ_hello_sent_cb,
937 occ);
938 if (NULL == lp2c->ohh)
939 {
940 GNUNET_break (0);
941 occ->send_hello_task =
942 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
943 (GNUNET_TIME_UNIT_MILLISECONDS,
944 100
945 + GNUNET_CRYPTO_random_u32
946 (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
947 &send_hello, occ);
948 }
949}
950
951
952/**
953 * Callback from cache with needed handles set
954 *
955 * @param cls the closure passed to GST_cache_get_handle_transport()
956 * @param ch the handle to CORE. Can be NULL if it is not requested
957 * @param th the handle to TRANSPORT. Can be NULL if it is not requested
958 * @param ac the handle to ATS. Can be NULL if it is not requested
959 * @param ignore_ peer identity which is ignored in this callback
960 * @param cfg configuration of the peer
961 */
962static void
963p2_transport_connect_cache_callback (void *cls,
964 struct GNUNET_CORE_Handle *ch,
965 struct GNUNET_TRANSPORT_CoreHandle *th,
966 struct GNUNET_ATS_ConnectivityHandle *ac,
967 const struct GNUNET_PeerIdentity *ignore_,
968 const struct
969 GNUNET_CONFIGURATION_Handle *cfg)
970{
971 struct OverlayConnectContext *occ = cls;
972
973 GNUNET_assert (OCC_TYPE_LOCAL == occ->type);
974 if (NULL == th)
975 {
976 GNUNET_asprintf (&occ->emsg,
977 "0x%llx: Cannot connect to TRANSPORT of %s",
978 (unsigned long long) occ->op_id,
979 GNUNET_i2s (&occ->other_peer_identity));
980 GNUNET_SCHEDULER_cancel (occ->timeout_task);
981 occ->timeout_task =
982 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
983 return;
984 }
985 occ->p2ctx.local.tcc.th_ = th;
986 occ->p2ctx.local.tcc.cfg = cfg;
987 GNUNET_asprintf (&occ->emsg,
988 "0x%llx: Timeout while offering HELLO to %s",
989 (unsigned long long) occ->op_id,
990 GNUNET_i2s (&occ->other_peer_identity));
991 occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
992}
993
994
995/**
996 * Connects to the transport of the other peer if it is a local peer and
997 * schedules the send hello task
998 *
999 * @param occ the overlay connect context
1000 */
1001static void
1002p2_transport_connect (struct OverlayConnectContext *occ)
1003{
1004 struct Peer *peer2;
1005
1006 /* HUH? Why to *obtain* HELLO? Seems we use this to *SEND* the
1007 HELLO! */
1008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1009 "Connecting to transport of peer %s to obtain HELLO\n",
1010 GNUNET_i2s (&occ->other_peer_identity));
1011 GNUNET_assert (NULL == occ->emsg);
1012 GNUNET_assert (NULL != occ->hello);
1013 GNUNET_assert (NULL == occ->ghh);
1014 GNUNET_assert (NULL == occ->p1th_);
1015 GNUNET_assert (NULL == occ->cgh_p1th);
1016 if (OCC_TYPE_LOCAL == occ->type)
1017 {
1018 GNUNET_assert (NULL != (peer2 = GST_peer_list[occ->other_peer_id]));
1019 occ->p2ctx.local.tcc.cgh_p2_th =
1020 GST_connection_pool_get_handle (occ->other_peer_id,
1021 peer2->details.local.cfg,
1022 GST_CONNECTIONPOOL_SERVICE_TRANSPORT,
1023 &p2_transport_connect_cache_callback,
1024 occ, NULL, NULL, NULL);
1025 return;
1026 }
1027 GNUNET_asprintf (&occ->emsg,
1028 "0x%llx: Timeout while offering HELLO to %s",
1029 (unsigned long long) occ->op_id,
1030 GNUNET_i2s (&occ->other_peer_identity));
1031 occ->send_hello_task = GNUNET_SCHEDULER_add_now (&send_hello, occ);
1032}
1033
1034
1035/**
1036 * Test for checking whether HELLO message is empty
1037 *
1038 * @param cls empty flag to set
1039 * @param address the HELLO
1040 * @param expiration expiration of the HELLO
1041 * @return #GNUNET_OK
1042 */
1043static int
1044test_address (void *cls,
1045 const struct GNUNET_HELLO_Address *address,
1046 struct GNUNET_TIME_Absolute expiration)
1047{
1048 int *empty = cls;
1049
1050 *empty = GNUNET_NO;
1051 return GNUNET_OK;
1052}
1053
1054
1055/**
1056 * Function called whenever there is an update to the HELLO of peers in the
1057 * OverlayConnectClosure. If we have a valid HELLO, we connect to the peer 2's
1058 * transport and offer peer 1's HELLO and ask peer 2 to connect to peer 1
1059 *
1060 * @param cls closure
1061 * @param hello our updated HELLO
1062 */
1063static void
1064hello_update_cb (void *cls,
1065 const struct GNUNET_MessageHeader *hello)
1066{
1067 struct OverlayConnectContext *occ = cls;
1068 int empty;
1069 uint16_t msize;
1070
1071 msize = ntohs (hello->size);
1072 empty = GNUNET_YES;
1073 (void) GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *)
1074 hello, GNUNET_NO,
1075 &test_address,
1076 &empty);
1077 if (GNUNET_YES == empty)
1078 {
1079 LOG_DEBUG ("0x%llx: HELLO of %s is empty\n",
1080 (unsigned long long) occ->op_id,
1081 GNUNET_i2s (&occ->peer_identity));
1082 return;
1083 }
1084 LOG_DEBUG ("0x%llx: Received HELLO of %s\n",
1085 (unsigned long long) occ->op_id,
1086 GNUNET_i2s (&occ->peer_identity));
1087 occ->hello = GNUNET_malloc (msize);
1088 GST_cache_add_hello (occ->peer->id, hello);
1089 GNUNET_memcpy (occ->hello, hello, msize);
1090 GNUNET_TRANSPORT_hello_get_cancel (occ->ghh);
1091 occ->ghh = NULL;
1092 GST_connection_pool_get_handle_done (occ->cgh_p1th);
1093 occ->cgh_p1th = NULL;
1094 occ->p1th_ = NULL;
1095 GNUNET_free (occ->emsg);
1096 occ->emsg = NULL;
1097 p2_transport_connect (occ);
1098}
1099
1100
1101/**
1102 * Callback from cache with needed handles set
1103 *
1104 * @param cls the closure passed to GST_cache_get_handle_transport()
1105 * @param ch the handle to CORE. Can be NULL if it is not requested
1106 * @param th the handle to TRANSPORT. Can be NULL if it is not requested
1107 * @param ac the handle to ATS. Can be NULL if it is not requested
1108 * @param ignore_ peer identity which is ignored in this callback
1109 */
1110static void
1111p1_transport_connect_cache_callback (void *cls,
1112 struct GNUNET_CORE_Handle *ch,
1113 struct GNUNET_TRANSPORT_CoreHandle *th,
1114 struct GNUNET_ATS_ConnectivityHandle *ac,
1115 const struct GNUNET_PeerIdentity *ignore_,
1116 const struct
1117 GNUNET_CONFIGURATION_Handle *cfg)
1118{
1119 struct OverlayConnectContext *occ = cls;
1120
1121 GNUNET_free (occ->emsg);
1122 occ->emsg = NULL;
1123 if (NULL == th)
1124 {
1125 GNUNET_asprintf (&occ->emsg,
1126 "0x%llx: Cannot connect to TRANSPORT of %s",
1127 (unsigned long long) occ->op_id,
1128 GNUNET_i2s (&occ->peer_identity));
1129 GNUNET_SCHEDULER_cancel (occ->timeout_task);
1130 occ->timeout_task =
1131 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
1132 return;
1133 }
1134 GNUNET_assert (NULL == occ->p1th_);
1135 GNUNET_assert (NULL != occ->cgh_p1th);
1136 occ->p1th_ = th;
1137 GNUNET_asprintf (&occ->emsg,
1138 "0x%llx: Timeout while acquiring HELLO of peer %s",
1139 (unsigned long long) occ->op_id,
1140 GNUNET_i2s (&occ->peer_identity));
1141 occ->ghh = GNUNET_TRANSPORT_hello_get (cfg,
1142 GNUNET_TRANSPORT_AC_ANY,
1143 &hello_update_cb,
1144 occ);
1145}
1146
1147
1148/**
1149 * Callback from cache with needed CORE handle set
1150 *
1151 * @param cls the closure passed to GST_cache_get_handle_transport()
1152 * @param ch the handle to CORE. Can be NULL if it is not requested
1153 * @param th the handle to TRANSPORT. Can be NULL if it is not requested
1154 * @param ac the handle to ATS. Can be NULL if it is not requested
1155 * @param my_identity the identity of our peer
1156 */
1157static void
1158occ_cache_get_handle_core_cb (void *cls,
1159 struct GNUNET_CORE_Handle *ch,
1160 struct GNUNET_TRANSPORT_CoreHandle *th,
1161 struct GNUNET_ATS_ConnectivityHandle *ac,
1162 const struct GNUNET_PeerIdentity *my_identity,
1163 const struct GNUNET_CONFIGURATION_Handle *cfg)
1164{
1165 struct OverlayConnectContext *occ = cls;
1166 const struct GNUNET_MessageHeader *hello;
1167
1168 GNUNET_assert (NULL != occ->timeout_task);
1169 GNUNET_free (occ->emsg);
1170 if ((NULL == ch) || (NULL == my_identity))
1171 {
1172 GNUNET_asprintf (&occ->emsg,
1173 "0x%llx: Failed to connect to CORE of peer with "
1174 "id: %u",
1175 (unsigned long long) occ->op_id,
1176 occ->peer->id);
1177 GNUNET_SCHEDULER_cancel (occ->timeout_task);
1178 occ->timeout_task =
1179 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
1180 return;
1181 }
1182 occ->emsg = NULL;
1183 occ->peer_identity = *my_identity;
1184 if (NULL !=
1185 GNUNET_CORE_get_mq (ch,
1186 &occ->other_peer_identity))
1187 {
1188 LOG_DEBUG ("0x%llx: Target peer %s already connected\n",
1189 (unsigned long long) occ->op_id,
1190 GNUNET_i2s (&occ->other_peer_identity));
1191 LOG_DEBUG ("0x%llx: Target peer %s connected\n",
1192 (unsigned long long) occ->op_id,
1193 GNUNET_i2s (&occ->peer_identity));
1194 GNUNET_SCHEDULER_cancel (occ->timeout_task);
1195 occ->timeout_task = NULL;
1196 send_overlay_connect_success_msg (occ);
1197 occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
1198 return;
1199 }
1200 LOG_DEBUG ("0x%llx: Acquiring HELLO of peer %s\n",
1201 (unsigned long long) occ->op_id,
1202 GNUNET_i2s (&occ->peer_identity));
1203 /* Lookup for HELLO in hello cache */
1204 if (NULL != (hello = GST_cache_lookup_hello (occ->peer->id)))
1205 {
1206 LOG_DEBUG ("0x%llx: HELLO of peer %s found in cache\n",
1207 (unsigned long long) occ->op_id,
1208 GNUNET_i2s (&occ->peer_identity));
1209 occ->hello = GNUNET_copy_message (hello);
1210 p2_transport_connect (occ);
1211 return;
1212 }
1213 GNUNET_asprintf (&occ->emsg,
1214 "0x%llx: Timeout while acquiring TRANSPORT of %s from cache",
1215 (unsigned long long) occ->op_id,
1216 GNUNET_i2s (&occ->peer_identity));
1217 occ->cgh_p1th =
1218 GST_connection_pool_get_handle (occ->peer->id,
1219 occ->peer->details.local.cfg,
1220 GST_CONNECTIONPOOL_SERVICE_TRANSPORT,
1221 p1_transport_connect_cache_callback,
1222 occ,
1223 NULL, NULL, NULL);
1224}
1225
1226
1227/**
1228 * Callback to be called when forwarded get peer config operation as part of
1229 * overlay connect is successful. Connection to Peer 1's core is made and is
1230 * checked for new connection from peer 2
1231 *
1232 * @param cls ForwardedOperationContext
1233 * @param msg the peer create success message
1234 */
1235static void
1236overlay_connect_get_config (void *cls,
1237 const struct GNUNET_MessageHeader *msg)
1238{
1239 struct OverlayConnectContext *occ = cls;
1240 struct RemotePeer2Context *rp2c;
1241 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *cmsg;
1242
1243 GNUNET_assert (OCC_TYPE_LOCAL != occ->type);
1244 rp2c = &occ->p2ctx.remote;
1245 rp2c->opc = NULL;
1246 GNUNET_assert (NULL != occ->timeout_task);
1247 if (GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION != ntohs (msg->type))
1248 {
1249 GNUNET_SCHEDULER_cancel (occ->timeout_task);
1250 occ->timeout_task =
1251 GNUNET_SCHEDULER_add_now (&timeout_overlay_connect, occ);
1252 }
1253 cmsg =
1254 (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
1255 occ->other_peer_identity = cmsg->peer_identity;
1256 GNUNET_free (occ->emsg);
1257 GNUNET_asprintf (&occ->emsg,
1258 "0x%llx: Timeout while connecting to CORE of peer with "
1259 "id: %u",
1260 (unsigned long long) occ->op_id,
1261 occ->peer->id);
1262 occ->cgh_ch =
1263 GST_connection_pool_get_handle (occ->peer->id,
1264 occ->peer->details.local.cfg,
1265 GST_CONNECTIONPOOL_SERVICE_CORE,
1266 &occ_cache_get_handle_core_cb,
1267 occ,
1268 &occ->other_peer_identity,
1269 &overlay_connect_notify,
1270 occ);
1271}
1272
1273
1274/**
1275 * Callback which will be called after a host registration succeeded or failed
1276 *
1277 * @param cls the RegisteredHostContext
1278 * @param emsg the error message; NULL if host registration is successful
1279 */
1280static void
1281host_registration_comp (void *cls, const char *emsg)
1282{
1283 struct RegisteredHostContext *rhc = cls;
1284
1285 rhc->state = RHC_DONE;
1286 GST_process_next_focc (rhc);
1287}
1288
1289
1290/**
1291 * Iterator to match a registered host context
1292 *
1293 * @param cls pointer 2 pointer of RegisteredHostContext
1294 * @param key current key code
1295 * @param value value in the hash map
1296 * @return #GNUNET_YES if we should continue to
1297 * iterate,
1298 * #GNUNET_NO if not.
1299 */
1300static int
1301reghost_match_iterator (void *cls,
1302 const struct GNUNET_HashCode *key,
1303 void *value)
1304{
1305 struct RegisteredHostContext **rh = cls;
1306 struct RegisteredHostContext *rh_val = value;
1307
1308 if ((rh_val->host == (*rh)->host) && (rh_val->reg_host == (*rh)->reg_host))
1309 {
1310 GNUNET_free (*rh);
1311 *rh = rh_val;
1312 return GNUNET_NO;
1313 }
1314 return GNUNET_YES;
1315}
1316
1317
1318/**
1319 * Function to generate the hashcode corresponding to a RegisteredHostContext
1320 *
1321 * @param reg_host the host which is being registered in RegisteredHostContext
1322 * @param host the host of the controller which has to connect to the above rhost
1323 * @return the hashcode
1324 */
1325static struct GNUNET_HashCode
1326hash_hosts (struct GNUNET_TESTBED_Host *reg_host,
1327 struct GNUNET_TESTBED_Host *host)
1328{
1329 struct GNUNET_HashCode hash;
1330 uint32_t host_ids[2];
1331
1332 host_ids[0] = GNUNET_TESTBED_host_get_id_ (reg_host);
1333 host_ids[1] = GNUNET_TESTBED_host_get_id_ (host);
1334 GNUNET_CRYPTO_hash (host_ids, sizeof(host_ids), &hash);
1335 return hash;
1336}
1337
1338
1339/**
1340 * Checks if the given host is registered at the given slave.
1341 *
1342 * @param slave the slave where registration has to be checked. The check is
1343 * actually done through a locally maintained hashmap. No
1344 * communication with the slave is involved.
1345 * @param host the host to register
1346 * @return If the given host is not registered already or the registration is
1347 * pending, it returns the registration context. Any overlay connects
1348 * to be forwarded should be queued in the context so that they can be
1349 * executed when the registration is completed. If the given host is
1350 * already registered, NULL is returned.
1351 */
1352static struct RegisteredHostContext *
1353register_host (struct Slave *slave,
1354 struct GNUNET_TESTBED_Host *host)
1355{
1356 struct GNUNET_HashCode hash;
1357 struct RegisteredHostContext *rhc;
1358
1359 rhc = GNUNET_new (struct RegisteredHostContext);
1360 rhc->reg_host = host;
1361 rhc->host = GST_host_list[slave->host_id];
1362 GNUNET_assert (NULL != rhc->reg_host);
1363 GNUNET_assert (NULL != rhc->host);
1364 rhc->state = RHC_INIT;
1365 hash = hash_hosts (rhc->reg_host, rhc->host);
1366 if ((GNUNET_NO ==
1367 GNUNET_CONTAINER_multihashmap_contains (slave->reghost_map,
1368 &hash)) ||
1369 (GNUNET_SYSERR !=
1370 GNUNET_CONTAINER_multihashmap_get_multiple (slave->reghost_map,
1371 &hash,
1372 reghost_match_iterator,
1373 &rhc)))
1374 {
1375 /* create and add a new registered host context */
1376 /* add the focc to its queue */
1377 GNUNET_CONTAINER_multihashmap_put (slave->reghost_map,
1378 &hash,
1379 rhc,
1380 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1381 GST_queue_host_registration (slave,
1382 host_registration_comp,
1383 rhc,
1384 rhc->reg_host);
1385 }
1386 else
1387 {
1388 /* rhc is now set to the existing one from the hash map by
1389 * reghost_match_iterator() */
1390 /* if queue is empty then ignore creating focc and proceed with normal
1391 * forwarding */
1392 if (RHC_DONE == rhc->state)
1393 return NULL;
1394 }
1395 return rhc;
1396}
1397
1398
1399/**
1400 * Forwards the overlay connect request to a slave controller. Before
1401 * forwarding, any hosts which are needed to be known by the slave controller to
1402 * execute the overlay connect request are registered at slave.
1403 *
1404 * @param msg the overlay connect request message to be forwarded
1405 * @param client the client to which the status of the forwarded request has to
1406 * be notified
1407 */
1408static void
1409forward_overlay_connect (const struct GNUNET_TESTBED_OverlayConnectMessage *msg,
1410 struct GNUNET_SERVICE_Client *client)
1411{
1412 struct ForwardedOperationContext *fopc;
1413 struct Route *route_to_peer2_host;
1414 struct Route *route_to_peer1_host;
1415 struct Peer *peer;
1416 struct RegisteredHostContext *rhc;
1417 struct ForwardedOverlayConnectContext *focc;
1418 uint64_t op_id;
1419 uint32_t peer2_host_id;
1420 uint32_t p1;
1421 uint32_t p2;
1422
1423 p1 = ntohl (msg->peer1);
1424 p2 = ntohl (msg->peer2);
1425 op_id = GNUNET_ntohll (msg->operation_id);
1426 peer2_host_id = ntohl (msg->peer2_host_id);
1427 GNUNET_assert (VALID_PEER_ID (p1));
1428 GNUNET_assert (VALID_HOST_ID (peer2_host_id));
1429 peer = GST_peer_list[p1];
1430 GNUNET_assert (GNUNET_YES == peer->is_remote);
1431 LOG_DEBUG ("0x%llx: Forwarding overlay connect\n",
1432 (unsigned long long) op_id);
1433 route_to_peer2_host = GST_find_dest_route (peer2_host_id);
1434 route_to_peer1_host = GST_find_dest_route
1435 (peer->details.remote.remote_host_id);
1436 GNUNET_assert (NULL != route_to_peer1_host);
1437 if ((NULL != route_to_peer2_host) &&
1438 (route_to_peer1_host->dest == route_to_peer2_host->dest))
1439 goto forward;
1440 /* Peer2 is either with us OR peer1 and peer2 can be reached through
1441 different subtrees OR peer2 is on a subtree unknown to us */
1442 if (NULL != (rhc = register_host (peer->details.remote.slave,
1443 GST_host_list[peer2_host_id])))
1444 {
1445 LOG_DEBUG ("Queueing forwarding FOCC for connecting peers %u and %u\n", p1,
1446 p2);
1447 focc = GNUNET_new (struct ForwardedOverlayConnectContext);
1448 focc->rhc = rhc;
1449 focc->peer1 = p1;
1450 focc->peer2 = p2;
1451 focc->peer2_host_id = peer2_host_id;
1452 focc->orig_msg = GNUNET_copy_message (&msg->header);
1453 focc->operation_id = op_id;
1454 focc->client = client;
1455 GNUNET_CONTAINER_DLL_insert_tail (rhc->focc_dll_head,
1456 rhc->focc_dll_tail,
1457 focc);
1458 return;
1459 }
1460
1461forward:
1462 LOG_DEBUG ("Forwarding without FOCC for connecting peers %u and %u\n", p1,
1463 p2);
1464 fopc = GNUNET_new (struct ForwardedOperationContext);
1465 fopc->client = client;
1466 fopc->operation_id = op_id;
1467 fopc->type = OP_OVERLAY_CONNECT;
1468 fopc->opc =
1469 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1470 slave->controller, op_id,
1471 &msg->header,
1472 &GST_forwarded_operation_reply_relay,
1473 fopc);
1474 fopc->timeout_task =
1475 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1476 &GST_forwarded_operation_timeout,
1477 fopc);
1478 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1479 fopcq_tail,
1480 fopc);
1481}
1482
1483
1484/**
1485 * Callback called when a connection to the controller of peer2 has been
1486 * established
1487 *
1488 * @param cls the overlay connect contexts
1489 * @param c handle to the controller connection
1490 */
1491static void
1492p2_controller_connect_cb (void *cls,
1493 struct GNUNET_TESTBED_Controller *c)
1494{
1495 struct OverlayConnectContext *occ = cls;
1496 struct RemotePeer2Context *rp2c;
1497 struct GNUNET_TESTBED_PeerGetConfigurationMessage cmsg;
1498
1499 GNUNET_assert (OCC_TYPE_LOCAL != occ->type);
1500 rp2c = &occ->p2ctx.remote;
1501 rp2c->ncn = NULL;
1502 rp2c->p2c = c;
1503 cmsg.header.size =
1504 htons (sizeof(struct GNUNET_TESTBED_PeerGetConfigurationMessage));
1505 cmsg.header.type =
1506 htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION);
1507 cmsg.peer_id = htonl (occ->other_peer_id);
1508 cmsg.operation_id = GNUNET_htonll (occ->op_id);
1509 rp2c->opc =
1510 GNUNET_TESTBED_forward_operation_msg_ (rp2c->p2c,
1511 occ->op_id,
1512 &cmsg.header,
1513 &overlay_connect_get_config,
1514 occ);
1515 GNUNET_free (occ->emsg);
1516 GNUNET_asprintf (&occ->emsg,
1517 "0x%llx: Timeout while getting peer identity of peer "
1518 "with id: %u",
1519 (unsigned long long) occ->op_id,
1520 occ->other_peer_id);
1521}
1522
1523
1524/**
1525 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT messages
1526 *
1527 * @param cls identification of the client
1528 * @param msg the actual message
1529 */
1530void
1531handle_overlay_connect (void *cls,
1532 const struct GNUNET_TESTBED_OverlayConnectMessage *msg)
1533{
1534 struct GNUNET_SERVICE_Client *client = cls;
1535 struct Peer *peer;
1536 struct Peer *peer2;
1537 struct OverlayConnectContext *occ;
1538 struct Neighbour *p2n;
1539 uint64_t operation_id;
1540 uint32_t p1;
1541 uint32_t p2;
1542 uint32_t peer2_host_id;
1543
1544 p1 = ntohl (msg->peer1);
1545 p2 = ntohl (msg->peer2);
1546 if (p1 == p2)
1547 {
1548 GNUNET_break (0);
1549 GNUNET_SERVICE_client_drop (client);
1550 return;
1551 }
1552 if (! VALID_PEER_ID (p1))
1553 {
1554 GNUNET_break (0);
1555 GNUNET_SERVICE_client_drop (client);
1556 return;
1557 }
1558 peer = GST_peer_list[p1];
1559 operation_id = GNUNET_ntohll (msg->operation_id);
1560 LOG_DEBUG
1561 ("Received overlay connect for peers %u and %u with op id: 0x%llx\n",
1562 p1,
1563 p2,
1564 (unsigned long long) operation_id);
1565 peer2_host_id = ntohl (msg->peer2_host_id);
1566 if (GNUNET_YES == peer->is_remote)
1567 {
1568 if (! VALID_HOST_ID (peer2_host_id))
1569 {
1570 GNUNET_break (0);
1571 GNUNET_SERVICE_client_drop (client);
1572 return;
1573 }
1574 forward_overlay_connect (msg, client);
1575 GNUNET_SERVICE_client_continue (client);
1576 return;
1577 }
1578 p2n = NULL;
1579 occ = GNUNET_new (struct OverlayConnectContext);
1580 occ->type = OCC_TYPE_LOCAL;
1581 if (! VALID_PEER_ID (p2)) /* May be peer2 is on a another controller */
1582 {
1583 if (NULL == (p2n = GST_get_neighbour (peer2_host_id)))
1584 {
1585 if (! VALID_HOST_ID (peer2_host_id))
1586 {
1587 GNUNET_break (0);
1588 LOG (GNUNET_ERROR_TYPE_WARNING,
1589 "0x%llx: Peer %u's host not in our neighbours list\n",
1590 (unsigned long long) operation_id, p2);
1591 GNUNET_SERVICE_client_drop (client);
1592 GNUNET_free (occ);
1593 return;
1594 }
1595 p2n = GST_create_neighbour (GST_host_list[peer2_host_id]);
1596 }
1597 occ->type = OCC_TYPE_REMOTE_LATERAL;
1598 occ->p2ctx.remote.p2n = p2n;
1599 }
1600 else if (GNUNET_YES == GST_peer_list[p2]->is_remote)
1601 {
1602 occ->type = OCC_TYPE_REMOTE_SLAVE;
1603 occ->p2ctx.remote.p2c = GST_peer_list[p2]->details.remote.slave->controller;
1604 }
1605 GNUNET_CONTAINER_DLL_insert_tail (occq_head,
1606 occq_tail,
1607 occ);
1608 occ->client = client;
1609 occ->other_peer_id = p2;
1610 GST_peer_list[p1]->reference_cnt++;
1611 occ->peer = GST_peer_list[p1];
1612 occ->op_id = operation_id;
1613 GNUNET_assert (NULL == occ->timeout_task);
1614 occ->timeout_task =
1615 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1616 &timeout_overlay_connect,
1617 occ);
1618 switch (occ->type)
1619 {
1620 case OCC_TYPE_REMOTE_LATERAL:
1621 GNUNET_asprintf (&occ->emsg,
1622 "0x%llx: Timeout while acquiring connection to peer %u's "
1623 "host: %u\n",
1624 (unsigned long long) occ->op_id,
1625 occ->other_peer_id,
1626 peer2_host_id);
1627 occ->p2ctx.remote.ncn
1628 = GST_neighbour_get_connection (p2n,
1629 &p2_controller_connect_cb,
1630 occ);
1631 break;
1632 case OCC_TYPE_REMOTE_SLAVE:
1633 p2_controller_connect_cb (occ,
1634 occ->p2ctx.remote.p2c);
1635 break;
1636 case OCC_TYPE_LOCAL:
1637 peer2 = GST_peer_list[occ->other_peer_id];
1638 peer2->reference_cnt++;
1639 GNUNET_TESTING_peer_get_identity (peer2->details.local.peer,
1640 &occ->other_peer_identity);
1641 GNUNET_asprintf (&occ->emsg,
1642 "0x%llx: Timeout while connecting to CORE of peer with "
1643 "id: %u",
1644 (unsigned long long) occ->op_id,
1645 occ->peer->id);
1646 LOG_DEBUG ("Peer %u has PID %s\n",
1647 occ->other_peer_id,
1648 GNUNET_i2s (&occ->other_peer_identity));
1649 {
1650 struct GNUNET_PeerIdentity lpid;
1651
1652 GNUNET_TESTING_peer_get_identity (peer->details.local.peer,
1653 &lpid);
1654 LOG_DEBUG ("Peer %u has PID %s\n",
1655 p1,
1656 GNUNET_i2s (&lpid));
1657 }
1658 occ->cgh_ch =
1659 GST_connection_pool_get_handle (occ->peer->id,
1660 occ->peer->details.local.cfg,
1661 GST_CONNECTIONPOOL_SERVICE_CORE,
1662 &occ_cache_get_handle_core_cb, occ,
1663 &occ->other_peer_identity,
1664 &overlay_connect_notify, occ);
1665 break;
1666 }
1667 GNUNET_SERVICE_client_continue (client);
1668}
1669
1670
1671/**
1672 * Function to cleanup RemoteOverlayConnectCtx and any associated tasks
1673 * with it
1674 *
1675 * @param rocc the RemoteOverlayConnectCtx
1676 */
1677static void
1678cleanup_rocc (struct RemoteOverlayConnectCtx *rocc)
1679{
1680 LOG_DEBUG ("0x%llx: Cleaning up rocc\n",
1681 (unsigned long long) rocc->op_id);
1682 if (NULL != rocc->attempt_connect_task_id)
1683 GNUNET_SCHEDULER_cancel (rocc->attempt_connect_task_id);
1684 if (NULL != rocc->timeout_rocc_task_id)
1685 GNUNET_SCHEDULER_cancel (rocc->timeout_rocc_task_id);
1686 if (NULL != rocc->ohh)
1687 GNUNET_TRANSPORT_offer_hello_cancel (rocc->ohh);
1688 if (NULL != rocc->tcc.csh)
1689 GNUNET_ATS_connectivity_suggest_cancel (rocc->tcc.csh);
1690 GST_connection_pool_get_handle_done (rocc->tcc.cgh_p2_th);
1691 GST_connection_pool_get_handle_done (rocc->tcc.cgh_p2_ats);
1692 GNUNET_assert (rocc->peer->reference_cnt > 0);
1693 rocc->peer->reference_cnt--;
1694 if ((GNUNET_YES == rocc->peer->destroy_flag) &&
1695 (0 == rocc->peer->reference_cnt))
1696 GST_destroy_peer (rocc->peer);
1697 GNUNET_free (rocc->hello);
1698 GNUNET_CONTAINER_DLL_remove (roccq_head,
1699 roccq_tail,
1700 rocc);
1701 GNUNET_free (rocc);
1702}
1703
1704
1705/**
1706 * Task to timeout rocc and cleanit up
1707 *
1708 * @param cls the RemoteOverlayConnectCtx
1709 */
1710static void
1711timeout_rocc_task (void *cls)
1712{
1713 struct RemoteOverlayConnectCtx *rocc = cls;
1714
1715 GNUNET_assert (rocc->timeout_rocc_task_id != NULL);
1716 rocc->timeout_rocc_task_id = NULL;
1717 LOG_DEBUG ("0x%llx: rocc timed out\n",
1718 (unsigned long long) rocc->op_id);
1719 cleanup_rocc (rocc);
1720}
1721
1722
1723/**
1724 * Function called to notify transport users that another
1725 * peer connected to us.
1726 *
1727 * @param cls the RemoteOverlayConnectContext
1728 * @param new_peer the peer that connected
1729 */
1730static void
1731cache_transport_peer_connect_notify (void *cls,
1732 const struct GNUNET_PeerIdentity *new_peer)
1733{
1734 struct RemoteOverlayConnectCtx *rocc = cls;
1735
1736 LOG_DEBUG ("0x%llx: Request Overlay connect notify\n",
1737 (unsigned long long) rocc->op_id);
1738 GNUNET_assert (0 ==
1739 memcmp (new_peer, &rocc->a_id,
1740 sizeof(struct GNUNET_PeerIdentity)));
1741 LOG_DEBUG ("0x%llx: Peer %s connected\n",
1742 (unsigned long long) rocc->op_id,
1743 GNUNET_i2s (&rocc->a_id));
1744 cleanup_rocc (rocc);
1745}
1746
1747
1748/**
1749 * Task to offer the HELLO message to the peer and ask it to connect to the peer
1750 * whose identity is in RemoteOverlayConnectCtx
1751 *
1752 * @param cls the RemoteOverlayConnectCtx
1753 */
1754static void
1755attempt_connect_task (void *cls);
1756
1757
1758/**
1759 * Task that is run when hello has been sent If tc->reason =
1760 * #GNUNET_SCHEDULER_REASON_TIMEOUT then sending HELLO failed; if
1761 * #GNUNET_SCHEDULER_REASON_READ_READY is succeeded
1762 *
1763 * @param cls the overlay connect context
1764 */
1765static void
1766rocc_hello_sent_cb (void *cls)
1767{
1768 struct RemoteOverlayConnectCtx *rocc = cls;
1769
1770 rocc->ohh = NULL;
1771 GNUNET_assert (NULL == rocc->attempt_connect_task_id);
1772 LOG_DEBUG ("0x%llx: HELLO of peer %s delivered to local peer with id: %u\n",
1773 (unsigned long long) rocc->op_id,
1774 GNUNET_i2s (&rocc->a_id),
1775 rocc->peer->id);
1776 rocc->tcc.cgh_p2_ats =
1777 GST_connection_pool_get_handle (rocc->peer->id,
1778 rocc->peer->details.local.cfg,
1779 GST_CONNECTIONPOOL_SERVICE_ATS_CONNECTIVITY,
1780 &occ_cache_get_handle_ats_rocc_cb,
1781 rocc, NULL, NULL, NULL);
1782}
1783
1784
1785/**
1786 * Task to offer the HELLO message to the peer and ask it to connect to the peer
1787 * whose identity is in RemoteOverlayConnectCtx
1788 *
1789 * @param cls the RemoteOverlayConnectCtx
1790 */
1791static void
1792attempt_connect_task (void *cls)
1793{
1794 struct RemoteOverlayConnectCtx *rocc = cls;
1795
1796 GNUNET_assert (NULL != rocc->attempt_connect_task_id);
1797 rocc->attempt_connect_task_id = NULL;
1798 LOG_DEBUG ("0x%llx: Offering HELLO of peer %s to remote peer with id: %u\n",
1799 (unsigned long long) rocc->op_id,
1800 GNUNET_i2s (&rocc->a_id),
1801 rocc->peer->id);
1802 rocc->ohh =
1803 GNUNET_TRANSPORT_offer_hello (rocc->tcc.cfg,
1804 rocc->hello,
1805 &rocc_hello_sent_cb,
1806 rocc);
1807 if (NULL == rocc->ohh)
1808 rocc->attempt_connect_task_id =
1809 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1810 (GNUNET_TIME_UNIT_MILLISECONDS,
1811 100
1812 + GNUNET_CRYPTO_random_u32
1813 (GNUNET_CRYPTO_QUALITY_WEAK, 500)),
1814 &attempt_connect_task, rocc);
1815}
1816
1817
1818/**
1819 * Callback from cache with needed handles set
1820 *
1821 * @param cls the closure passed to GST_cache_get_handle_transport()
1822 * @param ch the handle to CORE. Can be NULL if it is not requested
1823 * @param th the handle to TRANSPORT. Can be NULL if it is not requested
1824 * @param ac the handle to ATS. Can be NULL if it is not requested
1825 * @param ignore_ peer identity which is ignored in this callback
1826 */
1827static void
1828rocc_cache_get_handle_transport_cb (void *cls,
1829 struct GNUNET_CORE_Handle *ch,
1830 struct GNUNET_TRANSPORT_CoreHandle *th,
1831 struct GNUNET_ATS_ConnectivityHandle *ac,
1832 const struct GNUNET_PeerIdentity *ignore_,
1833 const struct
1834 GNUNET_CONFIGURATION_Handle *cfg)
1835{
1836 struct RemoteOverlayConnectCtx *rocc = cls;
1837
1838 if (NULL == th)
1839 {
1840 rocc->timeout_rocc_task_id =
1841 GNUNET_SCHEDULER_add_now (&timeout_rocc_task, rocc);
1842 return;
1843 }
1844 rocc->tcc.th_ = th;
1845 rocc->tcc.cfg = cfg;
1846 if (NULL !=
1847 GNUNET_TRANSPORT_core_get_mq (rocc->tcc.th_,
1848 &rocc->a_id))
1849 {
1850 LOG_DEBUG ("0x%llx: Target peer %s already connected to local peer: %u\n",
1851 (unsigned long long) rocc->op_id,
1852 GNUNET_i2s (&rocc->a_id),
1853 rocc->peer->id);
1854 cleanup_rocc (rocc);
1855 return;
1856 }
1857 rocc->attempt_connect_task_id =
1858 GNUNET_SCHEDULER_add_now (&attempt_connect_task, rocc);
1859}
1860
1861
1862/**
1863 * Check #GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT messages
1864 *
1865 * @param cls identification of the client
1866 * @param msg the actual message
1867 * @return #GNUNET_OK if @a msg is well-formed
1868 */
1869int
1870check_remote_overlay_connect (void *cls,
1871 const struct
1872 GNUNET_TESTBED_RemoteOverlayConnectMessage *msg)
1873{
1874 uint32_t peer_id;
1875 uint16_t msize;
1876 uint16_t hsize;
1877
1878 msize = ntohs (msg->header.size);
1879 if (GNUNET_MESSAGE_TYPE_HELLO != ntohs (msg->hello->type))
1880 {
1881 GNUNET_break (0);
1882 return GNUNET_SYSERR;
1883 }
1884 hsize = ntohs (msg->hello->size);
1885 if ((sizeof(struct GNUNET_TESTBED_RemoteOverlayConnectMessage) + hsize) !=
1886 msize)
1887 {
1888 GNUNET_break (0);
1889 return GNUNET_SYSERR;
1890 }
1891 peer_id = ntohl (msg->peer);
1892 if ((peer_id >= GST_peer_list_size) ||
1893 (NULL == GST_peer_list[peer_id]))
1894 {
1895 GNUNET_break_op (0);
1896 return GNUNET_SYSERR;
1897 }
1898 return GNUNET_OK;
1899}
1900
1901
1902/**
1903 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT messages
1904 *
1905 * @param cls identification of the client
1906 * @param msg the actual message
1907 */
1908void
1909handle_remote_overlay_connect (void *cls,
1910 const struct
1911 GNUNET_TESTBED_RemoteOverlayConnectMessage *msg)
1912{
1913 struct GNUNET_SERVICE_Client *client = cls;
1914 struct RemoteOverlayConnectCtx *rocc;
1915 struct Peer *peer;
1916 struct GNUNET_PeerIdentity pid;
1917 static char pid_str[16];
1918 uint32_t peer_id;
1919 uint16_t hsize;
1920
1921 hsize = ntohs (msg->hello->size);
1922 peer_id = ntohl (msg->peer);
1923 peer = GST_peer_list[peer_id];
1924 if (GNUNET_YES == peer->is_remote)
1925 {
1926 struct GNUNET_MessageHeader *msg2;
1927
1928 msg2 = GNUNET_copy_message (&msg->header);
1929 GNUNET_TESTBED_queue_message_ (peer->details.remote.slave->controller,
1930 msg2);
1931 GNUNET_SERVICE_client_continue (client);
1932 return;
1933 }
1934 rocc = GNUNET_new (struct RemoteOverlayConnectCtx);
1935 rocc->op_id = GNUNET_ntohll (msg->operation_id);
1936 GNUNET_CONTAINER_DLL_insert_tail (roccq_head,
1937 roccq_tail,
1938 rocc);
1939 rocc->a_id = msg->peer_identity;
1940 GNUNET_TESTING_peer_get_identity (peer->details.local.peer,
1941 &pid);
1942 (void) GNUNET_strlcpy (pid_str,
1943 GNUNET_i2s (&pid),
1944 sizeof(pid_str));
1945 LOG_DEBUG (
1946 "0x%llx: Remote overlay connect %s to peer %s with hello size: %u\n",
1947 (unsigned long long) rocc->op_id,
1948 pid_str,
1949 GNUNET_i2s (&rocc->a_id),
1950 hsize);
1951 rocc->peer = peer;
1952 rocc->peer->reference_cnt++;
1953 rocc->hello = GNUNET_malloc (hsize);
1954 GNUNET_memcpy (rocc->hello,
1955 msg->hello,
1956 hsize);
1957 rocc->tcc.cgh_p2_th =
1958 GST_connection_pool_get_handle (peer_id,
1959 rocc->peer->details.local.cfg,
1960 GST_CONNECTIONPOOL_SERVICE_TRANSPORT,
1961 &rocc_cache_get_handle_transport_cb,
1962 rocc,
1963 &rocc->a_id,
1964 &cache_transport_peer_connect_notify,
1965 rocc);
1966 rocc->timeout_rocc_task_id =
1967 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1968 &timeout_rocc_task,
1969 rocc);
1970 GNUNET_SERVICE_client_continue (client);
1971}
1972
1973
1974/**
1975 * Clears all pending overlay connect contexts in queue
1976 */
1977void
1978GST_free_occq ()
1979{
1980 struct OverlayConnectContext *occ;
1981
1982 while (NULL != (occ = occq_head))
1983 cleanup_occ (occ);
1984}
1985
1986
1987/**
1988 * Clears all pending remote overlay connect contexts in queue
1989 */
1990void
1991GST_free_roccq ()
1992{
1993 struct RemoteOverlayConnectCtx *rocc;
1994
1995 while (NULL != (rocc = roccq_head))
1996 cleanup_rocc (rocc);
1997}
diff --git a/src/testbed/gnunet-service-testbed_peers.c b/src/testbed/gnunet-service-testbed_peers.c
deleted file mode 100644
index 05410c26a..000000000
--- a/src/testbed/gnunet-service-testbed_peers.c
+++ /dev/null
@@ -1,1552 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21
22/**
23 * @file testbed/gnunet-service-testbed_peers.c
24 * @brief implementation of TESTBED service that deals with peer management
25 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 */
27
28#include "platform.h"
29#include "gnunet-service-testbed.h"
30#include "gnunet_arm_service.h"
31#include <zlib.h>
32
33
34/**
35 * A list of peers we know about
36 */
37struct Peer **GST_peer_list;
38
39/**
40 * The current number of peers running locally under this controller
41 */
42unsigned int GST_num_local_peers;
43
44
45/**
46 * Context information to manage peers' services
47 */
48struct ManageServiceContext
49{
50 /**
51 * DLL next ptr
52 */
53 struct ManageServiceContext *next;
54
55 /**
56 * DLL prev ptr
57 */
58 struct ManageServiceContext *prev;
59
60 /**
61 * The ARM handle of the peer
62 */
63 struct GNUNET_ARM_Handle *ah;
64
65 /**
66 * peer whose service has to be managed
67 */
68 struct Peer *peer;
69
70 /**
71 * The client which requested to manage the peer's service
72 */
73 struct GNUNET_SERVICE_Client *client;
74
75 /**
76 * Name of the service.
77 */
78 char *service;
79
80 /**
81 * The operation id of the associated request
82 */
83 uint64_t op_id;
84
85 /**
86 * 1 if the service at the peer has to be started; 0 if it has to be stopped
87 */
88 uint8_t start;
89
90 /**
91 * Is this context expired? Do not work on this context if it is set to
92 * GNUNET_YES
93 */
94 uint8_t expired;
95};
96
97
98/**
99 * Context information for peer re-configure operations
100 */
101struct PeerReconfigureContext
102{
103 /**
104 * DLL next for inclusoin in peer reconfigure operations list
105 */
106 struct PeerReconfigureContext *next;
107
108 /**
109 * DLL prev
110 */
111 struct PeerReconfigureContext *prev;
112
113 /**
114 * The client which gave this operation to us
115 */
116 struct GNUNET_SERVICE_Client *client;
117
118 /**
119 * The configuration handle to use as the new template
120 */
121 struct GNUNET_CONFIGURATION_Handle *cfg;
122
123 /**
124 * The id of the operation
125 */
126 uint64_t op_id;
127
128 /**
129 * The id of the peer which has to be reconfigured
130 */
131 uint32_t peer_id;
132
133 /**
134 * The the peer stopped? Used while cleaning up this context to decide
135 * whether the asynchronous stop request through Testing/ARM API has to be
136 * cancelled
137 */
138 uint8_t stopped;
139};
140
141/**
142 * The DLL head for the peer reconfigure list
143 */
144static struct PeerReconfigureContext *prc_head;
145
146/**
147 * The DLL tail for the peer reconfigure list
148 */
149static struct PeerReconfigureContext *prc_tail;
150
151
152/**
153 * DLL head for queue of manage service requests
154 */
155static struct ManageServiceContext *mctx_head;
156
157/**
158 * DLL tail for queue of manage service requests
159 */
160static struct ManageServiceContext *mctx_tail;
161
162
163/**
164 * Adds a peer to the peer array
165 *
166 * @param peer the peer to add
167 */
168static void
169peer_list_add (struct Peer *peer)
170{
171 if (peer->id >= GST_peer_list_size)
172 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
173 GNUNET_assert (NULL == GST_peer_list[peer->id]);
174 GST_peer_list[peer->id] = peer;
175 if (GNUNET_NO == peer->is_remote)
176 GST_num_local_peers++;
177}
178
179
180/**
181 * Removes a the give peer from the peer array
182 *
183 * @param peer the peer to be removed
184 */
185static void
186peer_list_remove (struct Peer *peer)
187{
188 unsigned int orig_size;
189 uint32_t id;
190
191 if (GNUNET_NO == peer->is_remote)
192 GST_num_local_peers--;
193 GST_peer_list[peer->id] = NULL;
194 orig_size = GST_peer_list_size;
195 while (GST_peer_list_size >= LIST_GROW_STEP)
196 {
197 for (id = GST_peer_list_size - 1;
198 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
199 id--)
200 if (NULL != GST_peer_list[id])
201 break;
202 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
203 break;
204 GST_peer_list_size -= LIST_GROW_STEP;
205 }
206 if (orig_size == GST_peer_list_size)
207 return;
208 GST_peer_list =
209 GNUNET_realloc (GST_peer_list,
210 sizeof(struct Peer *) * GST_peer_list_size);
211}
212
213
214/**
215 * The task to be executed if the forwarded peer create operation has been
216 * timed out
217 *
218 * @param cls the FowardedOperationContext
219 */
220static void
221peer_create_forward_timeout (void *cls)
222{
223 struct ForwardedOperationContext *fopc = cls;
224
225 GNUNET_free (fopc->cls);
226 GST_forwarded_operation_timeout (fopc);
227}
228
229
230/**
231 * Callback to be called when forwarded peer create operation is successful. We
232 * have to relay the reply msg back to the client
233 *
234 * @param cls ForwardedOperationContext
235 * @param msg the peer create success message
236 */
237static void
238peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
239{
240 struct ForwardedOperationContext *fopc = cls;
241 struct Peer *remote_peer;
242
243 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
244 {
245 GNUNET_assert (NULL != fopc->cls);
246 remote_peer = fopc->cls;
247 peer_list_add (remote_peer);
248 }
249 GST_forwarded_operation_reply_relay (fopc,
250 msg);
251}
252
253
254/**
255 * Function to destroy a peer
256 *
257 * @param peer the peer structure to destroy
258 */
259void
260GST_destroy_peer (struct Peer *peer)
261{
262 GNUNET_break (0 == peer->reference_cnt);
263 if (GNUNET_YES == peer->is_remote)
264 {
265 peer_list_remove (peer);
266 GNUNET_free (peer);
267 return;
268 }
269 if (GNUNET_YES == peer->details.local.is_running)
270 {
271 GNUNET_TESTING_peer_stop (peer->details.local.peer);
272 peer->details.local.is_running = GNUNET_NO;
273 }
274 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
275 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
276 peer_list_remove (peer);
277 GNUNET_free (peer);
278}
279
280
281/**
282 * Cleanup the context information created for managing a peer's service
283 *
284 * @param mctx the ManageServiceContext
285 */
286static void
287cleanup_mctx (struct ManageServiceContext *mctx)
288{
289 mctx->expired = GNUNET_YES;
290 GNUNET_CONTAINER_DLL_remove (mctx_head,
291 mctx_tail,
292 mctx);
293 GNUNET_ARM_disconnect (mctx->ah);
294 GNUNET_assert (0 < mctx->peer->reference_cnt);
295 mctx->peer->reference_cnt--;
296 if ((GNUNET_YES == mctx->peer->destroy_flag) &&
297 (0 == mctx->peer->reference_cnt))
298 GST_destroy_peer (mctx->peer);
299 GNUNET_free (mctx->service);
300 GNUNET_free (mctx);
301}
302
303
304/**
305 * Stops a peer
306 *
307 * @param peer the peer to stop
308 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
309 */
310static int
311stop_peer (struct Peer *peer)
312{
313 GNUNET_assert (GNUNET_NO == peer->is_remote);
314 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
315 return GNUNET_SYSERR;
316 peer->details.local.is_running = GNUNET_NO;
317 return GNUNET_OK;
318}
319
320
321/**
322 * Cleans up the given PeerReconfigureContext
323 *
324 * @param prc the PeerReconfigureContext
325 */
326static void
327cleanup_prc (struct PeerReconfigureContext *prc)
328{
329 struct Peer *peer;
330
331 if (VALID_PEER_ID (prc->peer_id))
332 {
333 peer = GST_peer_list [prc->peer_id];
334 if (1 != prc->stopped)
335 {
336 GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer);
337 stop_peer (peer); /* Stop the peer synchronously */
338 }
339 }
340 if (NULL != prc->cfg)
341 GNUNET_CONFIGURATION_destroy (prc->cfg);
342 GNUNET_CONTAINER_DLL_remove (prc_head,
343 prc_tail,
344 prc);
345 GNUNET_free (prc);
346}
347
348
349/**
350 * Notify peers subsystem that @a client disconnected.
351 *
352 * @param client the client that disconnected
353 */
354void
355GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client)
356{
357 struct ForwardedOperationContext *fopc;
358 struct ForwardedOperationContext *fopcn;
359 struct ManageServiceContext *mctx;
360 struct ManageServiceContext *mctxn;
361 struct PeerReconfigureContext *prc;
362 struct PeerReconfigureContext *prcn;
363
364 for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
365 {
366 fopcn = fopc->next;
367 if (client == fopc->client)
368 {
369 if (OP_PEER_CREATE == fopc->type)
370 GNUNET_free (fopc->cls);
371 GNUNET_SCHEDULER_cancel (fopc->timeout_task);
372 GST_forwarded_operation_timeout (fopc);
373 }
374 }
375 for (mctx = mctx_head; NULL != mctx; mctx = mctxn)
376 {
377 mctxn = mctx->next;
378 if (client == mctx->client)
379 cleanup_mctx (mctx);
380 }
381 for (prc = prc_head; NULL != prc; prc = prcn)
382 {
383 prcn = prc->next;
384 if (client == prc->client)
385 cleanup_prc (prc);
386 }
387}
388
389
390/**
391 * Callback to be called when forwarded peer destroy operation is successful. We
392 * have to relay the reply msg back to the client
393 *
394 * @param cls ForwardedOperationContext
395 * @param msg the peer create success message
396 */
397static void
398peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
399{
400 struct ForwardedOperationContext *fopc = cls;
401 struct Peer *remote_peer;
402
403 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
404 ntohs (msg->type))
405 {
406 remote_peer = fopc->cls;
407 GNUNET_assert (NULL != remote_peer);
408 remote_peer->destroy_flag = GNUNET_YES;
409 if (0 == remote_peer->reference_cnt)
410 GST_destroy_peer (remote_peer);
411 }
412 GST_forwarded_operation_reply_relay (fopc,
413 msg);
414}
415
416
417/**
418 * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
419 *
420 * @param cls identification of the client
421 * @param msg the actual message
422 * @return #GNUNET_OK if @a msg is well-formed
423 */
424int
425check_peer_create (void *cls,
426 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
427{
428 return GNUNET_OK; /* checked later */
429}
430
431
432void
433handle_peer_create (void *cls,
434 const struct GNUNET_TESTBED_PeerCreateMessage *msg)
435{
436 struct GNUNET_SERVICE_Client *client = cls;
437 struct GNUNET_MQ_Envelope *env;
438 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
439 struct GNUNET_CONFIGURATION_Handle *cfg;
440 struct ForwardedOperationContext *fo_ctxt;
441 struct Route *route;
442 struct Peer *peer;
443 char *emsg;
444 uint32_t host_id;
445 uint32_t peer_id;
446
447 host_id = ntohl (msg->host_id);
448 peer_id = ntohl (msg->peer_id);
449 if (VALID_PEER_ID (peer_id))
450 {
451 (void) GNUNET_asprintf (&emsg,
452 "Peer with ID %u already exists",
453 peer_id);
454 GST_send_operation_fail_msg (client,
455 GNUNET_ntohll (msg->operation_id),
456 emsg);
457 GNUNET_free (emsg);
458 GNUNET_SERVICE_client_continue (client);
459 return;
460 }
461 if (UINT32_MAX == peer_id)
462 {
463 GST_send_operation_fail_msg (client,
464 GNUNET_ntohll (msg->operation_id),
465 "Cannot create peer with given ID");
466 GNUNET_SERVICE_client_continue (client);
467 return;
468 }
469 if (host_id == GST_context->host_id)
470 {
471 /* We are responsible for this peer */
472 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
473 if (NULL == cfg)
474 {
475 GNUNET_break (0);
476 GNUNET_SERVICE_client_drop (client);
477 return;
478 }
479 GNUNET_CONFIGURATION_set_value_number (cfg,
480 "TESTBED",
481 "PEERID",
482 (unsigned long long) peer_id);
483
484 GNUNET_CONFIGURATION_set_value_number (cfg,
485 "PATHS",
486 "PEERID",
487 (unsigned long long) peer_id);
488 peer = GNUNET_new (struct Peer);
489 peer->is_remote = GNUNET_NO;
490 peer->details.local.cfg = cfg;
491 peer->id = peer_id;
492 LOG_DEBUG ("Creating peer with id: %u\n",
493 (unsigned int) peer->id);
494 peer->details.local.peer =
495 GNUNET_TESTING_peer_configure (GST_context->system,
496 peer->details.local.cfg, peer->id,
497 NULL /* Peer id */,
498 &emsg);
499 if (NULL == peer->details.local.peer)
500 {
501 LOG (GNUNET_ERROR_TYPE_WARNING,
502 "Configuring peer failed: %s\n",
503 emsg);
504 GNUNET_free (emsg);
505 GNUNET_free (peer);
506 GNUNET_break (0);
507 GNUNET_SERVICE_client_drop (client);
508 return;
509 }
510 peer->details.local.is_running = GNUNET_NO;
511 peer_list_add (peer);
512 env = GNUNET_MQ_msg (reply,
513 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
514 reply->peer_id = msg->peer_id;
515 reply->operation_id = msg->operation_id;
516 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
517 env);
518 GNUNET_SERVICE_client_continue (client);
519 return;
520 }
521
522 /* Forward peer create request */
523 route = GST_find_dest_route (host_id);
524 if (NULL == route)
525 {
526 GNUNET_break (0);
527 GNUNET_SERVICE_client_continue (client); // ?
528 return;
529 }
530 peer = GNUNET_new (struct Peer);
531 peer->is_remote = GNUNET_YES;
532 peer->id = peer_id;
533 peer->details.remote.slave = GST_slave_list[route->dest];
534 peer->details.remote.remote_host_id = host_id;
535 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
536 fo_ctxt->client = client;
537 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
538 fo_ctxt->cls = peer;
539 fo_ctxt->type = OP_PEER_CREATE;
540 fo_ctxt->opc =
541 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
542 [route->dest]->controller,
543 fo_ctxt->operation_id,
544 &msg->header,
545 &peer_create_success_cb,
546 fo_ctxt);
547 fo_ctxt->timeout_task =
548 GNUNET_SCHEDULER_add_delayed (GST_timeout,
549 &peer_create_forward_timeout,
550 fo_ctxt);
551 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
552 fopcq_tail,
553 fo_ctxt);
554 GNUNET_SERVICE_client_continue (client);
555}
556
557
558/**
559 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
560 *
561 * @param cls identification of the client
562 * @param msg the actual message
563 */
564void
565handle_peer_destroy (void *cls,
566 const struct GNUNET_TESTBED_PeerDestroyMessage *msg)
567{
568 struct GNUNET_SERVICE_Client *client = cls;
569 struct ForwardedOperationContext *fopc;
570 struct Peer *peer;
571 uint32_t peer_id;
572
573 peer_id = ntohl (msg->peer_id);
574 LOG_DEBUG ("Received peer destroy on peer: %u and operation id: %llu\n",
575 (unsigned int) peer_id,
576 (unsigned long long) GNUNET_ntohll (msg->operation_id));
577 if (! VALID_PEER_ID (peer_id))
578 {
579 LOG (GNUNET_ERROR_TYPE_ERROR,
580 "Asked to destroy a non existent peer with id: %u\n", peer_id);
581 GST_send_operation_fail_msg (client,
582 GNUNET_ntohll (msg->operation_id),
583 "Peer doesn't exist");
584 GNUNET_SERVICE_client_continue (client);
585 return;
586 }
587 peer = GST_peer_list[peer_id];
588 if (GNUNET_YES == peer->is_remote)
589 {
590 /* Forward the destroy message to sub controller */
591 fopc = GNUNET_new (struct ForwardedOperationContext);
592 fopc->client = client;
593 fopc->cls = peer;
594 fopc->type = OP_PEER_DESTROY;
595 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
596 fopc->opc =
597 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
598 slave->controller,
599 fopc->operation_id,
600 &msg->header,
601 &peer_destroy_success_cb,
602 fopc);
603 fopc->timeout_task =
604 GNUNET_SCHEDULER_add_delayed (GST_timeout,
605 &GST_forwarded_operation_timeout,
606 fopc);
607 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
608 fopcq_tail,
609 fopc);
610 GNUNET_SERVICE_client_continue (client);
611 return;
612 }
613 peer->destroy_flag = GNUNET_YES;
614 if (0 == peer->reference_cnt)
615 GST_destroy_peer (peer);
616 else
617 LOG (GNUNET_ERROR_TYPE_DEBUG,
618 "Delaying peer destroy as peer is currently in use\n");
619 GST_send_operation_success_msg (client,
620 GNUNET_ntohll (msg->operation_id));
621 GNUNET_SERVICE_client_continue (client);
622}
623
624
625/**
626 * Stats a peer
627 *
628 * @param peer the peer to start
629 * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
630 */
631static int
632start_peer (struct Peer *peer)
633{
634 GNUNET_assert (GNUNET_NO == peer->is_remote);
635 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
636 return GNUNET_SYSERR;
637 peer->details.local.is_running = GNUNET_YES;
638 return GNUNET_OK;
639}
640
641
642void
643handle_peer_start (void *cls,
644 const struct GNUNET_TESTBED_PeerStartMessage *msg)
645{
646 struct GNUNET_SERVICE_Client *client = cls;
647 struct GNUNET_MQ_Envelope *env;
648 struct GNUNET_TESTBED_PeerEventMessage *reply;
649 struct ForwardedOperationContext *fopc;
650 struct Peer *peer;
651 uint32_t peer_id;
652
653 peer_id = ntohl (msg->peer_id);
654 if (! VALID_PEER_ID (peer_id))
655 {
656 GNUNET_break (0);
657 LOG (GNUNET_ERROR_TYPE_ERROR,
658 "Asked to start a non existent peer with id: %u\n",
659 peer_id);
660 GNUNET_SERVICE_client_continue (client);
661 return;
662 }
663 peer = GST_peer_list[peer_id];
664 if (GNUNET_YES == peer->is_remote)
665 {
666 fopc = GNUNET_new (struct ForwardedOperationContext);
667 fopc->client = client;
668 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
669 fopc->type = OP_PEER_START;
670 fopc->opc =
671 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
672 slave->controller,
673 fopc->operation_id, &msg->header,
674 &
675 GST_forwarded_operation_reply_relay,
676 fopc);
677 fopc->timeout_task =
678 GNUNET_SCHEDULER_add_delayed (GST_timeout,
679 &GST_forwarded_operation_timeout,
680 fopc);
681 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
682 fopcq_tail,
683 fopc);
684 GNUNET_SERVICE_client_continue (client);
685 return;
686 }
687 if (GNUNET_OK != start_peer (peer))
688 {
689 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
690 "Failed to start");
691 GNUNET_SERVICE_client_continue (client);
692 return;
693 }
694 env = GNUNET_MQ_msg (reply,
695 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
696 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
697 reply->host_id = htonl (GST_context->host_id);
698 reply->peer_id = msg->peer_id;
699 reply->operation_id = msg->operation_id;
700 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
701 env);
702 GNUNET_SERVICE_client_continue (client);
703}
704
705
706/**
707 * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages
708 *
709 * @param cls identification of the client
710 * @param msg the actual message
711 */
712void
713handle_peer_stop (void *cls,
714 const struct GNUNET_TESTBED_PeerStopMessage *msg)
715{
716 struct GNUNET_SERVICE_Client *client = cls;
717 struct GNUNET_MQ_Envelope *env;
718 struct GNUNET_TESTBED_PeerEventMessage *reply;
719 struct ForwardedOperationContext *fopc;
720 struct Peer *peer;
721 uint32_t peer_id;
722
723 peer_id = ntohl (msg->peer_id);
724 LOG (GNUNET_ERROR_TYPE_DEBUG,
725 "Received PEER_STOP for peer %u\n",
726 (unsigned int) peer_id);
727 if (! VALID_PEER_ID (peer_id))
728 {
729 GST_send_operation_fail_msg (client,
730 GNUNET_ntohll (msg->operation_id),
731 "Peer not found");
732 GNUNET_SERVICE_client_continue (client);
733 return;
734 }
735 peer = GST_peer_list[peer_id];
736 if (GNUNET_YES == peer->is_remote)
737 {
738 LOG (GNUNET_ERROR_TYPE_DEBUG,
739 "Forwarding PEER_STOP for peer %u\n",
740 (unsigned int) peer_id);
741 fopc = GNUNET_new (struct ForwardedOperationContext);
742 fopc->client = client;
743 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
744 fopc->type = OP_PEER_STOP;
745 fopc->opc =
746 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
747 slave->controller,
748 fopc->operation_id,
749 &msg->header,
750 &
751 GST_forwarded_operation_reply_relay,
752 fopc);
753 fopc->timeout_task =
754 GNUNET_SCHEDULER_add_delayed (GST_timeout,
755 &GST_forwarded_operation_timeout,
756 fopc);
757 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
758 fopcq_tail,
759 fopc);
760 GNUNET_SERVICE_client_continue (client);
761 return;
762 }
763 if (GNUNET_OK != stop_peer (peer))
764 {
765 LOG (GNUNET_ERROR_TYPE_WARNING,
766 "Stopping peer %u failed\n",
767 (unsigned int) peer_id);
768 GST_send_operation_fail_msg (client,
769 GNUNET_ntohll (msg->operation_id),
770 "Peer not running");
771 GNUNET_SERVICE_client_continue (client);
772 return;
773 }
774 LOG (GNUNET_ERROR_TYPE_DEBUG,
775 "Peer %u successfully stopped\n",
776 (unsigned int) peer_id);
777 env = GNUNET_MQ_msg (reply,
778 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
779 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
780 reply->host_id = htonl (GST_context->host_id);
781 reply->peer_id = msg->peer_id;
782 reply->operation_id = msg->operation_id;
783 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
784 env);
785 GNUNET_SERVICE_client_continue (client);
786 GNUNET_TESTING_peer_wait (peer->details.local.peer);
787}
788
789
790/**
791 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages
792 *
793 * @param cls identification of the client
794 * @param msg the actual message
795 */
796void
797handle_peer_get_config (void *cls,
798 const struct
799 GNUNET_TESTBED_PeerGetConfigurationMessage *msg)
800{
801 struct GNUNET_SERVICE_Client *client = cls;
802 struct GNUNET_MQ_Envelope *env;
803 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
804 struct ForwardedOperationContext *fopc;
805 struct Peer *peer;
806 char *config;
807 char *xconfig;
808 size_t c_size;
809 size_t xc_size;
810 uint32_t peer_id;
811
812 peer_id = ntohl (msg->peer_id);
813 LOG_DEBUG ("Received GET_CONFIG for peer %u\n",
814 (unsigned int) peer_id);
815 if (! VALID_PEER_ID (peer_id))
816 {
817 GST_send_operation_fail_msg (client,
818 GNUNET_ntohll (msg->operation_id),
819 "Peer not found");
820 GNUNET_SERVICE_client_continue (client);
821 return;
822 }
823 peer = GST_peer_list[peer_id];
824 if (GNUNET_YES == peer->is_remote)
825 {
826 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n",
827 (unsigned int) peer_id);
828 fopc = GNUNET_new (struct ForwardedOperationContext);
829 fopc->client = client;
830 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
831 fopc->type = OP_PEER_INFO;
832 fopc->opc =
833 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
834 slave->controller,
835 fopc->operation_id,
836 &msg->header,
837 &
838 GST_forwarded_operation_reply_relay,
839 fopc);
840 fopc->timeout_task =
841 GNUNET_SCHEDULER_add_delayed (GST_timeout,
842 &GST_forwarded_operation_timeout,
843 fopc);
844 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
845 fopcq_tail,
846 fopc);
847 GNUNET_SERVICE_client_continue (client);
848 return;
849 }
850 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n",
851 peer_id);
852 config =
853 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
854 &c_size);
855 xc_size = GNUNET_TESTBED_compress_config_ (config,
856 c_size,
857 &xconfig);
858 GNUNET_free (config);
859 env = GNUNET_MQ_msg_extra (reply,
860 xc_size,
861 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION);
862 reply->peer_id = msg->peer_id;
863 reply->operation_id = msg->operation_id;
864 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
865 &reply->peer_identity);
866 reply->config_size = htons ((uint16_t) c_size);
867 GNUNET_memcpy (&reply[1],
868 xconfig,
869 xc_size);
870 GNUNET_free (xconfig);
871 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
872 env);
873 GNUNET_SERVICE_client_continue (client);
874}
875
876
877/**
878 * Cleans up the Peer reconfigure context list
879 */
880void
881GST_free_prcq ()
882{
883 while (NULL != prc_head)
884 cleanup_prc (prc_head);
885}
886
887
888/**
889 * Update peer configuration
890 *
891 * @param peer the peer to update
892 * @param cfg the new configuration
893 * @return error message (freshly allocated); NULL upon success
894 */
895static char *
896update_peer_config (struct Peer *peer,
897 struct GNUNET_CONFIGURATION_Handle *cfg)
898{
899 char *emsg;
900
901 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
902 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
903 peer->details.local.cfg = cfg;
904 emsg = NULL;
905 peer->details.local.peer
906 = GNUNET_TESTING_peer_configure (GST_context->system,
907 peer->details.local.cfg,
908 peer->id,
909 NULL /* Peer id */,
910 &emsg);
911 return emsg;
912}
913
914
915/**
916 * Callback to inform whether the peer is running or stopped.
917 *
918 * @param cls the closure given to GNUNET_TESTING_peer_stop_async()
919 * @param p the respective peer whose status is being reported
920 * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any
921 * error
922 */
923static void
924prc_stop_cb (void *cls,
925 struct GNUNET_TESTING_Peer *p,
926 int success)
927{
928 struct PeerReconfigureContext *prc = cls;
929 struct Peer *peer;
930 char *emsg;
931
932 GNUNET_assert (VALID_PEER_ID (prc->peer_id));
933 peer = GST_peer_list [prc->peer_id];
934 GNUNET_assert (GNUNET_NO == peer->is_remote);
935 emsg = update_peer_config (peer, prc->cfg);
936 prc->cfg = NULL;
937 prc->stopped = 1;
938 if (NULL != emsg)
939 {
940 GST_send_operation_fail_msg (prc->client,
941 prc->op_id,
942 emsg);
943 goto cleanup;
944 }
945 if (GNUNET_OK != start_peer (peer))
946 {
947 GST_send_operation_fail_msg (prc->client,
948 prc->op_id,
949 "Failed to start reconfigured peer");
950 goto cleanup;
951 }
952 GST_send_operation_success_msg (prc->client,
953 prc->op_id);
954
955cleanup:
956 cleanup_prc (prc);
957 return;
958}
959
960
961/**
962 * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
963 *
964 * @param cls identification of the client
965 * @param msg the actual message
966 * @return #GNUNET_OK if @a msg is well-formed
967 */
968int
969check_peer_reconfigure (void *cls,
970 const struct GNUNET_TESTBED_PeerReconfigureMessage *msg)
971{
972 return GNUNET_OK; /* checked later */
973}
974
975
976/**
977 * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages.
978 * Should stop the peer asynchronously, destroy it and create it again with the
979 * new configuration.
980 *
981 * @param cls identification of the client
982 * @param msg the actual message
983 */
984void
985handle_peer_reconfigure (void *cls,
986 const struct
987 GNUNET_TESTBED_PeerReconfigureMessage *msg)
988{
989 struct GNUNET_SERVICE_Client *client = cls;
990 struct Peer *peer;
991 struct GNUNET_CONFIGURATION_Handle *cfg;
992 struct ForwardedOperationContext *fopc;
993 struct PeerReconfigureContext *prc;
994 char *emsg;
995 uint64_t op_id;
996 uint32_t peer_id;
997
998 peer_id = ntohl (msg->peer_id);
999 op_id = GNUNET_ntohll (msg->operation_id);
1000 if (! VALID_PEER_ID (peer_id))
1001 {
1002 GNUNET_break (0);
1003 GST_send_operation_fail_msg (client,
1004 op_id,
1005 "Peer not found");
1006 GNUNET_SERVICE_client_continue (client);
1007 return;
1008 }
1009 peer = GST_peer_list[peer_id];
1010 if (GNUNET_YES == peer->is_remote)
1011 {
1012 LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id);
1013 fopc = GNUNET_new (struct ForwardedOperationContext);
1014 fopc->client = client;
1015 fopc->operation_id = op_id;
1016 fopc->type = OP_PEER_RECONFIGURE;
1017 fopc->opc =
1018 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1019 slave->controller,
1020 fopc->operation_id,
1021 &msg->header,
1022 &
1023 GST_forwarded_operation_reply_relay,
1024 fopc);
1025 fopc->timeout_task =
1026 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1027 &GST_forwarded_operation_timeout,
1028 fopc);
1029 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1030 fopcq_tail,
1031 fopc);
1032 GNUNET_SERVICE_client_continue (client);
1033 return;
1034 }
1035 LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n",
1036 (unsigned int) peer_id);
1037 if (0 < peer->reference_cnt)
1038 {
1039 GNUNET_break (0);
1040 GST_send_operation_fail_msg (client,
1041 op_id,
1042 "Peer in use");
1043 GNUNET_SERVICE_client_continue (client);
1044 return;
1045 }
1046 if (GNUNET_YES == peer->destroy_flag)
1047 {
1048 GNUNET_break (0);
1049 GST_send_operation_fail_msg (client,
1050 op_id,
1051 "Peer is being destroyed");
1052 GNUNET_SERVICE_client_continue (client);
1053 return;
1054 }
1055 cfg = GNUNET_TESTBED_extract_config_ (&msg->header);
1056 if (NULL == cfg)
1057 {
1058 GNUNET_break (0);
1059 GST_send_operation_fail_msg (client,
1060 op_id,
1061 "Compression error");
1062 GNUNET_SERVICE_client_continue (client);
1063 return;
1064 }
1065 if (GNUNET_NO == peer->details.local.is_running)
1066 {
1067 emsg = update_peer_config (peer,
1068 cfg);
1069 if (NULL != emsg)
1070 GST_send_operation_fail_msg (client,
1071 op_id,
1072 emsg);
1073 GST_send_operation_success_msg (client,
1074 op_id);
1075 GNUNET_SERVICE_client_continue (client);
1076 GNUNET_free (emsg);
1077 return;
1078 }
1079 prc = GNUNET_new (struct PeerReconfigureContext);
1080 if (GNUNET_OK !=
1081 GNUNET_TESTING_peer_stop_async (peer->details.local.peer,
1082 &prc_stop_cb,
1083 prc))
1084 {
1085 GNUNET_assert (0 < GNUNET_asprintf (&emsg,
1086 "Error trying to stop peer %u asynchronously\n",
1087 peer_id));
1088 LOG (GNUNET_ERROR_TYPE_ERROR,
1089 "%s\n",
1090 emsg);
1091 GST_send_operation_fail_msg (client,
1092 op_id,
1093 emsg);
1094 GNUNET_SERVICE_client_continue (client);
1095 GNUNET_free (prc);
1096 GNUNET_free (emsg);
1097 return;
1098 }
1099 prc->cfg = cfg;
1100 prc->peer_id = peer_id;
1101 prc->op_id = op_id;
1102 prc->client = client;
1103 GNUNET_CONTAINER_DLL_insert_tail (prc_head,
1104 prc_tail,
1105 prc);
1106 GNUNET_SERVICE_client_continue (client);
1107}
1108
1109
1110/**
1111 * Frees the ManageServiceContext queue
1112 */
1113void
1114GST_free_mctxq ()
1115{
1116 while (NULL != mctx_head)
1117 cleanup_mctx (mctx_head);
1118}
1119
1120
1121/**
1122 * Returns a string interpretation of @a rs.
1123 *
1124 * @param rs the request status from ARM
1125 * @return a string interpretation of the request status
1126 */
1127static const char *
1128arm_req_string (enum GNUNET_ARM_RequestStatus rs)
1129{
1130 switch (rs)
1131 {
1132 case GNUNET_ARM_REQUEST_SENT_OK:
1133 return _ ("Message was sent successfully");
1134
1135 case GNUNET_ARM_REQUEST_DISCONNECTED:
1136 return _ ("We disconnected from ARM before we could send a request");
1137 }
1138 return _ ("Unknown request status");
1139}
1140
1141
1142/**
1143 * Returns a string interpretation of the @a result.
1144 *
1145 * @param result the arm result
1146 * @return a string interpretation
1147 */
1148static const char *
1149arm_ret_string (enum GNUNET_ARM_Result result)
1150{
1151 switch (result)
1152 {
1153 case GNUNET_ARM_RESULT_STOPPED:
1154 return _ ("%s is stopped");
1155
1156 case GNUNET_ARM_RESULT_STARTING:
1157 return _ ("%s is starting");
1158
1159 case GNUNET_ARM_RESULT_STOPPING:
1160 return _ ("%s is stopping");
1161
1162 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
1163 return _ ("%s is starting already");
1164
1165 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
1166 return _ ("%s is stopping already");
1167
1168 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
1169 return _ ("%s is started already");
1170
1171 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
1172 return _ ("%s is stopped already");
1173
1174 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
1175 return _ ("%s service is not known to ARM");
1176
1177 case GNUNET_ARM_RESULT_START_FAILED:
1178 return _ ("%s service failed to start");
1179
1180 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
1181 return _ ("%s service can't be started because ARM is shutting down");
1182 }
1183 return _ ("%.s Unknown result code.");
1184}
1185
1186
1187/**
1188 * Function called in response to a start/stop request.
1189 * Will be called when request was not sent successfully,
1190 * or when a reply comes. If the request was not sent successfully,
1191 * @a rs will indicate that, and @a result will be undefined.
1192 *
1193 * @param cls ManageServiceContext
1194 * @param rs status of the request
1195 * @param result result of the operation
1196 */
1197static void
1198service_manage_result_cb (void *cls,
1199 enum GNUNET_ARM_RequestStatus rs,
1200 enum GNUNET_ARM_Result result)
1201{
1202 struct ManageServiceContext *mctx = cls;
1203 char *emsg;
1204
1205 emsg = NULL;
1206 if (GNUNET_YES == mctx->expired)
1207 return;
1208 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
1209 {
1210 GNUNET_asprintf (&emsg,
1211 "Error communicating with Peer %u's ARM: %s",
1212 mctx->peer->id,
1213 arm_req_string (rs));
1214 goto ret;
1215 }
1216 if (1 == mctx->start)
1217 goto service_start_check;
1218 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
1219 || (GNUNET_ARM_RESULT_STOPPING == result)
1220 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
1221 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)))
1222 {
1223 /* stopping a service failed */
1224 GNUNET_asprintf (&emsg,
1225 arm_ret_string (result),
1226 mctx->service);
1227 goto ret;
1228 }
1229 /* service stopped successfully */
1230 goto ret;
1231
1232service_start_check:
1233 if (! ((GNUNET_ARM_RESULT_STARTING == result)
1234 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
1235 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)))
1236 {
1237 /* starting a service failed */
1238 GNUNET_asprintf (&emsg,
1239 arm_ret_string (result),
1240 mctx->service);
1241 goto ret;
1242 }
1243 /* service started successfully */
1244
1245ret:
1246 if (NULL != emsg)
1247 {
1248 LOG_DEBUG ("%s\n", emsg);
1249 GST_send_operation_fail_msg (mctx->client,
1250 mctx->op_id,
1251 emsg);
1252 }
1253 else
1254 GST_send_operation_success_msg (mctx->client,
1255 mctx->op_id);
1256 GNUNET_free (emsg);
1257 cleanup_mctx (mctx);
1258}
1259
1260
1261/**
1262 * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message
1263 *
1264 * @param cls identification of client
1265 * @param msg the actual message
1266 * @return #GNUNET_OK if @a msg is well-formed
1267 */
1268int
1269check_manage_peer_service (void *cls,
1270 const struct
1271 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1272{
1273 uint16_t msize;
1274 const char*service;
1275
1276 msize = ntohs (msg->header.size);
1277 service = (const char *) &msg[1];
1278 if ('\0' != service[msize - sizeof
1279 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
1280 {
1281 GNUNET_break_op (0);
1282 return GNUNET_SYSERR;
1283 }
1284 if (1 < msg->start)
1285 {
1286 GNUNET_break_op (0);
1287 return GNUNET_SYSERR;
1288 }
1289 return GNUNET_OK;
1290}
1291
1292
1293void
1294handle_manage_peer_service (void *cls,
1295 const struct
1296 GNUNET_TESTBED_ManagePeerServiceMessage *msg)
1297{
1298 struct GNUNET_SERVICE_Client *client = cls;
1299 const char*service;
1300 struct Peer *peer;
1301 char *emsg;
1302 struct GNUNET_ARM_Handle *ah;
1303 struct ManageServiceContext *mctx;
1304 struct ForwardedOperationContext *fopc;
1305 uint64_t op_id;
1306 uint32_t peer_id;
1307
1308 service = (const char *) &msg[1];
1309 peer_id = ntohl (msg->peer_id);
1310 op_id = GNUNET_ntohll (msg->operation_id);
1311 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
1312 service, (unsigned int) peer_id);
1313 if ((GST_peer_list_size <= peer_id)
1314 || (NULL == (peer = GST_peer_list[peer_id])))
1315 {
1316 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
1317 "with id: %u", peer_id);
1318 goto err_ret;
1319 }
1320 if (0 == strcasecmp ("arm", service))
1321 {
1322 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
1323 "Use peer start/stop for that");
1324 goto err_ret;
1325 }
1326 if (GNUNET_YES == peer->is_remote)
1327 {
1328 /* Forward the destroy message to sub controller */
1329 fopc = GNUNET_new (struct ForwardedOperationContext);
1330 fopc->client = client;
1331 fopc->cls = peer;
1332 fopc->type = OP_MANAGE_SERVICE;
1333 fopc->operation_id = op_id;
1334 fopc->opc =
1335 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1336 slave->controller,
1337 fopc->operation_id,
1338 &msg->header,
1339 &
1340 GST_forwarded_operation_reply_relay,
1341 fopc);
1342 fopc->timeout_task =
1343 GNUNET_SCHEDULER_add_delayed (GST_timeout,
1344 &GST_forwarded_operation_timeout,
1345 fopc);
1346 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1347 fopcq_tail,
1348 fopc);
1349 GNUNET_SERVICE_client_continue (client);
1350 return;
1351 }
1352 if (GNUNET_NO == peer->details.local.is_running)
1353 {
1354 emsg = GNUNET_strdup ("Peer not running\n");
1355 goto err_ret;
1356 }
1357 if ((0 != peer->reference_cnt)
1358 && ((0 == strcasecmp ("core", service))
1359 || (0 == strcasecmp ("transport", service))))
1360 {
1361 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
1362 "since it is required by existing operations",
1363 service, peer_id);
1364 goto err_ret;
1365 }
1366 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
1367 if (NULL == ah)
1368 {
1369 GNUNET_asprintf (&emsg,
1370 "Cannot connect to ARM service of peer with id: %u",
1371 peer_id);
1372 goto err_ret;
1373 }
1374 mctx = GNUNET_new (struct ManageServiceContext);
1375 mctx->peer = peer;
1376 peer->reference_cnt++;
1377 mctx->op_id = op_id;
1378 mctx->ah = ah;
1379 mctx->client = client;
1380 mctx->start = msg->start;
1381 mctx->service = GNUNET_strdup (service);
1382 GNUNET_CONTAINER_DLL_insert_tail (mctx_head,
1383 mctx_tail,
1384 mctx);
1385 if (1 == mctx->start)
1386 GNUNET_ARM_request_service_start (mctx->ah,
1387 service,
1388 GNUNET_OS_INHERIT_STD_ERR,
1389 &service_manage_result_cb,
1390 mctx);
1391 else
1392 GNUNET_ARM_request_service_stop (mctx->ah, service,
1393 &service_manage_result_cb,
1394 mctx);
1395 GNUNET_SERVICE_client_continue (client);
1396 return;
1397
1398err_ret:
1399 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
1400 GST_send_operation_fail_msg (client, op_id, emsg);
1401 GNUNET_free (emsg);
1402 GNUNET_SERVICE_client_continue (client);
1403}
1404
1405
1406/**
1407 * Stops and destroys all peers
1408 */
1409void
1410GST_destroy_peers ()
1411{
1412 struct Peer *peer;
1413 unsigned int id;
1414
1415 if (NULL == GST_peer_list)
1416 return;
1417 for (id = 0; id < GST_peer_list_size; id++)
1418 {
1419 peer = GST_peer_list[id];
1420 if (NULL == peer)
1421 continue;
1422 /* If destroy flag is set it means that this peer should have been
1423 * destroyed by a context which we destroy before */
1424 GNUNET_break (GNUNET_NO == peer->destroy_flag);
1425 /* counter should be zero as we free all contexts before */
1426 GNUNET_break (0 == peer->reference_cnt);
1427 if ((GNUNET_NO == peer->is_remote) &&
1428 (GNUNET_YES == peer->details.local.is_running))
1429 GNUNET_TESTING_peer_kill (peer->details.local.peer);
1430 }
1431 for (id = 0; id < GST_peer_list_size; id++)
1432 {
1433 peer = GST_peer_list[id];
1434 if (NULL == peer)
1435 continue;
1436 if (GNUNET_NO == peer->is_remote)
1437 {
1438 if (GNUNET_YES == peer->details.local.is_running)
1439 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1440 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1441 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1442 }
1443 GNUNET_free (peer);
1444 }
1445 GNUNET_free (GST_peer_list);
1446 GST_peer_list = NULL;
1447 GST_peer_list_size = 0;
1448}
1449
1450
1451/**
1452 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
1453 * success reply is received from all clients and then sends the success message
1454 * to the client
1455 *
1456 * @param cls ForwardedOperationContext
1457 * @param msg the message to relay
1458 */
1459static void
1460shutdown_peers_reply_cb (void *cls,
1461 const struct GNUNET_MessageHeader *msg)
1462{
1463 struct ForwardedOperationContext *fo_ctxt = cls;
1464 struct HandlerContext_ShutdownPeers *hc;
1465
1466 hc = fo_ctxt->cls;
1467 GNUNET_assert (0 < hc->nslaves);
1468 hc->nslaves--;
1469 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
1470 ntohs (msg->type))
1471 hc->timeout = GNUNET_YES;
1472 if (0 == hc->nslaves)
1473 {
1474 if (GNUNET_YES == hc->timeout)
1475 GST_send_operation_fail_msg (fo_ctxt->client,
1476 fo_ctxt->operation_id,
1477 "Timeout at a slave controller");
1478 else
1479 GST_send_operation_success_msg (fo_ctxt->client,
1480 fo_ctxt->operation_id);
1481 GNUNET_free (hc);
1482 hc = NULL;
1483 }
1484 GNUNET_CONTAINER_DLL_remove (fopcq_head,
1485 fopcq_tail,
1486 fo_ctxt);
1487 GNUNET_free (fo_ctxt);
1488}
1489
1490
1491/**
1492 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
1493 *
1494 * @param cls identification of the client
1495 * @param msg the actual message
1496 */
1497void
1498handle_shutdown_peers (void *cls,
1499 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg)
1500{
1501 struct GNUNET_SERVICE_Client *client = cls;
1502 struct HandlerContext_ShutdownPeers *hc;
1503 struct Slave *slave;
1504 struct ForwardedOperationContext *fo_ctxt;
1505 uint64_t op_id;
1506 unsigned int cnt;
1507
1508 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
1509 /* Stop and destroy all peers */
1510 GST_free_mctxq ();
1511 GST_free_occq ();
1512 GST_free_roccq ();
1513 GST_clear_fopcq ();
1514 /* Forward to all slaves which we have started */
1515 op_id = GNUNET_ntohll (msg->operation_id);
1516 hc = GNUNET_new (struct HandlerContext_ShutdownPeers);
1517 /* FIXME: have a better implementation where we track which slaves are
1518 started by this controller */
1519 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
1520 {
1521 slave = GST_slave_list[cnt];
1522 if (NULL == slave)
1523 continue;
1524 if (NULL == slave->controller_proc) /* We didn't start the slave */
1525 continue;
1526 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
1527 hc->nslaves++;
1528 fo_ctxt = GNUNET_new (struct ForwardedOperationContext);
1529 fo_ctxt->client = client;
1530 fo_ctxt->operation_id = op_id;
1531 fo_ctxt->cls = hc;
1532 fo_ctxt->type = OP_SHUTDOWN_PEERS;
1533 fo_ctxt->opc =
1534 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
1535 fo_ctxt->operation_id,
1536 &msg->header,
1537 shutdown_peers_reply_cb,
1538 fo_ctxt);
1539 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head,
1540 fopcq_tail,
1541 fo_ctxt);
1542 }
1543 LOG_DEBUG ("Shutting down peers\n");
1544 GST_destroy_peers ();
1545 if (0 == hc->nslaves)
1546 {
1547 GST_send_operation_success_msg (client,
1548 op_id);
1549 GNUNET_free (hc);
1550 }
1551 GNUNET_SERVICE_client_continue (client);
1552}
diff --git a/src/testbed/gnunet-testbed-profiler.c b/src/testbed/gnunet-testbed-profiler.c
deleted file mode 100644
index 49d975119..000000000
--- a/src/testbed/gnunet-testbed-profiler.c
+++ /dev/null
@@ -1,323 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/gnunet-testbed-profiler.c
23 * @brief Profiling driver for the testbed.
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30#include "testbed_api_hosts.h"
31
32/**
33 * Generic loggins shorthand
34 */
35#define LOG(kind, ...) \
36 GNUNET_log (kind, __VA_ARGS__)
37
38
39/**
40 * Handle to global configuration
41 */
42struct GNUNET_CONFIGURATION_Handle *cfg;
43
44/**
45 * Peer linking - topology operation
46 */
47struct GNUNET_TESTBED_Operation *topology_op;
48
49/**
50 * Name of the file with the hosts to run the test over (configuration option).
51 * It will be NULL if ENABLE_LL is set
52 */
53static char *hosts_file;
54
55/**
56 * Abort task identifier
57 */
58static struct GNUNET_SCHEDULER_Task *abort_task;
59
60/**
61 * Global event mask for all testbed events
62 */
63uint64_t event_mask;
64
65/**
66 * Number of peers to be started by the profiler
67 */
68static unsigned int num_peers;
69
70/**
71 * Number of timeout failures to tolerate
72 */
73static unsigned int num_cont_fails;
74
75/**
76 * Continuous failures during overlay connect operations
77 */
78static unsigned int cont_fails;
79
80/**
81 * Links which are successfully established
82 */
83static unsigned int established_links;
84
85/**
86 * Links which are not successfully established
87 */
88static unsigned int failed_links;
89
90/**
91 * Global testing status
92 */
93static int result;
94
95/**
96 * Are we running non interactively
97 */
98static int noninteractive;
99
100
101/**
102 * Shutdown nicely
103 *
104 * @param cls NULL
105 */
106static void
107do_shutdown (void *cls)
108{
109 if (NULL != abort_task)
110 {
111 GNUNET_SCHEDULER_cancel (abort_task);
112 abort_task = NULL;
113 }
114 if (NULL != cfg)
115 {
116 GNUNET_CONFIGURATION_destroy (cfg);
117 cfg = NULL;
118 }
119}
120
121
122/**
123 * abort task to run on test timed out
124 *
125 * @param cls NULL
126 */
127static void
128do_abort (void *cls)
129{
130 abort_task = NULL;
131 LOG (GNUNET_ERROR_TYPE_WARNING,
132 "Aborting\n");
133 result = GNUNET_SYSERR;
134 GNUNET_SCHEDULER_shutdown ();
135}
136
137
138/**
139 * Function to print summary about how many overlay links we have made and how
140 * many failed
141 */
142static void
143print_overlay_links_summary ()
144{
145 static int printed_already;
146
147 if (GNUNET_YES == printed_already)
148 return;
149 printed_already = GNUNET_YES;
150 printf ("%u links succeeded\n", established_links);
151 printf ("%u links failed due to timeouts\n", failed_links);
152}
153
154
155/**
156 * Controller event callback
157 *
158 * @param cls NULL
159 * @param event the controller event
160 */
161static void
162controller_event_cb (void *cls,
163 const struct GNUNET_TESTBED_EventInformation *event)
164{
165 switch (event->type)
166 {
167 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
168 /* Control reaches here when a peer linking operation fails */
169 if (NULL != event->details.operation_finished.emsg)
170 {
171 printf ("F");
172 fflush (stdout);
173 failed_links++;
174 if (++cont_fails > num_cont_fails)
175 {
176 printf ("\nAborting due to very high failure rate\n");
177 print_overlay_links_summary ();
178 GNUNET_SCHEDULER_shutdown ();
179 return;
180 }
181 }
182 break;
183
184 case GNUNET_TESTBED_ET_CONNECT:
185 {
186 if (0 != cont_fails)
187 cont_fails--;
188 if (0 == established_links)
189 printf ("Establishing links. Please wait\n");
190 printf (".");
191 fflush (stdout);
192 established_links++;
193 }
194 break;
195
196 default:
197 GNUNET_break (0);
198 }
199}
200
201
202/**
203 * Signature of a main function for a testcase.
204 *
205 * @param cls closure
206 * @param h the run handle
207 * @param num_peers number of peers in 'peers'
208 * @param peers handle to peers run in the testbed
209 * @param links_succeeded the number of overlay link connection attempts that
210 * succeeded
211 * @param links_failed the number of overlay link
212 */
213static void
214test_run (void *cls,
215 struct GNUNET_TESTBED_RunHandle *h,
216 unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers,
217 unsigned int links_succeeded,
218 unsigned int links_failed)
219{
220 result = GNUNET_OK;
221 fprintf (stdout, "\n");
222 print_overlay_links_summary ();
223 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
224 if (noninteractive)
225 {
226 GNUNET_SCHEDULER_cancel (abort_task);
227 abort_task = NULL;
228 return;
229 }
230 fprintf (stdout, "Testbed running, waiting for keystroke to shut down\n");
231 fflush (stdout);
232 (void) getc (stdin);
233 fprintf (stdout, "Shutting down. Please wait\n");
234 fflush (stdout);
235 GNUNET_SCHEDULER_shutdown ();
236}
237
238
239/**
240 * Main function that will be run by the scheduler.
241 *
242 * @param cls closure
243 * @param args remaining command-line arguments
244 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
245 * @param config configuration
246 */
247static void
248run (void *cls, char *const *args, const char *cfgfile,
249 const struct GNUNET_CONFIGURATION_Handle *config)
250{
251 if (0 == num_peers)
252 {
253 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Exiting as the number of peers is %u\n"),
254 num_peers);
255 return;
256 }
257 cfg = GNUNET_CONFIGURATION_dup (config);
258 event_mask = 0;
259 event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
260 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
261 GNUNET_TESTBED_run (hosts_file, cfg, num_peers, event_mask,
262 &controller_event_cb, NULL,
263 &test_run, NULL);
264 abort_task =
265 GNUNET_SCHEDULER_add_shutdown (&do_abort,
266 NULL);
267}
268
269
270/**
271 * Main function.
272 *
273 * @return 0 on success
274 */
275int
276main (int argc, char *const *argv)
277{
278 struct GNUNET_GETOPT_CommandLineOption options[] = {
279 GNUNET_GETOPT_option_uint ('p',
280 "num-peers",
281 "COUNT",
282 gettext_noop ("create COUNT number of peers"),
283 &num_peers),
284 GNUNET_GETOPT_option_uint ('e',
285 "num-errors",
286 "COUNT",
287 gettext_noop (
288 "tolerate COUNT number of continuous timeout failures"),
289 &num_cont_fails),
290 GNUNET_GETOPT_option_flag ('n',
291 "non-interactive",
292 gettext_noop (
293 "run profiler in non-interactive mode where upon "
294 "testbed setup the profiler does not wait for a "
295 "keystroke but continues to run until a termination "
296 "signal is received"),
297 &noninteractive),
298 GNUNET_GETOPT_option_string ('H',
299 "hosts",
300 "FILENAME",
301 gettext_noop (
302 "name of the file with the login information for the testbed"),
303 &hosts_file),
304 GNUNET_GETOPT_OPTION_END
305 };
306 const char *binaryHelp = "gnunet-testbed-profiler [OPTIONS]";
307 int ret;
308
309 unsetenv ("XDG_DATA_HOME");
310 unsetenv ("XDG_CONFIG_HOME");
311 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
312 return 2;
313 result = GNUNET_SYSERR;
314 ret =
315 GNUNET_PROGRAM_run (argc, argv, "gnunet-testbed-profiler", binaryHelp,
316 options, &run, NULL);
317 GNUNET_free_nz ((void *) argv);
318 if (GNUNET_OK != ret)
319 return ret;
320 if (GNUNET_OK != result)
321 return 1;
322 return 0;
323}
diff --git a/src/testbed/gnunet_mpi_test.c b/src/testbed/gnunet_mpi_test.c
deleted file mode 100644
index 2ee707fe6..000000000
--- a/src/testbed/gnunet_mpi_test.c
+++ /dev/null
@@ -1,108 +0,0 @@
1#include "platform.h"
2#include "gnunet_util_lib.h"
3#include <mpi.h>
4
5/**
6 * Generic logging shorthand
7 */
8#define LOG(kind, ...) \
9 GNUNET_log_from (kind, "gnunet-mpi-test", __VA_ARGS__)
10
11int
12main (int argc, char *argv[])
13{
14 char *msg;
15 char *filename;
16 char **argv2;
17 struct GNUNET_OS_Process *proc;
18 unsigned long code;
19 pid_t pid;
20 enum GNUNET_OS_ProcessStatusType proc_status;
21 int ntasks;
22 int rank;
23 int msg_size;
24 int ret;
25 unsigned int cnt;
26
27 ret = GNUNET_SYSERR;
28 if (argc < 2)
29 {
30 printf ("Need arguments: gnunet-mpi-test <cmd> <cmd_args>");
31 return 1;
32 }
33 if (MPI_SUCCESS != MPI_Init (&argc, &argv))
34 {
35 GNUNET_break (0);
36 return 1;
37 }
38 if (MPI_SUCCESS != MPI_Comm_size (MPI_COMM_WORLD, &ntasks))
39 {
40 GNUNET_break (0);
41 goto finalize;
42 }
43 if (MPI_SUCCESS != MPI_Comm_rank (MPI_COMM_WORLD, &rank))
44 {
45 GNUNET_break (0);
46 goto finalize;
47 }
48 pid = getpid ();
49 (void) GNUNET_asprintf (&filename, "%d-%d.mpiout", (int) pid, rank);
50 msg_size = GNUNET_asprintf (&msg, "My rank is: %d\n", rank);
51 printf ("%s", msg);
52 (void) GNUNET_DISK_directory_remove (filename);
53 if (GNUNET_OK ==
54 GNUNET_DISK_fn_write (filename, msg, msg_size,
55 GNUNET_DISK_PERM_USER_READ
56 | GNUNET_DISK_PERM_GROUP_READ
57 | GNUNET_DISK_PERM_USER_WRITE
58 | GNUNET_DISK_PERM_GROUP_WRITE))
59 ret = GNUNET_OK;
60 GNUNET_free (filename);
61 GNUNET_free (msg);
62 if (GNUNET_OK != ret)
63 {
64 GNUNET_break (0);
65 goto finalize;
66 }
67
68 ret = GNUNET_SYSERR;
69 argv2 = GNUNET_malloc (sizeof(char *) * (argc));
70 for (cnt = 1; cnt < argc; cnt++)
71 argv2[cnt - 1] = argv[cnt];
72 proc =
73 GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ALL, NULL,
74 NULL, NULL, argv2[0], argv2);
75 if (NULL == proc)
76 {
77 printf ("Cannot exec\n");
78 GNUNET_free (argv2);
79 goto finalize;
80 }
81 do
82 {
83 (void) sleep (1);
84 ret = GNUNET_OS_process_status (proc, &proc_status, &code);
85 }
86 while (GNUNET_NO == ret);
87 GNUNET_free (argv2);
88 GNUNET_assert (GNUNET_NO != ret);
89 if (GNUNET_OK == ret)
90 {
91 if (0 != code)
92 {
93 LOG (GNUNET_ERROR_TYPE_WARNING, "Child terminated abnormally\n");
94 ret = GNUNET_SYSERR;
95 GNUNET_break (0);
96 goto finalize;
97 }
98 }
99 else
100 GNUNET_break (0);
101
102finalize:
103 (void) MPI_Finalize ();
104 if (GNUNET_OK == ret)
105 return 0;
106 printf ("Something went wrong\n");
107 return 1;
108}
diff --git a/src/testbed/misc.supp b/src/testbed/misc.supp
deleted file mode 100644
index 4e4424b6c..000000000
--- a/src/testbed/misc.supp
+++ /dev/null
@@ -1,49 +0,0 @@
1{
2 <get_log_call_status>
3 Memcheck:Leak
4 fun:malloc
5 ...
6 fun:re_acquire_state_context
7 fun:build_trtable
8 fun:re_search_internal
9 fun:regexec@@GLIBC_2.3.4
10 fun:GNUNET_get_log_call_status
11 ...
12}
13{
14 <log_setup>
15 Memcheck:Leak
16 ...
17 fun:GNUNET_log_setup
18 ...
19}
20{
21 <get_log_status>
22 Memcheck:Leak
23 ...
24 fun:GNUNET_get_log_call_status
25 ...
26}
27{
28 <linux-loader>
29 Memcheck:Leak
30 fun:malloc
31 obj:/lib/i386-linux-gnu/libgcrypt.so.11.7.0
32 ...
33 obj:/lib/i386-linux-gnu/ld-2.15.so
34}
35{
36 <glibc-networking>
37 Memcheck:Leak
38 fun:malloc
39 fun:make_request
40 fun:__check_pf
41}
42{
43 <crypto-reachable>
44 Memcheck:Leak
45 ...
46 fun:GNUNET_CRYPTO_random_init
47 fun:call_init
48 ...
49}
diff --git a/src/testbed/overlay_topology.txt b/src/testbed/overlay_topology.txt
deleted file mode 100644
index 420dbb6a6..000000000
--- a/src/testbed/overlay_topology.txt
+++ /dev/null
@@ -1,5 +0,0 @@
1
21:2|3
33:4| 0| 1
42: 3|1|0
50: 2
diff --git a/src/testbed/profile-testbed.patch b/src/testbed/profile-testbed.patch
deleted file mode 100644
index 50a8d5fed..000000000
--- a/src/testbed/profile-testbed.patch
+++ /dev/null
@@ -1,43 +0,0 @@
1Index: Makefile.am
2===================================================================
3--- Makefile.am (revision 29343)
4+++ Makefile.am (working copy)
5@@ -59,7 +59,7 @@
6 $(top_builddir)/src/testing/libgnunettesting.la \
7 $(top_builddir)/src/testbed/libgnunettestbed.la \
8 $(top_builddir)/src/arm/libgnunetarm.la \
9- $(LTLIBINTL) $(Z_LIBS)
10+ $(LTLIBINTL) $(Z_LIBS) -lprofiler
11 gnunet_service_testbed_DEPENDENCIES = \
12 libgnunettestbed.la
13
14Index: gnunet-service-testbed.c
15===================================================================
16--- gnunet-service-testbed.c (revision 29341)
17+++ gnunet-service-testbed.c (working copy)
18@@ -26,6 +26,7 @@
19
20 #include "gnunet-service-testbed.h"
21 #include "gnunet-service-testbed_barriers.h"
22+#include <gperftools/profiler.h>
23
24 /***********/
25 /* Globals */
26@@ -956,9 +957,14 @@
27 main (int argc, char *const *argv)
28 {
29 //sleep (15); /* Debugging */
30- return (GNUNET_OK ==
31- GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
32- &testbed_run, NULL)) ? 0 : 1;
33+ int ret;
34+
35+ ProfilerStart (NULL);
36+ ret = GNUNET_SERVICE_run (argc, argv, "testbed", GNUNET_SERVICE_OPTION_NONE,
37+ &testbed_run, NULL);
38+ ProfilerStop ();
39+ return (GNUNET_OK == ret) ? 0 : 1;
40+
41 }
42
43 /* end of gnunet-service-testbed.c */
diff --git a/src/testbed/sample.job b/src/testbed/sample.job
deleted file mode 100755
index da3ee47f4..000000000
--- a/src/testbed/sample.job
+++ /dev/null
@@ -1,16 +0,0 @@
1#!/bin/bash
2# This job command file is called job.cmd
3#@ job_type = parallel
4#@ class = general
5#@ node = 1
6#@ output = job$(jobid).out
7#@ error = job$(jobid).err
8#@ total_tasks=16
9#@ wall_clock_limit = 0:0:1
10#@ network.MPI = sn_all,not_shared,us
11##@ ... other LoadLeveler keywords (see below)
12#@ notification = always
13#@ notify_user = totakura@in.tum.de
14#@ queue
15
16#@ executable = /bin/bash
diff --git a/src/testbed/sample_hosts.txt b/src/testbed/sample_hosts.txt
deleted file mode 100644
index 32b87e87e..000000000
--- a/src/testbed/sample_hosts.txt
+++ /dev/null
@@ -1,7 +0,0 @@
1totakura@192.168.0.1:22
2totakura@192.168.0.2:22
3totakura@opt01:22
4totakura@i19-n015:2022
5totakura@asgard.realm
6rivendal
7rohan:561
diff --git a/src/testbed/test-underlay.sqlite b/src/testbed/test-underlay.sqlite
deleted file mode 100644
index 46f48d9db..000000000
--- a/src/testbed/test-underlay.sqlite
+++ /dev/null
Binary files differ
diff --git a/src/testbed/test_gnunet_helper_testbed.c b/src/testbed/test_gnunet_helper_testbed.c
deleted file mode 100644
index ea303a86c..000000000
--- a/src/testbed/test_gnunet_helper_testbed.c
+++ /dev/null
@@ -1,255 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_gnunet_helper_testbed.c
23 * @brief Testcase for testing gnunet-helper-testbed.c
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30#include <zlib.h>
31
32#include "testbed_api.h"
33#include "testbed_helper.h"
34#include "testbed_api_hosts.h"
35
36/**
37 * Generic logging shortcut
38 */
39#define LOG(kind, ...) \
40 GNUNET_log (kind, __VA_ARGS__)
41
42
43/**
44 * Handle to the helper process
45 */
46static struct GNUNET_HELPER_Handle *helper;
47
48/**
49 * Message to helper
50 */
51static struct GNUNET_TESTBED_HelperInit *msg;
52
53/**
54 * Message send handle
55 */
56static struct GNUNET_HELPER_SendHandle *shandle;
57
58/**
59 * Abort task identifier
60 */
61static struct GNUNET_SCHEDULER_Task *abort_task;
62
63/**
64 * Shutdown task identifier
65 */
66static struct GNUNET_SCHEDULER_Task *shutdown_task;
67
68/**
69 * Configuration handle.
70 */
71static struct GNUNET_CONFIGURATION_Handle *cfg;
72
73/**
74 * Global testing status
75 */
76static int result;
77
78
79/**
80 * Shutdown nicely
81 *
82 * @param cls NULL
83 */
84static void
85do_shutdown (void *cls)
86{
87 if (NULL != abort_task)
88 GNUNET_SCHEDULER_cancel (abort_task);
89 if (NULL != helper)
90 GNUNET_HELPER_stop (helper, GNUNET_NO);
91 GNUNET_free (msg);
92 if (NULL != cfg)
93 GNUNET_CONFIGURATION_destroy (cfg);
94}
95
96
97/**
98 * abort task to run on test timed out
99 *
100 * @param cls NULL
101 */
102static void
103do_abort (void *cls)
104{
105 abort_task = NULL;
106 LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
107 result = GNUNET_SYSERR;
108 if (NULL != shandle)
109 GNUNET_HELPER_send_cancel (shandle);
110 if (NULL == shutdown_task)
111 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
112}
113
114
115/**
116 * Continuation function.
117 *
118 * @param cls closure
119 * @param result #GNUNET_OK on success,
120 * #GNUNET_NO if helper process died
121 * #GNUNET_SYSERR during GNUNET_HELPER_stop()
122 */
123static void
124cont_cb (void *cls,
125 int result)
126{
127 shandle = NULL;
128 LOG (GNUNET_ERROR_TYPE_DEBUG,
129 "Message sent\n");
130 GNUNET_assert (GNUNET_OK == result);
131}
132
133
134/**
135 * Functions with this signature are called whenever a
136 * complete message is received by the tokenizer.
137 *
138 * Do not call GNUNET_SERVER_mst_destroy in callback
139 *
140 * @param cls closure
141 * @param client identification of the client
142 * @param message the actual message
143 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
144 */
145static int
146mst_cb (void *cls,
147 const struct GNUNET_MessageHeader *message)
148{
149 const struct GNUNET_TESTBED_HelperReply *msg;
150 char *config;
151 uLongf config_size;
152 uLongf xconfig_size;
153
154 msg = (const struct GNUNET_TESTBED_HelperReply *) message;
155 config_size = 0;
156 xconfig_size = 0;
157 GNUNET_assert (sizeof(struct GNUNET_TESTBED_HelperReply) <
158 ntohs (msg->header.size));
159 GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
160 ntohs (msg->header.type));
161 config_size = (uLongf) ntohs (msg->config_size);
162 xconfig_size =
163 (uLongf) (ntohs (msg->header.size)
164 - sizeof(struct GNUNET_TESTBED_HelperReply));
165 config = GNUNET_malloc (config_size);
166 GNUNET_assert (Z_OK ==
167 uncompress ((Bytef *) config, &config_size,
168 (const Bytef *) &msg[1], xconfig_size));
169 GNUNET_free (config);
170 if (NULL == shutdown_task)
171 shutdown_task =
172 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
173 (GNUNET_TIME_UNIT_SECONDS, 1),
174 &do_shutdown, NULL);
175 return GNUNET_OK;
176}
177
178
179/**
180 * Callback that will be called when the helper process dies. This is not called
181 * when the helper process is stopped using GNUNET_HELPER_stop()
182 *
183 * @param cls the closure from GNUNET_HELPER_start()
184 */
185static void
186exp_cb (void *cls)
187{
188 helper = NULL;
189 result = GNUNET_SYSERR;
190}
191
192
193/**
194 * Main function that will be run.
195 *
196 * @param cls closure
197 * @param args remaining command-line arguments
198 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
199 * @param cfg configuration
200 */
201static void
202run (void *cls, char *const *args, const char *cfgfile,
203 const struct GNUNET_CONFIGURATION_Handle *cfg2)
204{
205 static char *const binary_argv[] = {
206 "gnunet-helper-testbed",
207 NULL
208 };
209 const char *trusted_ip = "127.0.0.1";
210
211 helper =
212 GNUNET_HELPER_start (GNUNET_YES,
213 "gnunet-helper-testbed",
214 binary_argv,
215 &mst_cb,
216 &exp_cb,
217 NULL);
218 GNUNET_assert (NULL != helper);
219 cfg = GNUNET_CONFIGURATION_dup (cfg2);
220 msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, NULL, cfg);
221 shandle =
222 GNUNET_HELPER_send (helper, &msg->header, GNUNET_NO, &cont_cb, NULL);
223 GNUNET_assert (NULL != shandle);
224 abort_task =
225 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
226 (GNUNET_TIME_UNIT_MINUTES, 1), &do_abort,
227 NULL);
228}
229
230
231/**
232 * Main function
233 *
234 * @param argc the number of command line arguments
235 * @param argv command line arg array
236 * @return return code
237 */
238int
239main (int argc, char **argv)
240{
241 struct GNUNET_GETOPT_CommandLineOption options[] = {
242 GNUNET_GETOPT_OPTION_END
243 };
244
245 result = GNUNET_OK;
246 if (GNUNET_OK !=
247 GNUNET_PROGRAM_run (argc, argv, "test_gnunet_helper_testbed",
248 "Testcase for testing gnunet-helper-testbed.c",
249 options, &run, NULL))
250 return 1;
251 return (GNUNET_OK == result) ? 0 : 1;
252}
253
254
255/* end of test_gnunet_helper_testbed.c */
diff --git a/src/testbed/test_testbed_api.c b/src/testbed/test_testbed_api.c
deleted file mode 100644
index a46a7596a..000000000
--- a/src/testbed/test_testbed_api.c
+++ /dev/null
@@ -1,515 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api.c
23 * @brief testcases for the testbed api
24 * @author Sree Harsha Totakura
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_testing_lib.h"
31#include "gnunet_testbed_service.h"
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) \
37 GNUNET_log (kind, __VA_ARGS__)
38
39/**
40 * Relative time seconds shorthand
41 */
42#define TIME_REL_SECS(sec) \
43 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
44
45/**
46 * Our localhost
47 */
48static struct GNUNET_TESTBED_Host *host;
49
50/**
51 * The controller process
52 */
53static struct GNUNET_TESTBED_ControllerProc *cp;
54
55/**
56 * The controller handle
57 */
58static struct GNUNET_TESTBED_Controller *controller;
59
60/**
61 * A neighbouring host
62 */
63static struct GNUNET_TESTBED_Host *neighbour;
64
65/**
66 * Handle for neighbour registration
67 */
68static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
69
70/**
71 * Handle for a peer
72 */
73static struct GNUNET_TESTBED_Peer *peer;
74
75/**
76 * Handle to configuration
77 */
78static struct GNUNET_CONFIGURATION_Handle *cfg;
79
80/**
81 * Handle to operation
82 */
83static struct GNUNET_TESTBED_Operation *operation;
84
85/**
86 * Handle to peer's ARM service
87 */
88static struct GNUNET_ARM_Handle *arm_handle;
89
90/**
91 * Abort task identifier
92 */
93static struct GNUNET_SCHEDULER_Task *abort_task;
94
95/**
96 * The testing result
97 */
98static int result;
99
100
101/**
102 * Enumeration of sub testcases
103 */
104enum Test
105{
106 /**
107 * Test cases which are not covered by the below ones
108 */
109 OTHER,
110
111 /**
112 * Test where we get a peer config from controller
113 */
114 PEER_GETCONFIG,
115
116 /**
117 * Test where we connect to a service running on the peer
118 */
119 PEER_SERVICE_CONNECT,
120
121 /**
122 * Test where we get a peer's identity from controller
123 */
124 PEER_DESTROY
125};
126
127/**
128 * Testing status
129 */
130static enum Test sub_test;
131
132/**
133 * Shutdown nicely
134 *
135 * @param cls NULL
136 * @param tc the task context
137 */
138static void
139do_shutdown (void *cls)
140{
141 LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down...\n");
142 if (NULL != abort_task)
143 GNUNET_SCHEDULER_cancel (abort_task);
144 if (NULL != reg_handle)
145 GNUNET_TESTBED_cancel_registration (reg_handle);
146 if (NULL != controller)
147 GNUNET_TESTBED_controller_disconnect (controller);
148 if (NULL != cfg)
149 GNUNET_CONFIGURATION_destroy (cfg);
150 if (NULL != cp)
151 GNUNET_TESTBED_controller_stop (cp);
152 if (NULL != neighbour)
153 GNUNET_TESTBED_host_destroy (neighbour);
154 if (NULL != host)
155 GNUNET_TESTBED_host_destroy (host);
156}
157
158
159/**
160 * shortcut to exit during failure
161 */
162#define FAIL_TEST(cond, ret) do { \
163 if (! (cond)) { \
164 GNUNET_break (0); \
165 if (NULL != abort_task) \
166 GNUNET_SCHEDULER_cancel (abort_task); \
167 abort_task = NULL; \
168 GNUNET_SCHEDULER_add_now (do_shutdown, NULL); \
169 ret; \
170 } \
171} while (0)
172
173
174/**
175 * abort task to run on test timed out
176 *
177 * @param cls NULL
178 * @param tc the task context
179 */
180static void
181do_abort (void *cls)
182{
183 LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
184 abort_task = NULL;
185 do_shutdown (cls);
186}
187
188
189/**
190 * Adapter function called to establish a connection to
191 * a service.
192 *
193 * @param cls closure
194 * @param cfg configuration of the peer to connect to; will be available until
195 * GNUNET_TESTBED_operation_done() is called on the operation returned
196 * from GNUNET_TESTBED_service_connect()
197 * @return service handle to return in 'op_result', NULL on error
198 */
199static void *
200arm_connect_adapter (void *cls,
201 const struct GNUNET_CONFIGURATION_Handle *cfg)
202{
203 FAIL_TEST (NULL == cls, return NULL);
204 FAIL_TEST (OTHER == sub_test, return NULL);
205 sub_test = PEER_SERVICE_CONNECT;
206 arm_handle = GNUNET_ARM_connect (cfg, NULL, NULL);
207 return arm_handle;
208}
209
210
211/**
212 * Adapter function called to destroy a connection to
213 * a service.
214 *
215 * @param cls closure
216 * @param op_result service handle returned from the connect adapter
217 */
218static void
219arm_disconnect_adapter (void *cls,
220 void *op_result)
221{
222 FAIL_TEST (NULL != op_result, return );
223 FAIL_TEST (op_result == arm_handle, return );
224 GNUNET_ARM_disconnect (arm_handle);
225 arm_handle = NULL;
226 FAIL_TEST (PEER_SERVICE_CONNECT == sub_test, return );
227 FAIL_TEST (NULL != operation, return );
228 operation = GNUNET_TESTBED_peer_stop (NULL, peer, NULL, NULL);
229 FAIL_TEST (NULL != operation, return );
230}
231
232
233/**
234 * Callback to be called when a service connect operation is completed
235 *
236 * @param cls the callback closure from functions generating an operation
237 * @param op the operation that has been finished
238 * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
239 * @param emsg error message in case the operation has failed; will be NULL if
240 * operation has executed successfully.
241 */
242static void
243service_connect_comp_cb (void *cls,
244 struct GNUNET_TESTBED_Operation *op,
245 void *ca_result,
246 const char *emsg)
247{
248 switch (sub_test)
249 {
250 case PEER_SERVICE_CONNECT:
251 FAIL_TEST (operation == op, return );
252 FAIL_TEST (NULL == emsg, return );
253 FAIL_TEST (NULL == cls, return );
254 FAIL_TEST (ca_result == arm_handle, return );
255 GNUNET_TESTBED_operation_done (operation); /* This results in call to
256 * disconnect adapter */
257 break;
258
259 default:
260 FAIL_TEST (0, return );
261 }
262}
263
264
265/**
266 * Callback to be called when the requested peer information is available
267 *
268 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
269 * @param op the operation this callback corresponds to
270 * @param pinfo the result; will be NULL if the operation has failed
271 * @param emsg error message if the operation has failed; will be NULL if the
272 * operation is successful
273 */
274static void
275peerinfo_cb (void *cb_cls,
276 struct GNUNET_TESTBED_Operation *op,
277 const struct GNUNET_TESTBED_PeerInformation *pinfo,
278 const char *emsg)
279{
280 switch (sub_test)
281 {
282 case PEER_GETCONFIG:
283 FAIL_TEST (NULL != pinfo, return );
284 FAIL_TEST (NULL == emsg, return );
285 FAIL_TEST (NULL == cb_cls, return );
286 FAIL_TEST (operation == op, return );
287 FAIL_TEST (GNUNET_TESTBED_PIT_CONFIGURATION == pinfo->pit, return );
288 FAIL_TEST (NULL != pinfo->result.cfg, return );
289 sub_test = PEER_DESTROY;
290 GNUNET_TESTBED_operation_done (operation);
291 operation = GNUNET_TESTBED_peer_destroy (peer);
292 break;
293
294 default:
295 FAIL_TEST (0, return );
296 }
297}
298
299
300/**
301 * Signature of the event handler function called by the
302 * respective event controller.
303 *
304 * @param cls closure
305 * @param event information about the event
306 */
307static void
308controller_cb (void *cls,
309 const struct GNUNET_TESTBED_EventInformation *event)
310{
311 switch (event->type)
312 {
313 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
314 switch (sub_test)
315 {
316 case PEER_DESTROY:
317 FAIL_TEST (event->op == operation, return );
318 FAIL_TEST (NULL == event->op_cls, return );
319 FAIL_TEST (NULL == event->details.operation_finished.emsg, return );
320 FAIL_TEST (NULL == event->details.operation_finished.generic, return );
321 GNUNET_TESTBED_operation_done (operation);
322 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
323 break;
324
325 case PEER_SERVICE_CONNECT:
326 FAIL_TEST (event->op == operation, return );
327 FAIL_TEST (NULL == event->op_cls, return );
328 FAIL_TEST (NULL == event->details.operation_finished.emsg, return );
329 FAIL_TEST (NULL != arm_handle, return );
330 FAIL_TEST (event->details.operation_finished.generic == arm_handle,
331 return );
332 break;
333
334 default:
335 FAIL_TEST (0, return );
336 break;
337 }
338 break;
339
340 case GNUNET_TESTBED_ET_PEER_START:
341 FAIL_TEST (event->details.peer_start.host == host, return );
342 FAIL_TEST (event->details.peer_start.peer == peer, return );
343 FAIL_TEST (OTHER == sub_test, return );
344 GNUNET_TESTBED_operation_done (operation);
345 operation =
346 GNUNET_TESTBED_service_connect (NULL, peer, "dht",
347 &service_connect_comp_cb, NULL,
348 &arm_connect_adapter,
349 &arm_disconnect_adapter, NULL);
350 FAIL_TEST (NULL != operation, return );
351 break;
352
353 case GNUNET_TESTBED_ET_PEER_STOP:
354 FAIL_TEST (event->details.peer_stop.peer == peer, return );
355 FAIL_TEST (PEER_SERVICE_CONNECT == sub_test, return );
356 result = GNUNET_YES;
357 sub_test = PEER_GETCONFIG;
358 GNUNET_TESTBED_operation_done (operation);
359 operation =
360 GNUNET_TESTBED_peer_get_information (peer,
361 GNUNET_TESTBED_PIT_CONFIGURATION,
362 &peerinfo_cb, NULL);
363 break;
364
365 default:
366 FAIL_TEST (0, return ); /* We should never reach this state */
367 }
368}
369
370
371/**
372 * Functions of this signature are called when a peer has been successfully
373 * created
374 *
375 * @param cls the closure from GNUNET_TESTBED_peer_create()
376 * @param peer the handle for the created peer; NULL on any error during
377 * creation
378 * @param emsg NULL if peer is not NULL; else MAY contain the error description
379 */
380static void
381peer_create_cb (void *cls,
382 struct GNUNET_TESTBED_Peer *peer,
383 const char *emsg)
384{
385 struct GNUNET_TESTBED_Peer **peer_ptr;
386
387 peer_ptr = cls;
388 FAIL_TEST (NULL != peer, return );
389 FAIL_TEST (NULL != peer_ptr, return );
390 *peer_ptr = peer;
391 GNUNET_TESTBED_operation_done (operation);
392 operation = GNUNET_TESTBED_peer_start (NULL,
393 peer,
394 NULL,
395 NULL);
396 FAIL_TEST (NULL != operation, return );
397}
398
399
400/**
401 * Callback which will be called to after a host registration succeeded or failed
402 *
403 * @param cls the host which has been registered
404 * @param emsg the error message; NULL if host registration is successful
405 */
406static void
407registration_comp (void *cls,
408 const char *emsg)
409{
410 FAIL_TEST (cls == neighbour, return );
411 reg_handle = NULL;
412 operation =
413 GNUNET_TESTBED_peer_create (controller,
414 host,
415 cfg,
416 &peer_create_cb,
417 &peer);
418 FAIL_TEST (NULL != operation, return );
419}
420
421
422/**
423 * Callback to signal successful startup of the controller process
424 *
425 * @param cls the closure from GNUNET_TESTBED_controller_start()
426 * @param cfg the configuration with which the controller has been started;
427 * NULL if status is not #GNUNET_OK
428 * @param status #GNUNET_OK if the startup is successful; #GNUNET_SYSERR if not,
429 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
430 */
431static void
432status_cb (void *cls,
433 const struct GNUNET_CONFIGURATION_Handle *cfg_,
434 int status)
435{
436 uint64_t event_mask;
437
438 if (GNUNET_OK != status)
439 {
440 cp = NULL;
441 FAIL_TEST (0, return );
442 return;
443 }
444 event_mask = 0;
445 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
446 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
447 event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
448 event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
449 controller =
450 GNUNET_TESTBED_controller_connect (host, event_mask, &controller_cb,
451 NULL);
452 FAIL_TEST (NULL != controller, return );
453 neighbour = GNUNET_TESTBED_host_create ("localhost", NULL, cfg, 0);
454 FAIL_TEST (NULL != neighbour, return );
455 reg_handle =
456 GNUNET_TESTBED_register_host (controller, neighbour, &registration_comp,
457 neighbour);
458 FAIL_TEST (NULL != reg_handle, return );
459}
460
461
462/**
463 * Main run function.
464 *
465 * @param cls NULL
466 * @param args arguments passed to #GNUNET_PROGRAM_run()
467 * @param cfgfile the path to configuration file
468 * @param cfg the configuration file handle
469 */
470static void
471run (void *cls,
472 char *const *args,
473 const char *cfgfile,
474 const struct GNUNET_CONFIGURATION_Handle *config)
475{
476 cfg = GNUNET_CONFIGURATION_dup (config);
477 host = GNUNET_TESTBED_host_create (NULL, NULL, cfg, 0);
478 FAIL_TEST (NULL != host, return );
479 cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host,
480 &status_cb,
481 NULL);
482 abort_task =
483 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
484 (GNUNET_TIME_UNIT_MINUTES, 5),
485 &do_abort,
486 NULL);
487}
488
489
490/**
491 * Main function
492 */
493int
494main (int argc, char **argv)
495{
496 int ret;
497
498 char *const argv2[] = { "test_testbed_api",
499 "-c", "test_testbed_api.conf",
500 NULL };
501 struct GNUNET_GETOPT_CommandLineOption options[] = {
502 GNUNET_GETOPT_OPTION_END
503 };
504
505 result = GNUNET_SYSERR;
506 ret =
507 GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1, argv2,
508 "test_testbed_api", "nohelp", options, &run, NULL);
509 if ((GNUNET_OK != ret) || (GNUNET_OK != result))
510 return 1;
511 return 0;
512}
513
514
515/* end of test_testbed_api.c */
diff --git a/src/testbed/test_testbed_api.conf b/src/testbed/test_testbed_api.conf
deleted file mode 100644
index e5f286d5b..000000000
--- a/src/testbed/test_testbed_api.conf
+++ /dev/null
@@ -1 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
diff --git a/src/testbed/test_testbed_api_2peers_1controller.c b/src/testbed/test_testbed_api_2peers_1controller.c
deleted file mode 100644
index 1ca1d1b2e..000000000
--- a/src/testbed/test_testbed_api_2peers_1controller.c
+++ /dev/null
@@ -1,540 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_2peers_1controller.c
23 * @brief testcases for the testbed api: 2 peers are configured, started and
24 * connected together. The 2 peer reside on a single controller.
25 * @author Sree Harsha Totakura
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_testing_lib.h"
31#include "gnunet_testbed_service.h"
32
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) \
38 GNUNET_log (kind, __VA_ARGS__)
39
40/**
41 * Relative time seconds shorthand
42 */
43#define TIME_REL_SECS(sec) \
44 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
45
46/**
47 * Peer context
48 */
49struct PeerContext
50{
51 /**
52 * The peer handle
53 */
54 struct GNUNET_TESTBED_Peer *peer;
55
56 /**
57 * Operations involving this peer
58 */
59 struct GNUNET_TESTBED_Operation *operation;
60
61 /**
62 * set to GNUNET_YES when peer is started
63 */
64 int is_running;
65};
66
67/**
68 * Our localhost
69 */
70static struct GNUNET_TESTBED_Host *host;
71
72/**
73 * The controller process
74 */
75static struct GNUNET_TESTBED_ControllerProc *cp;
76
77/**
78 * The controller handle
79 */
80static struct GNUNET_TESTBED_Controller *controller;
81
82/**
83 * A neighbouring host
84 */
85static struct GNUNET_TESTBED_Host *neighbour;
86
87/**
88 * Handle for neighbour registration
89 */
90static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
91
92/**
93 * peer 1
94 */
95static struct PeerContext peer1;
96
97/**
98 * peer2
99 */
100static struct PeerContext peer2;
101
102/**
103 * Handle to configuration
104 */
105static struct GNUNET_CONFIGURATION_Handle *cfg;
106
107/**
108 * Handle to operations involving both peers
109 */
110static struct GNUNET_TESTBED_Operation *common_operation;
111
112/**
113 * Abort task identifier
114 */
115static struct GNUNET_SCHEDULER_Task *abort_task;
116
117/**
118 * Delayed connect job identifier
119 */
120static struct GNUNET_SCHEDULER_Task *delayed_connect_task;
121
122/**
123 * Different stages in testing
124 */
125enum Stage
126{
127 /**
128 * Initial stage
129 */
130 INIT,
131
132 /**
133 * peers are created
134 */
135 PEERS_CREATED,
136
137 /**
138 * peers are started
139 */
140 PEERS_STARTED,
141
142 /**
143 * peers are connected
144 */
145 PEERS_CONNECTED,
146
147 /**
148 * Peers are connected once again (this should not fail as they are already connected)
149 */
150 PEERS_CONNECTED_2,
151
152 /**
153 * peers are stopped
154 */
155 PEERS_STOPPED,
156
157 /**
158 * Final success stage
159 */
160 SUCCESS
161};
162
163/**
164 * The testing result
165 */
166static enum Stage result;
167
168
169/**
170 * shortcut to exit during failure
171 */
172#define FAIL_TEST(cond) do { \
173 if (! (cond)) { \
174 GNUNET_break (0); \
175 if (NULL != abort_task) \
176 GNUNET_SCHEDULER_cancel (abort_task); \
177 abort_task = NULL; \
178 GNUNET_SCHEDULER_add_now (do_shutdown, NULL); \
179 return; \
180 } \
181} while (0)
182
183
184/**
185 * Shutdown nicely
186 *
187 * @param cls NULL
188 */
189static void
190do_shutdown (void *cls)
191{
192 if (NULL != abort_task)
193 GNUNET_SCHEDULER_cancel (abort_task);
194 if (NULL != delayed_connect_task)
195 GNUNET_SCHEDULER_cancel (delayed_connect_task);
196 if (NULL != reg_handle)
197 GNUNET_TESTBED_cancel_registration (reg_handle);
198 GNUNET_TESTBED_controller_disconnect (controller);
199 GNUNET_CONFIGURATION_destroy (cfg);
200 if (NULL != cp)
201 GNUNET_TESTBED_controller_stop (cp);
202 GNUNET_TESTBED_host_destroy (neighbour);
203 GNUNET_TESTBED_host_destroy (host);
204}
205
206
207/**
208 * abort task to run on test timed out
209 *
210 * @param cls NULL
211 */
212static void
213do_abort (void *cls)
214{
215 LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
216 abort_task = NULL;
217 do_shutdown (cls);
218}
219
220
221/**
222 * Callback to be called when an operation is completed
223 *
224 * @param cls the callback closure from functions generating an operation
225 * @param op the operation that has been finished
226 * @param emsg error message in case the operation has failed; will be NULL if
227 * operation has executed successfully.
228 */
229static void
230op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg);
231
232
233/**
234 * task for delaying a connect
235 *
236 * @param cls NULL
237 */
238static void
239do_delayed_connect (void *cls)
240{
241 delayed_connect_task = NULL;
242 FAIL_TEST (NULL == common_operation);
243 common_operation =
244 GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
245 peer2.peer);
246}
247
248
249/**
250 * Callback to be called when an operation is completed
251 *
252 * @param cls the callback closure from functions generating an operation
253 * @param op the operation that has been finished
254 * @param emsg error message in case the operation has failed; will be NULL if
255 * operation has executed successfully.
256 */
257static void
258op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
259{
260 FAIL_TEST (common_operation == op);
261 switch (result)
262 {
263 case PEERS_STARTED:
264 FAIL_TEST (NULL == peer1.operation);
265 FAIL_TEST (NULL == peer2.operation);
266 FAIL_TEST (NULL != common_operation);
267 break;
268
269 case PEERS_CONNECTED:
270 FAIL_TEST (NULL == peer1.operation);
271 FAIL_TEST (NULL == peer2.operation);
272 FAIL_TEST (NULL != common_operation);
273 break;
274
275 default:
276 FAIL_TEST (0);
277 }
278}
279
280
281/**
282 * Signature of the event handler function called by the
283 * respective event controller.
284 *
285 * @param cls closure
286 * @param event information about the event
287 */
288static void
289controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
290{
291 switch (event->type)
292 {
293 case GNUNET_TESTBED_ET_OPERATION_FINISHED: /* Will be reached when we destroy peers */
294 FAIL_TEST (PEERS_STOPPED == result);
295 FAIL_TEST (NULL == event->op_cls);
296 FAIL_TEST (NULL == event->details.operation_finished.emsg);
297 FAIL_TEST (NULL == event->details.operation_finished.generic);
298 if (event->op == peer1.operation)
299 {
300 GNUNET_TESTBED_operation_done (peer1.operation);
301 peer1.operation = NULL;
302 peer1.peer = NULL;
303 }
304 else if (event->op == peer2.operation)
305 {
306 GNUNET_TESTBED_operation_done (peer2.operation);
307 peer2.operation = NULL;
308 peer2.peer = NULL;
309 }
310 else
311 FAIL_TEST (0);
312 if ((NULL == peer1.peer) && (NULL == peer2.peer))
313 {
314 result = SUCCESS;
315 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
316 }
317 break;
318
319 case GNUNET_TESTBED_ET_PEER_START:
320 FAIL_TEST (INIT == result);
321 FAIL_TEST (event->details.peer_start.host == host);
322 if (event->details.peer_start.peer == peer1.peer)
323 {
324 peer1.is_running = GNUNET_YES;
325 GNUNET_TESTBED_operation_done (peer1.operation);
326 peer1.operation = NULL;
327 }
328 else if (event->details.peer_start.peer == peer2.peer)
329 {
330 peer2.is_running = GNUNET_YES;
331 GNUNET_TESTBED_operation_done (peer2.operation);
332 peer2.operation = NULL;
333 }
334 else
335 FAIL_TEST (0);
336 if ((GNUNET_YES == peer1.is_running) && (GNUNET_YES == peer2.is_running))
337 {
338 result = PEERS_STARTED;
339 common_operation =
340 GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
341 peer2.peer);
342 }
343 break;
344
345 case GNUNET_TESTBED_ET_PEER_STOP:
346 FAIL_TEST (PEERS_CONNECTED_2 == result);
347 if (event->details.peer_stop.peer == peer1.peer)
348 {
349 peer1.is_running = GNUNET_NO;
350 GNUNET_TESTBED_operation_done (peer1.operation);
351 peer1.operation = GNUNET_TESTBED_peer_destroy (peer1.peer);
352 }
353 else if (event->details.peer_stop.peer == peer2.peer)
354 {
355 peer2.is_running = GNUNET_NO;
356 GNUNET_TESTBED_operation_done (peer2.operation);
357 peer2.operation = GNUNET_TESTBED_peer_destroy (peer2.peer);
358 }
359 else
360 FAIL_TEST (0);
361 if ((GNUNET_NO == peer1.is_running) && (GNUNET_NO == peer2.is_running))
362 result = PEERS_STOPPED;
363 break;
364
365 case GNUNET_TESTBED_ET_CONNECT:
366 switch (result)
367 {
368 case PEERS_STARTED:
369 FAIL_TEST (NULL == peer1.operation);
370 FAIL_TEST (NULL == peer2.operation);
371 FAIL_TEST (NULL != common_operation);
372 FAIL_TEST ((event->details.peer_connect.peer1 == peer1.peer) &&
373 (event->details.peer_connect.peer2 == peer2.peer));
374 GNUNET_TESTBED_operation_done (common_operation);
375 common_operation = NULL;
376 result = PEERS_CONNECTED;
377 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected\n");
378 delayed_connect_task =
379 GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (3), &do_delayed_connect,
380 NULL);
381 break;
382
383 case PEERS_CONNECTED:
384 FAIL_TEST (NULL == peer1.operation);
385 FAIL_TEST (NULL == peer2.operation);
386 FAIL_TEST (NULL != common_operation);
387 GNUNET_TESTBED_operation_done (common_operation);
388 common_operation = NULL;
389 result = PEERS_CONNECTED_2;
390 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected again\n");
391 peer1.operation = GNUNET_TESTBED_peer_stop (NULL, peer1.peer, NULL, NULL);
392 peer2.operation = GNUNET_TESTBED_peer_stop (NULL, peer2.peer, NULL, NULL);
393 break;
394
395 default:
396 FAIL_TEST (0);
397 }
398 break;
399
400 default:
401 FAIL_TEST (0);
402 }
403 ;
404}
405
406
407/**
408 * Functions of this signature are called when a peer has been successfully
409 * created
410 *
411 * @param cls the closure from GNUNET_TESTBED_peer_create()
412 * @param peer the handle for the created peer; NULL on any error during
413 * creation
414 * @param emsg NULL if peer is not NULL; else MAY contain the error description
415 */
416static void
417peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
418{
419 struct PeerContext *pc = cls;
420
421 FAIL_TEST (NULL != pc->operation);
422 FAIL_TEST (NULL != peer);
423 FAIL_TEST (NULL == pc->peer);
424 pc->peer = peer;
425 GNUNET_TESTBED_operation_done (pc->operation);
426 pc->operation = GNUNET_TESTBED_peer_start (NULL, pc->peer, NULL, NULL);
427}
428
429
430/**
431 * Callback which will be called to after a host registration succeeded or failed
432 *
433 * @param cls the host which has been registered
434 * @param emsg the error message; NULL if host registration is successful
435 */
436static void
437registration_comp (void *cls, const char *emsg)
438{
439 FAIL_TEST (cls == neighbour);
440 reg_handle = NULL;
441 peer1.operation =
442 GNUNET_TESTBED_peer_create (controller, host, cfg, &peer_create_cb,
443 &peer1);
444 peer2.operation =
445 GNUNET_TESTBED_peer_create (controller, host, cfg, &peer_create_cb,
446 &peer2);
447 FAIL_TEST (NULL != peer1.operation);
448 FAIL_TEST (NULL != peer2.operation);
449}
450
451
452/**
453 * Callback to signal successful startup of the controller process
454 *
455 * @param cls the closure from GNUNET_TESTBED_controller_start()
456 * @param cfg the configuration with which the controller has been started;
457 * NULL if status is not GNUNET_OK
458 * @param status GNUNET_OK if the startup is successful; GNUNET_SYSERR if not,
459 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
460 */
461static void
462status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg_, int
463 status)
464{
465 uint64_t event_mask;
466
467 if (GNUNET_OK != status)
468 {
469 cp = NULL;
470 FAIL_TEST (0);
471 }
472 event_mask = 0;
473 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
474 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
475 event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
476 event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
477 controller =
478 GNUNET_TESTBED_controller_connect (host, event_mask, &controller_cb,
479 NULL);
480 FAIL_TEST (NULL != controller);
481 neighbour = GNUNET_TESTBED_host_create ("localhost", NULL, cfg, 0);
482 FAIL_TEST (NULL != neighbour);
483 reg_handle =
484 GNUNET_TESTBED_register_host (controller, neighbour, &registration_comp,
485 neighbour);
486 FAIL_TEST (NULL != reg_handle);
487}
488
489
490/**
491 * Main run function.
492 *
493 * @param cls NULL
494 * @param args arguments passed to GNUNET_PROGRAM_run
495 * @param cfgfile the path to configuration file
496 * @param cfg the configuration file handle
497 */
498static void
499run (void *cls, char *const *args, const char *cfgfile,
500 const struct GNUNET_CONFIGURATION_Handle *config)
501{
502 cfg = GNUNET_CONFIGURATION_dup (config);
503 host = GNUNET_TESTBED_host_create (NULL, NULL, cfg, 0);
504 FAIL_TEST (NULL != host);
505 cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, status_cb,
506 NULL);
507 abort_task =
508 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
509 (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
510 NULL);
511}
512
513
514/**
515 * Main function
516 */
517int
518main (int argc, char **argv)
519{
520 int ret;
521
522 char *const argv2[] = { "test_testbed_api_2peers_1controller",
523 "-c", "test_testbed_api.conf",
524 NULL };
525 struct GNUNET_GETOPT_CommandLineOption options[] = {
526 GNUNET_GETOPT_OPTION_END
527 };
528
529 result = INIT;
530 ret =
531 GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1, argv2,
532 "test_testbed_api_2peers_1controller", "nohelp",
533 options, &run, NULL);
534 if ((GNUNET_OK != ret) || (SUCCESS != result))
535 return 1;
536 return 0;
537}
538
539
540/* end of test_testbed_api_2peers_1controller.c */
diff --git a/src/testbed/test_testbed_api_3peers_3controllers.c b/src/testbed/test_testbed_api_3peers_3controllers.c
deleted file mode 100644
index 17072ffa8..000000000
--- a/src/testbed/test_testbed_api_3peers_3controllers.c
+++ /dev/null
@@ -1,964 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_3peers_3controllers.c
23 * @brief testcases for the testbed api: 3 peers are configured, started and
24 * connected together. Each peer resides on its own controller.
25 * @author Sree Harsha Totakura
26 */
27
28
29/**
30 * The testing architecture is:
31 * A
32 * / \
33 * / \
34 * B === C
35 * A is the master controller and B, C are slave controllers. B links to C
36 * laterally.
37 * Peers are mapped to controllers in the following relations:
38 * Peer Controller
39 * 1 A
40 * 2 B
41 * 3 C
42 *
43 */
44
45#include "platform.h"
46#include "gnunet_util_lib.h"
47#include "gnunet_testing_lib.h"
48#include "gnunet_testbed_service.h"
49
50
51/**
52 * Generic logging shortcut
53 */
54#define LOG(kind, ...) \
55 GNUNET_log (kind, __VA_ARGS__)
56
57/**
58 * Relative time seconds shorthand
59 */
60#define TIME_REL_SECS(sec) \
61 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
62
63
64/**
65 * Peer context
66 */
67struct PeerContext
68{
69 /**
70 * The peer handle
71 */
72 struct GNUNET_TESTBED_Peer *peer;
73
74 /**
75 * Operations involving this peer
76 */
77 struct GNUNET_TESTBED_Operation *operation;
78
79 /**
80 * set to GNUNET_YES when peer is started
81 */
82 int is_running;
83};
84
85/**
86 * Our localhost
87 */
88static struct GNUNET_TESTBED_Host *host;
89
90/**
91 * The controller process of one controller
92 */
93static struct GNUNET_TESTBED_ControllerProc *cp1;
94
95/**
96 * A neighbouring host
97 */
98static struct GNUNET_TESTBED_Host *neighbour1;
99
100/**
101 * Another neighbouring host
102 */
103static struct GNUNET_TESTBED_Host *neighbour2;
104
105/**
106 * Handle for neighbour registration
107 */
108static struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
109
110/**
111 * The controller handle of one controller
112 */
113static struct GNUNET_TESTBED_Controller *controller1;
114
115/**
116 * peer 1
117 */
118static struct PeerContext peer1;
119
120/**
121 * peer2
122 */
123static struct PeerContext peer2;
124
125/**
126 * peer3
127 */
128static struct PeerContext peer3;
129
130/**
131 * Handle to starting configuration
132 */
133static struct GNUNET_CONFIGURATION_Handle *cfg;
134
135/**
136 * Handle to slave controller C's configuration, used to establish lateral link from
137 * master controller
138 */
139static struct GNUNET_CONFIGURATION_Handle *cfg2;
140
141/**
142 * Handle to operations involving both peers
143 */
144static struct GNUNET_TESTBED_Operation *common_operation;
145
146/**
147 * The handle for whether a host is habitable or not
148 */
149struct GNUNET_TESTBED_HostHabitableCheckHandle *hc_handle;
150
151/**
152 * Abort task identifier
153 */
154static struct GNUNET_SCHEDULER_Task *abort_task;
155
156/**
157 * Delayed connect job identifier
158 */
159static struct GNUNET_SCHEDULER_Task *delayed_connect_task;
160
161/**
162 * Different stages in testing
163 */
164enum Stage
165{
166 /**
167 * Initial stage
168 */
169 INIT,
170
171 /**
172 * Controller 1 has started
173 */
174 CONTROLLER1_UP,
175
176 /**
177 * peer1 is created
178 */
179 PEER1_CREATED,
180
181 /**
182 * peer1 is started
183 */
184 PEER1_STARTED,
185
186 /**
187 * Controller 2 has started
188 */
189 CONTROLLER2_UP,
190
191 /**
192 * peer2 is created
193 */
194 PEER2_CREATED,
195
196 /**
197 * peer2 is started
198 */
199 PEER2_STARTED,
200
201 /**
202 * Controller 3 has started
203 */
204 CONTROLLER3_UP,
205
206 /**
207 * Peer3 is created
208 */
209 PEER3_CREATED,
210
211 /**
212 * Peer3 started
213 */
214 PEER3_STARTED,
215
216 /**
217 * peer1 and peer2 are connected
218 */
219 PEERS_1_2_CONNECTED,
220
221 /**
222 * peer2 and peer3 are connected
223 */
224 PEERS_2_3_CONNECTED,
225
226 /**
227 * Peers are connected once again (this should not fail as they are already connected)
228 */
229 PEERS_CONNECTED_2,
230
231 /**
232 * peers are stopped
233 */
234 PEERS_STOPPED,
235
236 /**
237 * Final success stage
238 */
239 SUCCESS,
240
241 /**
242 * Optional stage for marking test to be skipped
243 */
244 SKIP
245};
246
247/**
248 * The testing result
249 */
250static enum Stage result;
251
252/**
253 * Shutdown nicely
254 *
255 * @param cls NULL
256 */
257static void
258do_shutdown (void *cls)
259{
260 if (NULL != abort_task)
261 GNUNET_SCHEDULER_cancel (abort_task);
262 if (NULL != hc_handle)
263 GNUNET_TESTBED_is_host_habitable_cancel (hc_handle);
264 GNUNET_assert (NULL == delayed_connect_task);
265 if (NULL != common_operation)
266 GNUNET_TESTBED_operation_done (common_operation);
267 if (NULL != reg_handle)
268 GNUNET_TESTBED_cancel_registration (reg_handle);
269 if (NULL != controller1)
270 GNUNET_TESTBED_controller_disconnect (controller1);
271 GNUNET_CONFIGURATION_destroy (cfg);
272 if (NULL != cfg2)
273 GNUNET_CONFIGURATION_destroy (cfg2);
274 if (NULL != cp1)
275 GNUNET_TESTBED_controller_stop (cp1);
276 if (NULL != host)
277 GNUNET_TESTBED_host_destroy (host);
278 if (NULL != neighbour1)
279 GNUNET_TESTBED_host_destroy (neighbour1);
280 if (NULL != neighbour2)
281 GNUNET_TESTBED_host_destroy (neighbour2);
282}
283
284
285/**
286 * abort task to run on test timed out
287 *
288 * @param cls NULL
289 */
290static void
291do_abort (void *cls)
292{
293 LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
294 abort_task = NULL;
295 if (NULL != delayed_connect_task)
296 {
297 GNUNET_SCHEDULER_cancel (delayed_connect_task);
298 delayed_connect_task = NULL;
299 }
300 do_shutdown (cls);
301}
302
303
304static void
305abort_test ()
306{
307 if (NULL != abort_task)
308 GNUNET_SCHEDULER_cancel (abort_task);
309 abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
310}
311
312
313/**
314 * Callback to be called when an operation is completed
315 *
316 * @param cls the callback closure from functions generating an operation
317 * @param op the operation that has been finished
318 * @param emsg error message in case the operation has failed; will be NULL if
319 * operation has executed successfully.
320 */
321static void
322op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg);
323
324
325/**
326 * task for delaying a connect
327 *
328 * @param cls NULL
329 */
330static void
331do_delayed_connect (void *cls)
332{
333 delayed_connect_task = NULL;
334 if (NULL != common_operation)
335 {
336 GNUNET_break (0);
337 abort_test ();
338 return;
339 }
340 common_operation =
341 GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer1.peer,
342 peer2.peer);
343}
344
345
346/**
347 * Callback to be called when an operation is completed
348 *
349 * @param cls the callback closure from functions generating an operation
350 * @param op the operation that has been finished
351 * @param emsg error message in case the operation has failed; will be NULL if
352 * operation has executed successfully.
353 */
354static void
355op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
356{
357 if (common_operation != op)
358 {
359 GNUNET_break (0);
360 abort_test ();
361 return;
362 }
363
364 switch (result)
365 {
366 case PEER3_STARTED:
367 case PEERS_2_3_CONNECTED:
368 case PEERS_1_2_CONNECTED:
369 break;
370
371 default:
372 GNUNET_break (0);
373 abort_test ();
374 return;
375 }
376 if ((NULL != peer1.operation) || (NULL != peer2.operation) ||
377 (NULL != peer3.operation))
378 {
379 GNUNET_break (0);
380 abort_test ();
381 return;
382 }
383}
384
385
386/**
387 * Functions of this signature are called when a peer has been successfully
388 * created
389 *
390 * @param cls NULL
391 * @param peer the handle for the created peer; NULL on any error during
392 * creation
393 * @param emsg NULL if peer is not NULL; else MAY contain the error description
394 */
395static void
396peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
397{
398 switch (result)
399 {
400 case CONTROLLER1_UP:
401 if ((NULL == peer1.operation) || (NULL == peer) || (NULL != peer1.peer))
402 {
403 GNUNET_break (0);
404 abort_test ();
405 return;
406 }
407 peer1.peer = peer;
408 GNUNET_TESTBED_operation_done (peer1.operation);
409 result = PEER1_CREATED;
410 peer1.operation = GNUNET_TESTBED_peer_start (NULL, peer, NULL, NULL);
411 break;
412
413 case CONTROLLER2_UP:
414 if ((NULL == peer2.operation) || (NULL == peer) || (NULL != peer2.peer))
415 {
416 GNUNET_break (0);
417 abort_test ();
418 return;
419 }
420 peer2.peer = peer;
421 GNUNET_TESTBED_operation_done (peer2.operation);
422 result = PEER2_CREATED;
423 peer2.operation = GNUNET_TESTBED_peer_start (NULL, peer, NULL, NULL);
424 break;
425
426 case CONTROLLER3_UP:
427 if ((NULL == peer3.operation) || (NULL == peer) || (NULL != peer3.peer))
428 {
429 GNUNET_break (0);
430 abort_test ();
431 return;
432 }
433 peer3.peer = peer;
434 GNUNET_TESTBED_operation_done (peer3.operation);
435 result = PEER3_CREATED;
436 peer3.operation = GNUNET_TESTBED_peer_start (NULL, peer, NULL, NULL);
437 break;
438
439 default:
440 GNUNET_break (0);
441 abort_test ();
442 return;
443 }
444}
445
446
447/**
448 * Signature of the event handler function called by the
449 * respective event controller.
450 *
451 * @param cls closure
452 * @param event information about the event
453 */
454static void
455controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
456{
457 switch (event->type)
458 {
459 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
460 if ((NULL != event->op_cls) ||
461 (NULL != event->details.operation_finished.emsg))
462 {
463 GNUNET_break (0);
464 abort_test ();
465 return;
466 }
467 switch (result)
468 {
469 case PEERS_STOPPED:
470 if (NULL != event->details.operation_finished.generic)
471 {
472 GNUNET_break (0);
473 abort_test ();
474 return;
475 }
476 if (event->op == peer1.operation)
477 {
478 GNUNET_TESTBED_operation_done (peer1.operation);
479 peer1.operation = NULL;
480 peer1.peer = NULL;
481 }
482 else if (event->op == peer2.operation)
483 {
484 GNUNET_TESTBED_operation_done (peer2.operation);
485 peer2.operation = NULL;
486 peer2.peer = NULL;
487 }
488 else if (event->op == peer3.operation)
489 {
490 GNUNET_TESTBED_operation_done (peer3.operation);
491 peer3.operation = NULL;
492 peer3.peer = NULL;
493 }
494 else
495 {
496 GNUNET_break (0);
497 abort_test ();
498 return;
499 }
500 if ((NULL == peer1.peer) && (NULL == peer2.peer) && (NULL == peer3.peer))
501 {
502 result = SUCCESS;
503 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
504 }
505 break;
506
507 case PEER1_STARTED:
508 if ((NULL != event->details.operation_finished.generic) ||
509 (NULL == common_operation))
510 {
511 GNUNET_break (0);
512 abort_test ();
513 return;
514 }
515 GNUNET_TESTBED_operation_done (common_operation);
516 common_operation = NULL;
517 result = CONTROLLER2_UP;
518 peer2.operation =
519 GNUNET_TESTBED_peer_create (controller1, neighbour1, cfg,
520 &peer_create_cb, NULL);
521 if (NULL == peer2.operation)
522 {
523 GNUNET_break (0);
524 abort_test ();
525 return;
526 }
527 break;
528
529 case PEER2_STARTED:
530 if ((NULL != event->details.operation_finished.generic) ||
531 (NULL == common_operation))
532 {
533 GNUNET_break (0);
534 abort_test ();
535 return;
536 }
537 GNUNET_TESTBED_operation_done (common_operation);
538 common_operation = NULL;
539 result = CONTROLLER3_UP;
540 peer3.operation =
541 GNUNET_TESTBED_peer_create (controller1, neighbour2, cfg,
542 &peer_create_cb, NULL);
543 if (NULL == peer3.operation)
544 {
545 GNUNET_break (0);
546 abort_test ();
547 return;
548 }
549 break;
550
551 default:
552 GNUNET_break (0);
553 abort_test ();
554 return;
555 }
556 break;
557
558 case GNUNET_TESTBED_ET_PEER_START:
559 switch (result)
560 {
561 case PEER1_CREATED:
562 if (event->details.peer_start.host != host)
563 {
564 GNUNET_break (0);
565 abort_test ();
566 return;
567 }
568 peer1.is_running = GNUNET_YES;
569 GNUNET_TESTBED_operation_done (peer1.operation);
570 peer1.operation = NULL;
571 result = PEER1_STARTED;
572 common_operation =
573 GNUNET_TESTBED_controller_link (NULL, controller1, neighbour1, NULL,
574 GNUNET_YES);
575 break;
576
577 case PEER2_CREATED:
578 if (event->details.peer_start.host != neighbour1)
579 {
580 GNUNET_break (0);
581 abort_test ();
582 return;
583 }
584 peer2.is_running = GNUNET_YES;
585 GNUNET_TESTBED_operation_done (peer2.operation);
586 peer2.operation = NULL;
587 result = PEER2_STARTED;
588 if (NULL != common_operation)
589 {
590 GNUNET_break (0);
591 abort_test ();
592 return;
593 }
594 common_operation =
595 GNUNET_TESTBED_controller_link (NULL, controller1, neighbour2, NULL,
596 GNUNET_YES);
597 if (NULL == common_operation)
598 {
599 GNUNET_break (0);
600 abort_test ();
601 return;
602 }
603 break;
604
605 case PEER3_CREATED:
606 if (event->details.peer_start.host != neighbour2)
607 {
608 GNUNET_break (0);
609 abort_test ();
610 return;
611 }
612 peer3.is_running = GNUNET_YES;
613 GNUNET_TESTBED_operation_done (peer3.operation);
614 peer3.operation = NULL;
615 result = PEER3_STARTED;
616 common_operation =
617 GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer2.peer,
618 peer1.peer);
619 break;
620
621 default:
622 GNUNET_break (0);
623 abort_test ();
624 return;
625 }
626 break;
627
628 case GNUNET_TESTBED_ET_PEER_STOP:
629 if (PEERS_CONNECTED_2 != result)
630 {
631 GNUNET_break (0);
632 abort_test ();
633 return;
634 }
635 if (event->details.peer_stop.peer == peer1.peer)
636 {
637 peer1.is_running = GNUNET_NO;
638 GNUNET_TESTBED_operation_done (peer1.operation);
639 }
640 else if (event->details.peer_stop.peer == peer2.peer)
641 {
642 peer2.is_running = GNUNET_NO;
643 GNUNET_TESTBED_operation_done (peer2.operation);
644 }
645 else if (event->details.peer_stop.peer == peer3.peer)
646 {
647 peer3.is_running = GNUNET_NO;
648 GNUNET_TESTBED_operation_done (peer3.operation);
649 }
650 else
651 {
652 GNUNET_break (0);
653 abort_test ();
654 return;
655 }
656 if ((GNUNET_NO == peer1.is_running) && (GNUNET_NO == peer2.is_running) &&
657 (GNUNET_NO == peer3.is_running))
658 {
659 result = PEERS_STOPPED;
660 peer1.operation = GNUNET_TESTBED_peer_destroy (peer1.peer);
661 peer2.operation = GNUNET_TESTBED_peer_destroy (peer2.peer);
662 peer3.operation = GNUNET_TESTBED_peer_destroy (peer3.peer);
663 }
664 break;
665
666 case GNUNET_TESTBED_ET_CONNECT:
667 if ((NULL != peer1.operation) || (NULL != peer2.operation) ||
668 (NULL != peer3.operation) || (NULL == common_operation))
669 {
670 GNUNET_break (0);
671 abort_test ();
672 return;
673 }
674 switch (result)
675 {
676 case PEER3_STARTED:
677 if ((event->details.peer_connect.peer1 != peer2.peer) ||
678 (event->details.peer_connect.peer2 != peer1.peer))
679 {
680 GNUNET_break (0);
681 abort_test ();
682 return;
683 }
684 GNUNET_TESTBED_operation_done (common_operation);
685 common_operation = NULL;
686 result = PEERS_1_2_CONNECTED;
687 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected\n");
688 common_operation =
689 GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peer2.peer,
690 peer3.peer);
691 break;
692
693 case PEERS_1_2_CONNECTED:
694 if ((event->details.peer_connect.peer1 != peer2.peer) ||
695 (event->details.peer_connect.peer2 != peer3.peer))
696 {
697 GNUNET_break (0);
698 abort_test ();
699 return;
700 }
701 GNUNET_TESTBED_operation_done (common_operation);
702 common_operation = NULL;
703 result = PEERS_2_3_CONNECTED;
704 delayed_connect_task =
705 GNUNET_SCHEDULER_add_delayed (TIME_REL_SECS (3), &do_delayed_connect,
706 NULL);
707 break;
708
709 case PEERS_2_3_CONNECTED:
710 if ((event->details.peer_connect.peer1 != peer1.peer) ||
711 (event->details.peer_connect.peer2 != peer2.peer))
712 {
713 GNUNET_break (0);
714 abort_test ();
715 return;
716 }
717 GNUNET_TESTBED_operation_done (common_operation);
718 common_operation = NULL;
719 result = PEERS_CONNECTED_2;
720 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peers connected again\n");
721 peer1.operation = GNUNET_TESTBED_peer_stop (NULL, peer1.peer, NULL, NULL);
722 peer2.operation = GNUNET_TESTBED_peer_stop (NULL, peer2.peer, NULL, NULL);
723 peer3.operation = GNUNET_TESTBED_peer_stop (NULL, peer3.peer, NULL, NULL);
724 break;
725
726 default:
727 GNUNET_break (0);
728 abort_test ();
729 return;
730 }
731 break;
732
733 default:
734 GNUNET_break (0);
735 abort_test ();
736 return;
737 }
738}
739
740
741/**
742 * Callback which will be called to after a host registration succeeded or failed
743 *
744 * @param cls the host which has been registered
745 * @param emsg the error message; NULL if host registration is successful
746 */
747static void
748registration_comp (void *cls, const char *emsg)
749{
750 reg_handle = NULL;
751 if (cls == neighbour1)
752 {
753 neighbour2 = GNUNET_TESTBED_host_create ("127.0.0.1", NULL, cfg, 0);
754 if (NULL == neighbour2)
755 {
756 GNUNET_break (0);
757 abort_test ();
758 return;
759 }
760 reg_handle =
761 GNUNET_TESTBED_register_host (controller1, neighbour2,
762 &registration_comp, neighbour2);
763 if (NULL == reg_handle)
764 {
765 GNUNET_break (0);
766 abort_test ();
767 return;
768 }
769 return;
770 }
771 if (cls != neighbour2)
772 {
773 GNUNET_break (0);
774 abort_test ();
775 return;
776 }
777 peer1.operation =
778 GNUNET_TESTBED_peer_create (controller1, host, cfg, &peer_create_cb,
779 &peer1);
780 if (NULL == peer1.operation)
781 {
782 GNUNET_break (0);
783 abort_test ();
784 return;
785 }
786}
787
788
789/**
790 * Callback to signal successful startup of the controller process
791 *
792 * @param cls the closure from GNUNET_TESTBED_controller_start()
793 * @param cfg the configuration with which the controller has been started;
794 * NULL if status is not GNUNET_OK
795 * @param status GNUNET_OK if the startup is successful; GNUNET_SYSERR if not,
796 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
797 */
798static void
799status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *config,
800 int status)
801{
802 uint64_t event_mask;
803
804 if (GNUNET_OK != status)
805 {
806 GNUNET_break (0);
807 cp1 = NULL;
808 abort_test ();
809 return;
810 }
811 event_mask = 0;
812 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
813 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
814 event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
815 event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
816 switch (result)
817 {
818 case INIT:
819 controller1 =
820 GNUNET_TESTBED_controller_connect (host, event_mask,
821 &controller_cb, NULL);
822 if (NULL == controller1)
823 {
824 GNUNET_break (0);
825 abort_test ();
826 return;
827 }
828 result = CONTROLLER1_UP;
829 neighbour1 = GNUNET_TESTBED_host_create ("127.0.0.1", NULL, cfg, 0);
830 if (NULL == neighbour1)
831 {
832 GNUNET_break (0);
833 abort_test ();
834 return;
835 }
836 reg_handle =
837 GNUNET_TESTBED_register_host (controller1, neighbour1,
838 &registration_comp, neighbour1);
839 if (NULL == reg_handle)
840 {
841 GNUNET_break (0);
842 abort_test ();
843 return;
844 }
845 break;
846
847 default:
848 GNUNET_break (0);
849 abort_test ();
850 return;
851 }
852}
853
854
855/**
856 * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
857 * inform whether the given host is habitable or not. The Handle returned by
858 * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
859 *
860 * @param cls NULL
861 * @param host the host whose status is being reported; will be NULL if the host
862 * given to GNUNET_TESTBED_is_host_habitable() is NULL
863 * @param status #GNUNET_YES if it is habitable; #GNUNET_NO if not
864 */
865static void
866host_habitable_cb (void *cls,
867 const struct GNUNET_TESTBED_Host *_host,
868 int status)
869{
870 hc_handle = NULL;
871 if (GNUNET_NO == status)
872 {
873 (void) printf ("%s",
874 "Unable to run the test as this system is not configured "
875 "to use password less SSH logins to localhost.\n"
876 "Skipping test\n");
877 GNUNET_SCHEDULER_cancel (abort_task);
878 abort_task = NULL;
879 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
880 result = SKIP;
881 return;
882 }
883 cp1 =
884 GNUNET_TESTBED_controller_start ("127.0.0.1", host, status_cb, NULL);
885}
886
887
888/**
889 * Main run function.
890 *
891 * @param cls NULL
892 * @param args arguments passed to GNUNET_PROGRAM_run
893 * @param cfgfile the path to configuration file
894 * @param cfg the configuration file handle
895 */
896static void
897run (void *cls, char *const *args, const char *cfgfile,
898 const struct GNUNET_CONFIGURATION_Handle *config)
899{
900 cfg = GNUNET_CONFIGURATION_dup (config);
901 host = GNUNET_TESTBED_host_create (NULL, NULL, cfg, 0);
902 if (NULL == host)
903 {
904 GNUNET_break (0);
905 abort_test ();
906 return;
907 }
908 if (NULL ==
909 (hc_handle =
910 GNUNET_TESTBED_is_host_habitable (host, config, &host_habitable_cb,
911 NULL)))
912 {
913 GNUNET_TESTBED_host_destroy (host);
914 host = NULL;
915 (void) printf ("%s",
916 "Unable to run the test as this system is not configured "
917 "to use password less SSH logins to localhost.\n"
918 "Skipping test\n");
919 result = SKIP;
920 return;
921 }
922 abort_task =
923 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
924 (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
925 NULL);
926}
927
928
929/**
930 * Main function
931 */
932int
933main (int argc, char **argv)
934{
935 char *const argv2[] = { "test_testbed_api_3peers_3controllers",
936 "-c", "test_testbed_api.conf",
937 NULL };
938 struct GNUNET_GETOPT_CommandLineOption options[] = {
939 GNUNET_GETOPT_OPTION_END
940 };
941 int ret;
942
943 result = INIT;
944 ret =
945 GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1, argv2,
946 "test_testbed_api_3peers_3controllers", "nohelp",
947 options, &run, NULL);
948 if (GNUNET_OK != ret)
949 return 1;
950 switch (result)
951 {
952 case SUCCESS:
953 return 0;
954
955 case SKIP:
956 return 77; /* Mark test as skipped */
957
958 default:
959 return 1;
960 }
961}
962
963
964/* end of test_testbed_api_3peers_3controllers.c */
diff --git a/src/testbed/test_testbed_api_barriers.c b/src/testbed/test_testbed_api_barriers.c
deleted file mode 100644
index 74dd89126..000000000
--- a/src/testbed/test_testbed_api_barriers.c
+++ /dev/null
@@ -1,234 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_barriers.c
23 * @brief testcase binary for testing testbed barriers API
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30#include "test_testbed_api_barriers.h"
31
32
33/**
34 * logging short hand
35 */
36#define LOG(type, ...) \
37 GNUNET_log (type, __VA_ARGS__);
38
39/**
40 * Number of peers we start in this test case
41 */
42#define NUM_PEERS 3
43
44
45/**
46 * Our barrier
47 */
48struct GNUNET_TESTBED_Barrier *barrier;
49
50/**
51 * Identifier for the shutdown task
52 */
53static struct GNUNET_SCHEDULER_Task *timeout_task;
54
55/**
56 * Result of this test case
57 */
58static int result;
59
60
61/**
62 * Handle SIGINT and SIGTERM
63 */
64static void
65shutdown_handler (void *cls)
66{
67 if (NULL != timeout_task)
68 {
69 GNUNET_SCHEDULER_cancel (timeout_task);
70 timeout_task = NULL;
71 }
72}
73
74
75/**
76 * Shutdown this test case when it takes too long
77 *
78 * @param cls NULL
79 */
80static void
81do_timeout (void *cls)
82{
83 timeout_task = NULL;
84 if (barrier != NULL)
85 GNUNET_TESTBED_barrier_cancel (barrier);
86 GNUNET_SCHEDULER_shutdown ();
87}
88
89
90/**
91 * Functions of this type are to be given as callback argument to
92 * GNUNET_TESTBED_barrier_init(). The callback will be called when status
93 * information is available for the barrier.
94 *
95 * @param cls the closure given to GNUNET_TESTBED_barrier_init()
96 * @param name the name of the barrier
97 * @param barrier the barrier handle
98 * @param status status of the barrier; #GNUNET_OK if the barrier is crossed;
99 * #GNUNET_SYSERR upon error
100 * @param emsg if the status were to be #GNUNET_SYSERR, this parameter has the
101 * error message
102 */
103static void
104barrier_cb (void *cls,
105 const char *name,
106 struct GNUNET_TESTBED_Barrier *_barrier,
107 enum GNUNET_TESTBED_BarrierStatus status,
108 const char *emsg)
109{
110 static enum GNUNET_TESTBED_BarrierStatus old_status;
111
112 GNUNET_assert (NULL == cls);
113 GNUNET_assert (_barrier == barrier);
114 switch (status)
115 {
116 case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
117 LOG (GNUNET_ERROR_TYPE_INFO,
118 "Barrier initialised\n");
119 old_status = status;
120 return;
121
122 case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
123 LOG (GNUNET_ERROR_TYPE_ERROR,
124 "Barrier initialisation failed: %s",
125 (NULL == emsg) ? "unknown reason" : emsg);
126 break;
127
128 case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
129 LOG (GNUNET_ERROR_TYPE_INFO,
130 "Barrier crossed\n");
131 if (old_status == GNUNET_TESTBED_BARRIERSTATUS_INITIALISED)
132 result = GNUNET_OK;
133 break;
134
135 default:
136 GNUNET_assert (0);
137 return;
138 }
139 barrier = NULL;
140 GNUNET_SCHEDULER_shutdown ();
141}
142
143
144/**
145 * Signature of a main function for a testcase.
146 *
147 * @param cls closure
148 * @param h the run handle
149 * @param num_peers number of peers in 'peers'
150 * @param peers_ handle to peers run in the testbed
151 * @param links_succeeded the number of overlay link connection attempts that
152 * succeeded
153 * @param links_failed the number of overlay link connection attempts that
154 * failed
155 */
156static void
157test_master (void *cls,
158 struct GNUNET_TESTBED_RunHandle *h,
159 unsigned int num_peers,
160 struct GNUNET_TESTBED_Peer **peers_,
161 unsigned int links_succeeded,
162 unsigned int links_failed)
163{
164 struct GNUNET_TESTBED_Controller *c;
165
166 GNUNET_assert (NULL == cls);
167 if (NULL == peers_)
168 {
169 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
170 "Failing test due to timeout\n");
171 return;
172 }
173 GNUNET_assert (NUM_PEERS == num_peers);
174 c = GNUNET_TESTBED_run_get_controller_handle (h);
175 barrier = GNUNET_TESTBED_barrier_init (c,
176 TEST_BARRIER_NAME,
177 100,
178 &barrier_cb,
179 NULL);
180 timeout_task =
181 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
182 (GNUNET_TIME_UNIT_SECONDS,
183 10 * (NUM_PEERS + 1)),
184 &do_timeout, NULL);
185 GNUNET_SCHEDULER_add_shutdown (&shutdown_handler, NULL);
186}
187
188
189#ifndef PATH_MAX
190/**
191 * Assumed maximum path length (for the log file name).
192 */
193#define PATH_MAX 4096
194#endif
195
196
197/**
198 * Main function
199 */
200int
201main (int argc, char **argv)
202{
203 struct GNUNET_CONFIGURATION_Handle *cfg;
204 char pwd[PATH_MAX];
205 char *binary;
206 uint64_t event_mask;
207
208 result = GNUNET_SYSERR;
209 event_mask = 0;
210 cfg = GNUNET_CONFIGURATION_create ();
211 GNUNET_assert (GNUNET_YES ==
212 GNUNET_CONFIGURATION_parse (cfg,
213 "test_testbed_api_barriers.conf.in"));
214 if (NULL == getcwd (pwd, PATH_MAX))
215 return 1;
216 GNUNET_assert (0 < GNUNET_asprintf (&binary, "%s/%s", pwd,
217 "gnunet-service-test-barriers"));
218 GNUNET_CONFIGURATION_set_value_string (cfg, "test-barriers", "BINARY",
219 binary);
220 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_write
221 (cfg, "test_testbed_api_barriers.conf"));
222 GNUNET_CONFIGURATION_destroy (cfg);
223 cfg = NULL;
224 GNUNET_free (binary);
225 binary = NULL;
226 (void) GNUNET_TESTBED_test_run ("test_testbed_api_barriers",
227 "test_testbed_api_barriers.conf", NUM_PEERS,
228 event_mask, NULL, NULL,
229 &test_master, NULL);
230 (void) unlink ("test_testbed_api_barriers.conf");
231 if (GNUNET_OK != result)
232 return 1;
233 return 0;
234}
diff --git a/src/testbed/test_testbed_api_barriers.conf.in b/src/testbed/test_testbed_api_barriers.conf.in
deleted file mode 100644
index 2e9c0038d..000000000
--- a/src/testbed/test_testbed_api_barriers.conf.in
+++ /dev/null
@@ -1,103 +0,0 @@
1[testbed]
2START_ON_DEMAND = NO
3PORT = 12113
4ACCEPT_FROM = 127.0.0.1;
5HOSTNAME = localhost
6TOPOLOGY = RANDOM
7#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
8
9[arm]
10PORT = 12366
11
12[test-barriers]
13START_ON_DEMAND = NO
14PORT = 12114
15BINARY = /will/be/overwritten/in/test_testbed_api_barriers/
16IMMEDIATE_START = YES
17
18[fs]
19START_ON_DEMAND = NO
20IMMEDIATE_START = NO
21
22[resolver]
23HOSTNAME = localhost
24START_ON_DEMAND = NO
25
26[cadet]
27START_ON_DEMAND = NO
28IMMEDIATE_START = NO
29
30[dht]
31START_ON_DEMAND = NO
32IMMEDIATE_START = NO
33
34[dhtcache]
35QUOTA = 1 MB
36DATABASE = heap
37
38[transport]
39PLUGINS = udp
40ACCEPT_FROM6 = ::1;
41ACCEPT_FROM = 127.0.0.1;
42NEIGHBOUR_LIMIT = 50
43PORT = 12365
44IMMEDIATE_START = YES
45
46[ats]
47WAN_QUOTA_OUT = 3932160
48WAN_QUOTA_IN = 3932160
49
50[core]
51PORT = 12092
52START_ON_DEMAND = YES
53IMMEDIATE_START = YES
54USE_EPHEMERAL_KEYS = NO
55
56[transport-udp]
57TIMEOUT = 300 s
58PORT = 12368
59
60[PATHS]
61GNUNET_TEST_HOME = $GNUNET_TMP/test-testbed/
62
63[dns]
64START_ON_DEMAND = NO
65IMMEDIATE_START = NO
66
67[nse]
68START_ON_DEMAND = NO
69IMMEDIATE_START = NO
70
71[vpn]
72START_ON_DEMAND = NO
73IMMEDIATE_START = NO
74
75[nat]
76RETURN_LOCAL_ADDRESSES = YES
77IMMEDIATE_START = NO
78
79[gns-helper-service-w32]
80START_ON_DEMAND = NO
81
82[consensus]
83START_ON_DEMAND = NO
84IMMEDIATE_START = NO
85
86[gns]
87START_ON_DEMAND = NO
88IMMEDIATE_START = NO
89
90[statistics]
91START_ON_DEMAND = NO
92IMMEDIATE_START = NO
93
94[peerinfo]
95NO_IO = YES
96
97[set]
98START_ON_DEMAND = NO
99IMMEDIATE_START = NO
100
101[revocation]
102START_ON_DEMAND = NO
103IMMEDIATE_START = NO
diff --git a/src/testbed/test_testbed_api_barriers.h b/src/testbed/test_testbed_api_barriers.h
deleted file mode 100644
index c0a34472d..000000000
--- a/src/testbed/test_testbed_api_barriers.h
+++ /dev/null
@@ -1,4 +0,0 @@
1/**
2 * The name to use for the barrier in the test cases
3 */
4#define TEST_BARRIER_NAME "test_barrier"
diff --git a/src/testbed/test_testbed_api_controllerlink.c b/src/testbed/test_testbed_api_controllerlink.c
deleted file mode 100644
index 0ec9d63e1..000000000
--- a/src/testbed/test_testbed_api_controllerlink.c
+++ /dev/null
@@ -1,881 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_controllerlink.c
23 * @brief testcase for testing controller to subcontroller linking
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27
28/**
29 * The controller architecture we try to achieve in this test case:
30 *
31 * Master Controller
32 * // \\
33 * // \\
34 * Slave Controller 1---------Slave Controller 3
35 * ||
36 * ||
37 * Slave Controller 2
38 */
39
40#include "platform.h"
41#include "gnunet_util_lib.h"
42#include "gnunet_testing_lib.h"
43#include "gnunet_testbed_service.h"
44
45/**
46 * Generic logging shortcut
47 */
48#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
49
50/**
51 * Debug logging shorthand
52 */
53#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
54
55/**
56 * Different stages in testing
57 */
58enum Stage
59{
60 /**
61 * Initial stage
62 */
63 INIT,
64
65 /**
66 * Master controller has started
67 */
68 MASTER_STARTED,
69
70 /**
71 * A peer has been created on master
72 */
73 MASTER_PEER_CREATE_SUCCESS,
74
75 /**
76 * Peer on master controller has been started successfully.
77 */
78 MASTER_PEER_START_SUCCESS,
79
80 /**
81 * The first slave has been registered at master controller
82 */
83 SLAVE1_REGISTERED,
84
85 /**
86 * The second slave has been registered at the master controller
87 */
88 SLAVE2_REGISTERED,
89
90 /**
91 * Link from master to slave 1 has been successfully created
92 */
93 SLAVE1_LINK_SUCCESS,
94
95 /**
96 * Peer create on slave 1 successful
97 */
98 SLAVE1_PEER_CREATE_SUCCESS,
99
100 /**
101 * Peer startup on slave 1 successful
102 */
103 SLAVE1_PEER_START_SUCCESS,
104
105 /**
106 * Link from slave 1 to slave 2 has been successfully created.
107 */
108 SLAVE2_LINK_SUCCESS,
109
110 /**
111 * Peer create on slave 2 successful
112 */
113 SLAVE2_PEER_CREATE_SUCCESS,
114
115 /**
116 * Peer on slave 1 successfully stopped
117 */
118 SLAVE1_PEER_STOP_SUCCESS,
119
120 /**
121 * Peer startup on slave 2 successful
122 */
123 SLAVE2_PEER_START_SUCCESS,
124
125 /**
126 * Try to connect peers on master and slave 2.
127 */
128 MASTER_SLAVE2_PEERS_CONNECTED,
129
130 /**
131 * Slave 3 has successfully registered
132 */
133 SLAVE3_REGISTERED,
134
135 /**
136 * Slave 3 has successfully started
137 */
138 SLAVE3_STARTED,
139
140 /**
141 * Peer created on slave 3
142 */
143 SLAVE3_PEER_CREATE_SUCCESS,
144
145 /**
146 * Peer started at slave 3
147 */
148 SLAVE3_PEER_START_SUCCESS,
149
150 /**
151 * Try to connect peers on slave2 and slave3
152 */
153 SLAVE2_SLAVE3_PEERS_CONNECTED,
154
155 /**
156 * Peer on slave 2 successfully stopped
157 */
158 SLAVE2_PEER_STOP_SUCCESS,
159
160 /**
161 * Peer destroy on slave 1 successful
162 */
163 SLAVE1_PEER_DESTROY_SUCCESS,
164
165 /**
166 * Peer destroy on slave 2 successful
167 */
168 SLAVE2_PEER_DESTROY_SUCCESS,
169
170 /**
171 * The configuration of slave 3 is acquired
172 */
173 SLAVE3_GET_CONFIG_SUCCESS,
174
175 /**
176 * Slave 1 has linked to slave 3;
177 */
178 SLAVE3_LINK_SUCCESS,
179
180 /**
181 * Master peer destroyed. Destroy slave 3 peer
182 */
183 MASTER_PEER_DESTROY_SUCCESS,
184
185 /**
186 * Slave 3 peer destroyed. Mark test as success
187 */
188 SUCCESS,
189
190 /**
191 * Marks test as skipped
192 */
193 SKIP
194};
195
196/**
197 * Host for running master controller
198 */
199static struct GNUNET_TESTBED_Host *host;
200
201/**
202 * The master controller process
203 */
204static struct GNUNET_TESTBED_ControllerProc *cp;
205
206/**
207 * Handle to master controller
208 */
209static struct GNUNET_TESTBED_Controller *mc;
210
211/**
212 * Slave host for running slave controller
213 */
214static struct GNUNET_TESTBED_Host *slave;
215
216/**
217 * Another slave host for running another slave controller
218 */
219static struct GNUNET_TESTBED_Host *slave2;
220
221/**
222 * Host for slave 3
223 */
224static struct GNUNET_TESTBED_Host *slave3;
225
226/**
227 * Slave host registration handle
228 */
229static struct GNUNET_TESTBED_HostRegistrationHandle *rh;
230
231/**
232 * Handle to global configuration
233 */
234static struct GNUNET_CONFIGURATION_Handle *cfg;
235
236/**
237 * Configuration of slave 3 controller
238 */
239static struct GNUNET_CONFIGURATION_Handle *cfg3;
240
241/**
242 * Abort task
243 */
244static struct GNUNET_SCHEDULER_Task *abort_task;
245
246/**
247 * Operation handle for linking controllers
248 */
249static struct GNUNET_TESTBED_Operation *op;
250
251/**
252 * Handle to peer started at slave 1
253 */
254static struct GNUNET_TESTBED_Peer *slave1_peer;
255
256/**
257 * Handle to peer started at slave 2
258 */
259static struct GNUNET_TESTBED_Peer *slave2_peer;
260
261/**
262 * Handle to peer started at slave 2
263 */
264static struct GNUNET_TESTBED_Peer *slave3_peer;
265
266/**
267 * Handle to a peer started at master controller
268 */
269static struct GNUNET_TESTBED_Peer *master_peer;
270
271/**
272 * The handle for whether a host is habitable or not
273 */
274static struct GNUNET_TESTBED_HostHabitableCheckHandle *hc_handle;
275
276/**
277 * The task handle for the delay task
278 */
279static struct GNUNET_SCHEDULER_Task *delay_task_id;
280
281/**
282 * Event mask
283 */
284static uint64_t event_mask;
285
286/**
287 * Global testing status
288 */
289static enum Stage result;
290
291/**
292 * shortcut to exit during failure
293 */
294#define FAIL_TEST(cond) \
295 do \
296 { \
297 if (! (cond)) \
298 { \
299 GNUNET_break (0); \
300 if (NULL != abort_task) \
301 GNUNET_SCHEDULER_cancel (abort_task); \
302 abort_task = NULL; \
303 GNUNET_SCHEDULER_shutdown (); \
304 return; \
305 } \
306 } while (0)
307
308
309/**
310 * Shutdown nicely
311 *
312 * @param cls NULL
313 */
314static void
315do_shutdown (void *cls)
316{
317 if (NULL != abort_task)
318 GNUNET_SCHEDULER_cancel (abort_task);
319 if (NULL != delay_task_id)
320 {
321 GNUNET_SCHEDULER_cancel (delay_task_id);
322 delay_task_id = NULL;
323 }
324 if (NULL != hc_handle)
325 GNUNET_TESTBED_is_host_habitable_cancel (hc_handle);
326 if (NULL != op)
327 {
328 GNUNET_TESTBED_operation_done (op);
329 op = NULL;
330 }
331 if (NULL != mc)
332 GNUNET_TESTBED_controller_disconnect (mc);
333 if (NULL != cp)
334 GNUNET_TESTBED_controller_stop (cp);
335 if (NULL != slave3)
336 GNUNET_TESTBED_host_destroy (slave3);
337 if (NULL != slave2)
338 GNUNET_TESTBED_host_destroy (slave2);
339 if (NULL != slave)
340 GNUNET_TESTBED_host_destroy (slave);
341 if (NULL != host)
342 GNUNET_TESTBED_host_destroy (host);
343 if (NULL != cfg)
344 GNUNET_CONFIGURATION_destroy (cfg);
345 if (NULL != cfg3)
346 GNUNET_CONFIGURATION_destroy (cfg3);
347 if (NULL != rh)
348 GNUNET_TESTBED_cancel_registration (rh);
349}
350
351
352/**
353 * abort task to run on test timed out
354 *
355 * @param cls NULL
356 */
357static void
358do_abort (void *cls)
359{
360 LOG (GNUNET_ERROR_TYPE_WARNING, "Aborting in stage %d\n", result);
361 abort_task = NULL;
362 GNUNET_SCHEDULER_shutdown ();
363}
364
365
366/**
367 * Calls abort now
368 *
369 * @param
370 * @return
371 */
372static void
373do_abort_now (void *cls)
374{
375 if (NULL != abort_task)
376 GNUNET_SCHEDULER_cancel (abort_task);
377 abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL);
378}
379
380
381/**
382 * Callback which will be called to after a host registration succeeded or failed
383 *
384 * @param cls the host which has been registered
385 * @param emsg the error message; NULL if host registration is successful
386 */
387static void
388registration_cont (void *cls, const char *emsg);
389
390
391/**
392 * Task for inserting delay between tests
393 *
394 * @param
395 * @return
396 */
397static void
398delay_task (void *cls)
399{
400 delay_task_id = NULL;
401 switch (result)
402 {
403 case SLAVE2_PEER_CREATE_SUCCESS:
404 op = GNUNET_TESTBED_peer_stop (NULL, slave1_peer, NULL, NULL);
405 FAIL_TEST (NULL != op);
406 break;
407
408 case MASTER_SLAVE2_PEERS_CONNECTED:
409 slave3 = GNUNET_TESTBED_host_create_with_id (3, "127.0.0.1", NULL, cfg, 0);
410 rh = GNUNET_TESTBED_register_host (mc, slave3, &registration_cont, NULL);
411 break;
412
413 case SLAVE2_SLAVE3_PEERS_CONNECTED:
414 op = GNUNET_TESTBED_peer_stop (NULL, slave2_peer, NULL, NULL);
415 FAIL_TEST (NULL != op);
416 break;
417
418 default:
419 FAIL_TEST (0);
420 }
421}
422
423
424/**
425 * Functions of this signature are called when a peer has been successfully
426 * created
427 *
428 * @param cls the closure from GNUNET_TESTBED_peer_create()
429 * @param peer the handle for the created peer; NULL on any error during
430 * creation
431 * @param emsg NULL if peer is not NULL; else MAY contain the error description
432 */
433static void
434peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
435{
436 FAIL_TEST (NULL != peer);
437 FAIL_TEST (NULL == emsg);
438 switch (result)
439 {
440 case MASTER_STARTED:
441 result = MASTER_PEER_CREATE_SUCCESS;
442 master_peer = peer;
443 GNUNET_TESTBED_operation_done (op);
444 op = GNUNET_TESTBED_peer_start (NULL, master_peer, NULL, NULL);
445 break;
446
447 case SLAVE1_LINK_SUCCESS:
448 result = SLAVE1_PEER_CREATE_SUCCESS;
449 slave1_peer = peer;
450 GNUNET_TESTBED_operation_done (op);
451 op = GNUNET_TESTBED_peer_start (NULL, slave1_peer, NULL, NULL);
452 break;
453
454 case SLAVE2_LINK_SUCCESS:
455 result = SLAVE2_PEER_CREATE_SUCCESS;
456 slave2_peer = peer;
457 GNUNET_TESTBED_operation_done (op);
458 op = NULL;
459 delay_task_id = GNUNET_SCHEDULER_add_delayed (
460 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
461 &delay_task,
462 NULL);
463 return;
464
465 case SLAVE3_STARTED:
466 result = SLAVE3_PEER_CREATE_SUCCESS;
467 slave3_peer = peer;
468 GNUNET_TESTBED_operation_done (op);
469 op = GNUNET_TESTBED_peer_start (NULL, slave3_peer, NULL, NULL);
470 break;
471
472 default:
473 FAIL_TEST (0);
474 }
475 FAIL_TEST (NULL != op);
476}
477
478
479/**
480 * Checks the event if it is an operation finished event and if indicates a
481 * successful completion of operation
482 *
483 * @param event the event information to check
484 */
485static void
486check_operation_success (const struct GNUNET_TESTBED_EventInformation *event)
487{
488 FAIL_TEST (NULL != event);
489 FAIL_TEST (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
490 FAIL_TEST (event->op == op);
491 FAIL_TEST (NULL == event->op_cls);
492 FAIL_TEST (NULL == event->details.operation_finished.emsg);
493 FAIL_TEST (NULL == event->details.operation_finished.generic);
494}
495
496
497/**
498 * Signature of the event handler function called by the
499 * respective event controller.
500 *
501 * @param cls closure
502 * @param event information about the event
503 */
504static void
505controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
506{
507 switch (result)
508 {
509 case SLAVE2_REGISTERED:
510 check_operation_success (event);
511 GNUNET_TESTBED_operation_done (op);
512 op = NULL;
513 result = SLAVE1_LINK_SUCCESS;
514 FAIL_TEST (NULL != slave2);
515 FAIL_TEST (NULL != slave);
516 op = GNUNET_TESTBED_peer_create (mc, slave, cfg, peer_create_cb, NULL);
517 FAIL_TEST (NULL != op);
518 break;
519
520 case SLAVE1_PEER_START_SUCCESS:
521 check_operation_success (event);
522 GNUNET_TESTBED_operation_done (op);
523 result = SLAVE2_LINK_SUCCESS;
524 op = GNUNET_TESTBED_peer_create (mc, slave2, cfg, peer_create_cb, NULL);
525 FAIL_TEST (NULL != op);
526 break;
527
528 case MASTER_PEER_CREATE_SUCCESS:
529 FAIL_TEST (GNUNET_TESTBED_ET_PEER_START == event->type);
530 FAIL_TEST (event->details.peer_start.host == host);
531 FAIL_TEST (event->details.peer_start.peer == master_peer);
532 GNUNET_TESTBED_operation_done (op);
533 op = NULL;
534 result = MASTER_PEER_START_SUCCESS;
535 slave = GNUNET_TESTBED_host_create_with_id (1, "127.0.0.1", NULL, cfg, 0);
536 FAIL_TEST (NULL != slave);
537 rh = GNUNET_TESTBED_register_host (mc, slave, &registration_cont, NULL);
538 FAIL_TEST (NULL != rh);
539 break;
540
541 case SLAVE1_PEER_CREATE_SUCCESS:
542 FAIL_TEST (GNUNET_TESTBED_ET_PEER_START == event->type);
543 FAIL_TEST (event->details.peer_start.host == slave);
544 FAIL_TEST (event->details.peer_start.peer == slave1_peer);
545 GNUNET_TESTBED_operation_done (op);
546 result = SLAVE1_PEER_START_SUCCESS;
547 op = GNUNET_TESTBED_controller_link (NULL, mc, slave2, slave, GNUNET_YES);
548 break;
549
550 case SLAVE2_PEER_CREATE_SUCCESS:
551 FAIL_TEST (GNUNET_TESTBED_ET_PEER_STOP == event->type);
552 FAIL_TEST (event->details.peer_stop.peer == slave1_peer);
553 GNUNET_TESTBED_operation_done (op);
554 result = SLAVE1_PEER_STOP_SUCCESS;
555 op = GNUNET_TESTBED_peer_start (NULL, slave2_peer, NULL, NULL);
556 FAIL_TEST (NULL != op);
557 break;
558
559 case SLAVE3_PEER_CREATE_SUCCESS:
560 FAIL_TEST (GNUNET_TESTBED_ET_PEER_START == event->type);
561 FAIL_TEST (event->details.peer_start.host == slave3);
562 FAIL_TEST (event->details.peer_start.peer == slave3_peer);
563 GNUNET_TESTBED_operation_done (op);
564 result = SLAVE3_PEER_START_SUCCESS;
565 sleep (1);
566 LOG_DEBUG ("**************************************\n");
567 op =
568 GNUNET_TESTBED_overlay_connect (mc, NULL, NULL, slave2_peer, slave3_peer);
569 FAIL_TEST (NULL != op);
570 break;
571
572 case SLAVE3_PEER_START_SUCCESS:
573 FAIL_TEST (NULL != event);
574 FAIL_TEST (GNUNET_TESTBED_ET_CONNECT == event->type);
575 FAIL_TEST (event->details.peer_connect.peer1 == slave2_peer);
576 FAIL_TEST (event->details.peer_connect.peer2 == slave3_peer);
577 result = SLAVE2_SLAVE3_PEERS_CONNECTED;
578 GNUNET_TESTBED_operation_done (op);
579 op = NULL;
580 delay_task_id = GNUNET_SCHEDULER_add_delayed (
581 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
582 &delay_task,
583 NULL);
584 break;
585
586 case SLAVE1_PEER_STOP_SUCCESS:
587 FAIL_TEST (GNUNET_TESTBED_ET_PEER_START == event->type);
588 FAIL_TEST (event->details.peer_start.host == slave2);
589 FAIL_TEST (event->details.peer_start.peer == slave2_peer);
590 GNUNET_TESTBED_operation_done (op);
591 result = SLAVE2_PEER_START_SUCCESS;
592 op =
593 GNUNET_TESTBED_overlay_connect (mc, NULL, NULL, master_peer, slave2_peer);
594 break;
595
596 case SLAVE2_PEER_START_SUCCESS:
597 FAIL_TEST (NULL != event);
598 FAIL_TEST (GNUNET_TESTBED_ET_CONNECT == event->type);
599 FAIL_TEST (event->details.peer_connect.peer1 == master_peer);
600 FAIL_TEST (event->details.peer_connect.peer2 == slave2_peer);
601 result = MASTER_SLAVE2_PEERS_CONNECTED;
602 GNUNET_TESTBED_operation_done (op);
603 op = NULL;
604 delay_task_id = GNUNET_SCHEDULER_add_delayed (
605 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
606 &delay_task,
607 NULL);
608 break;
609
610 case SLAVE2_SLAVE3_PEERS_CONNECTED:
611 FAIL_TEST (GNUNET_TESTBED_ET_PEER_STOP == event->type);
612 FAIL_TEST (event->details.peer_stop.peer == slave2_peer);
613 GNUNET_TESTBED_operation_done (op);
614 result = SLAVE2_PEER_STOP_SUCCESS;
615 op = GNUNET_TESTBED_peer_destroy (slave1_peer);
616 FAIL_TEST (NULL != op);
617 break;
618
619 case SLAVE2_PEER_STOP_SUCCESS:
620 check_operation_success (event);
621 GNUNET_TESTBED_operation_done (op);
622 result = SLAVE1_PEER_DESTROY_SUCCESS;
623 op = GNUNET_TESTBED_peer_destroy (slave2_peer);
624 FAIL_TEST (NULL != op);
625 break;
626
627 case SLAVE1_PEER_DESTROY_SUCCESS:
628 check_operation_success (event);
629 GNUNET_TESTBED_operation_done (op);
630 op = NULL;
631 result = SLAVE2_PEER_DESTROY_SUCCESS;
632 op = GNUNET_TESTBED_get_slave_config (NULL, mc, slave3);
633 FAIL_TEST (NULL != op);
634 break;
635
636 case SLAVE2_PEER_DESTROY_SUCCESS:
637 FAIL_TEST (NULL != event);
638 FAIL_TEST (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
639 FAIL_TEST (event->op == op);
640 FAIL_TEST (NULL == event->op_cls);
641 FAIL_TEST (NULL == event->details.operation_finished.emsg);
642 cfg3 = GNUNET_CONFIGURATION_dup (event->details.operation_finished.generic);
643 GNUNET_TESTBED_operation_done (op);
644 result = SLAVE3_GET_CONFIG_SUCCESS;
645 op = GNUNET_TESTBED_controller_link (NULL, mc, slave3, slave, GNUNET_NO);
646 break;
647
648 case SLAVE3_REGISTERED:
649 check_operation_success (event);
650 GNUNET_TESTBED_operation_done (op);
651 result = SLAVE3_STARTED;
652 op = GNUNET_TESTBED_peer_create (mc, slave3, cfg, peer_create_cb, NULL);
653 FAIL_TEST (NULL != op);
654 break;
655
656 case SLAVE3_GET_CONFIG_SUCCESS:
657 result = SLAVE3_LINK_SUCCESS;
658 GNUNET_TESTBED_operation_done (op);
659 op = GNUNET_TESTBED_peer_destroy (master_peer);
660 break;
661
662 case SLAVE3_LINK_SUCCESS:
663 check_operation_success (event);
664 result = MASTER_PEER_DESTROY_SUCCESS;
665 GNUNET_TESTBED_operation_done (op);
666 op = GNUNET_TESTBED_peer_destroy (slave3_peer);
667 break;
668
669 case MASTER_PEER_DESTROY_SUCCESS:
670 result = SUCCESS;
671 GNUNET_TESTBED_operation_done (op);
672 op = NULL;
673 GNUNET_SCHEDULER_shutdown ();
674 break;
675
676 default:
677 FAIL_TEST (0);
678 }
679}
680
681
682/**
683 * Callback which will be called to after a host registration succeeded or failed
684 *
685 * @param cls the host which has been registered
686 * @param emsg the error message; NULL if host registration is successful
687 */
688static void
689registration_cont (void *cls, const char *emsg)
690{
691 rh = NULL;
692 switch (result)
693 {
694 case MASTER_PEER_START_SUCCESS:
695 FAIL_TEST (NULL == emsg);
696 FAIL_TEST (NULL != mc);
697 result = SLAVE1_REGISTERED;
698 slave2 = GNUNET_TESTBED_host_create_with_id (2, "127.0.0.1", NULL, cfg, 0);
699 FAIL_TEST (NULL != slave2);
700 rh = GNUNET_TESTBED_register_host (mc, slave2, &registration_cont, NULL);
701 FAIL_TEST (NULL != rh);
702 break;
703
704 case SLAVE1_REGISTERED:
705 FAIL_TEST (NULL == emsg);
706 FAIL_TEST (NULL != mc);
707 result = SLAVE2_REGISTERED;
708 FAIL_TEST (NULL != cfg);
709 op = GNUNET_TESTBED_controller_link (NULL, mc, slave, NULL, GNUNET_YES);
710 FAIL_TEST (NULL != op);
711 break;
712
713 case MASTER_SLAVE2_PEERS_CONNECTED:
714 FAIL_TEST (NULL == emsg);
715 FAIL_TEST (NULL != mc);
716 FAIL_TEST (NULL == op);
717 result = SLAVE3_REGISTERED;
718 op = GNUNET_TESTBED_controller_link (NULL, mc, slave3, NULL, GNUNET_YES);
719 FAIL_TEST (NULL != op);
720 break;
721
722 default:
723 GNUNET_break (0);
724 do_abort_now (NULL);
725 }
726}
727
728
729/**
730 * Callback to signal successful startup of the controller process
731 *
732 * @param cls the closure from GNUNET_TESTBED_controller_start()
733 * @param cfg the configuration with which the controller has been started;
734 * NULL if status is not GNUNET_OK
735 * @param status GNUNET_OK if the startup is successful; GNUNET_SYSERR if not,
736 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
737 */
738static void
739status_cb (void *cls,
740 const struct GNUNET_CONFIGURATION_Handle *config,
741 int status)
742{
743 switch (result)
744 {
745 case INIT:
746 FAIL_TEST (GNUNET_OK == status);
747 event_mask = 0;
748 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_START);
749 event_mask |= (1L << GNUNET_TESTBED_ET_PEER_STOP);
750 event_mask |= (1L << GNUNET_TESTBED_ET_CONNECT);
751 event_mask |= (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED);
752 mc = GNUNET_TESTBED_controller_connect (host,
753 event_mask,
754 &controller_cb,
755 NULL);
756 FAIL_TEST (NULL != mc);
757 result = MASTER_STARTED;
758 op = GNUNET_TESTBED_peer_create (mc, host, cfg, peer_create_cb, NULL);
759 FAIL_TEST (NULL != op);
760 break;
761
762 default:
763 GNUNET_break (0);
764 cp = NULL;
765 do_abort_now (NULL);
766 }
767}
768
769
770/**
771 * Callbacks of this type are called by #GNUNET_TESTBED_is_host_habitable to
772 * inform whether the given host is habitable or not. The Handle returned by
773 * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
774 *
775 * @param cls NULL
776 * @param host the host whose status is being reported; will be NULL if the host
777 * given to GNUNET_TESTBED_is_host_habitable() is NULL
778 * @param status #GNUNET_YES if it is habitable; #GNUNET_NO if not
779 */
780static void
781host_habitable_cb (void *cls,
782 const struct GNUNET_TESTBED_Host *_host,
783 int status)
784{
785 hc_handle = NULL;
786 if (GNUNET_NO == status)
787 {
788 (void) printf ("%s",
789 "Unable to run the test as this system is not configured "
790 "to use password less SSH logins to localhost.\n"
791 "Skipping test\n");
792 GNUNET_SCHEDULER_cancel (abort_task);
793 abort_task = NULL;
794 GNUNET_SCHEDULER_shutdown ();
795 result = SKIP;
796 return;
797 }
798 cp = GNUNET_TESTBED_controller_start ("127.0.0.1", host, status_cb, NULL);
799}
800
801
802/**
803 * Main run function.
804 *
805 * @param cls NULL
806 * @param args arguments passed to #GNUNET_PROGRAM_run()
807 * @param cfgfile the path to configuration file
808 * @param cfg the configuration file handle
809 */
810static void
811run (void *cls,
812 char *const *args,
813 const char *cfgfile,
814 const struct GNUNET_CONFIGURATION_Handle *config)
815{
816 cfg = GNUNET_CONFIGURATION_dup (config);
817 host = GNUNET_TESTBED_host_create (NULL, NULL, cfg, 0);
818 FAIL_TEST (NULL != host);
819 if (NULL == (hc_handle = GNUNET_TESTBED_is_host_habitable (host,
820 config,
821 &host_habitable_cb,
822 NULL)))
823 {
824 GNUNET_TESTBED_host_destroy (host);
825 GNUNET_CONFIGURATION_destroy (cfg);
826 cfg = NULL;
827 host = NULL;
828 (void) printf ("%s",
829 "Unable to run the test as this system is not configured "
830 "to use password less SSH logins to localhost.\n"
831 "Marking test as successful\n");
832 result = SKIP;
833 return;
834 }
835 abort_task = GNUNET_SCHEDULER_add_delayed (
836 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5),
837 &do_abort,
838 NULL);
839 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
840}
841
842
843/**
844 * Main function
845 */
846int
847main (int argc, char **argv)
848{
849 char *const argv2[] = { "test_testbed_api_controllerlink",
850 "-c",
851 "test_testbed_api.conf",
852 NULL };
853 struct GNUNET_GETOPT_CommandLineOption options[] =
854 { GNUNET_GETOPT_OPTION_END };
855 int ret;
856
857 result = INIT;
858 ret = GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1,
859 argv2,
860 "test_testbed_api_controllerlink",
861 "nohelp",
862 options,
863 &run,
864 NULL);
865 if (GNUNET_OK != ret)
866 return 1;
867 switch (result)
868 {
869 case SUCCESS:
870 return 0;
871
872 case SKIP:
873 return 77; /* Mark test as skipped */
874
875 default:
876 return 1;
877 }
878}
879
880
881/* end of test_testbed_api_controllerlink.c */
diff --git a/src/testbed/test_testbed_api_hosts.c b/src/testbed/test_testbed_api_hosts.c
deleted file mode 100644
index 9e49debf7..000000000
--- a/src/testbed/test_testbed_api_hosts.c
+++ /dev/null
@@ -1,183 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_hosts.c
23 * @brief tests cases for testbed_api_hosts.c
24 * @author Sree Harsha Totakura
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30#include "testbed_api_hosts.h"
31
32
33#define TIME_REL_SECS(sec) \
34 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
35
36/**
37 * configuration handle to use as template configuration while creating hosts
38 */
39static struct GNUNET_CONFIGURATION_Handle *cfg;
40
41/**
42 * Host we are creating and using
43 */
44static struct GNUNET_TESTBED_Host *host;
45
46/**
47 * An array of hosts which are loaded from a file
48 */
49static struct GNUNET_TESTBED_Host **hosts;
50
51/**
52 * Number of hosts in the above list
53 */
54static unsigned int num_hosts;
55
56/**
57 * Global test status
58 */
59static int status;
60
61
62/**
63 * The shutdown task
64 *
65 * @param cls NULL
66 */
67static void
68do_shutdown (void *cls)
69{
70 GNUNET_TESTBED_host_destroy (host);
71 while (0 != num_hosts)
72 {
73 GNUNET_TESTBED_host_destroy (hosts[num_hosts - 1]);
74 num_hosts--;
75 }
76 GNUNET_free (hosts);
77 if (NULL != cfg)
78 {
79 GNUNET_CONFIGURATION_destroy (cfg);
80 cfg = NULL;
81 }
82}
83
84
85/**
86 * Main run function.
87 *
88 * @param cls NULL
89 * @param args arguments passed to GNUNET_PROGRAM_run
90 * @param cfgfile the path to configuration file
91 * @param cfg the configuration file handle
92 */
93static void
94run (void *cls, char *const *args, const char *cfgfile,
95 const struct GNUNET_CONFIGURATION_Handle *config)
96{
97 unsigned int cnt;
98
99 cfg = GNUNET_CONFIGURATION_dup (config);
100 host = GNUNET_TESTBED_host_create ("localhost", NULL, cfg, 0);
101 GNUNET_assert (NULL != host);
102 GNUNET_assert (0 != GNUNET_TESTBED_host_get_id_ (host));
103 GNUNET_TESTBED_host_destroy (host);
104 host = GNUNET_TESTBED_host_create (NULL, NULL, cfg, 0);
105 GNUNET_assert (NULL != host);
106 GNUNET_assert (0 == GNUNET_TESTBED_host_get_id_ (host));
107 GNUNET_assert (host == GNUNET_TESTBED_host_lookup_by_id_ (0));
108 hosts = NULL;
109 num_hosts = GNUNET_TESTBED_hosts_load_from_file ("sample_hosts.txt", cfg,
110 &hosts);
111 GNUNET_assert (7 == num_hosts);
112 GNUNET_assert (NULL != hosts);
113 for (cnt = 0; cnt < num_hosts; cnt++)
114 {
115 if (cnt < 3)
116 {
117 GNUNET_assert (0 == strcmp ("totakura",
118 GNUNET_TESTBED_host_get_username_
119 (hosts[cnt])));
120 GNUNET_assert (NULL != GNUNET_TESTBED_host_get_hostname (hosts[cnt]));
121 GNUNET_assert (22 == GNUNET_TESTBED_host_get_ssh_port_ (hosts[cnt]));
122 }
123 if (3 == cnt)
124 {
125 GNUNET_assert (0 == strcmp ("totakura",
126 GNUNET_TESTBED_host_get_username_
127 (hosts[cnt])));
128 GNUNET_assert (NULL != GNUNET_TESTBED_host_get_hostname (hosts[cnt]));
129 GNUNET_assert (2022 == GNUNET_TESTBED_host_get_ssh_port_ (hosts[cnt]));
130 }
131 if (4 == cnt)
132 {
133 GNUNET_assert (0 == strcmp ("totakura",
134 GNUNET_TESTBED_host_get_username_
135 (hosts[cnt])));
136 GNUNET_assert (0 == strcmp ("asgard.realm",
137 GNUNET_TESTBED_host_get_hostname
138 (hosts[cnt])));
139 GNUNET_assert (22 == GNUNET_TESTBED_host_get_ssh_port_ (hosts[cnt]));
140 }
141 if (5 == cnt)
142 {
143 GNUNET_assert (NULL == GNUNET_TESTBED_host_get_username_ (hosts[cnt]));
144 GNUNET_assert (0 == strcmp ("rivendal",
145 GNUNET_TESTBED_host_get_hostname
146 (hosts[cnt])));
147 GNUNET_assert (22 == GNUNET_TESTBED_host_get_ssh_port_ (hosts[cnt]));
148 }
149 if (6 == cnt)
150 {
151 GNUNET_assert (NULL == GNUNET_TESTBED_host_get_username_ (hosts[cnt]));
152 GNUNET_assert (0 == strcmp ("rohan",
153 GNUNET_TESTBED_host_get_hostname
154 (hosts[cnt])));
155 GNUNET_assert (561 == GNUNET_TESTBED_host_get_ssh_port_ (hosts[cnt]));
156 }
157 }
158 status = GNUNET_YES;
159 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
160}
161
162
163int
164main (int argc, char **argv)
165{
166 char *const argv2[] = { "test_testbed_api_hosts",
167 "-c", "test_testbed_api.conf",
168 NULL };
169 struct GNUNET_GETOPT_CommandLineOption options[] = {
170 GNUNET_GETOPT_OPTION_END
171 };
172
173 status = GNUNET_SYSERR;
174 if (GNUNET_OK !=
175 GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1, argv2,
176 "test_testbed_api_hosts", "nohelp", options, &run,
177 NULL))
178 return 1;
179 return (GNUNET_OK == status) ? 0 : 1;
180}
181
182
183/* end of test_testbed_api_hosts.c */
diff --git a/src/testbed/test_testbed_api_operations.c b/src/testbed/test_testbed_api_operations.c
deleted file mode 100644
index 133aadf21..000000000
--- a/src/testbed/test_testbed_api_operations.c
+++ /dev/null
@@ -1,568 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_operations.c
23 * @brief tests cases for testbed_api_operations.c
24 * @author Sree Harsha Totakura
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "testbed_api_operations.h"
30
31/**
32 * Generic logging shortcut
33 */
34#define LOG(kind, ...) \
35 GNUNET_log (kind, __VA_ARGS__)
36
37/**
38 * Delay to start step task
39 */
40#define STEP_DELAY \
41 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
42
43/**
44 * Queue A. Initially the max active is set to 2 and then reduced to 0 - this
45 * should block op2 even after op1 has finished. Later the max active is set to
46 * 2 and this should start op2
47 */
48struct OperationQueue *q1;
49
50/**
51 * Queue B. Max active set to 2 is not changed throughout the test
52 */
53struct OperationQueue *q2;
54
55/**
56 * This operation should go into both queues and block op2 until it is done
57 */
58struct GNUNET_TESTBED_Operation *op1;
59
60/**
61 * This operation should go into q1 and q2
62 */
63struct GNUNET_TESTBED_Operation *op2;
64
65/**
66 * This operation should go into both queues and should consume 2 units of
67 * resources on both queues. Since op2 needs a resource from both queues and is
68 * queues before this operation, it will be blocked until op2 is released even
69 * though q1 has enough free resources
70 */
71struct GNUNET_TESTBED_Operation *op3;
72
73/**
74 * Just like op3, this operation also consumes 2 units of resources on both
75 * queues. Since this is queued after op3 and both queues are at max active
76 * 2. This will be blocked until op3 is done.
77 */
78struct GNUNET_TESTBED_Operation *op4;
79
80/**
81 * This operation is started after op4 is released and should consume only 1
82 * resource on queue q1. It should be started along with op6 and op7
83 */
84struct GNUNET_TESTBED_Operation *op5;
85
86/**
87 * This operation is started after op4 is released and should consume only 1
88 * resource on q2. It should be started along with op5 and op7
89 */
90struct GNUNET_TESTBED_Operation *op6;
91
92/**
93 * This operation is started after op4 is released and should consume 1 resource
94 * on both queues q1 and q1. It should be started along with op5 and op6. It is
95 * then inactivated when op6 is released. op8's start should release this
96 * operation implicitly.
97 */
98struct GNUNET_TESTBED_Operation *op7;
99
100/**
101 * This operation is started after op6 is finished in step task. It consumes 2
102 * resources on both queues q1 and q2. This operation should evict op7. After
103 * starting, it should be made inactive, active and inactive again in the step task.
104 */
105struct GNUNET_TESTBED_Operation *op8;
106
107/**
108 * This operation is started after activating op8. It should consume a resource
109 * on queues q1 and q2. It should not be started until op8 is again made
110 * inactive at which point it should be released. It can be released as soon as
111 * it begins.
112 */
113struct GNUNET_TESTBED_Operation *op9;
114
115/**
116 * The delay task identifier
117 */
118struct GNUNET_SCHEDULER_Task *step_task;
119
120
121/**
122 * Enumeration of test stages
123 */
124enum Test
125{
126 /**
127 * Initial stage
128 */
129 TEST_INIT,
130
131 /**
132 * op1 has been started
133 */
134 TEST_OP1_STARTED,
135
136 /**
137 * op1 has been released
138 */
139 TEST_OP1_RELEASED,
140
141 /**
142 * Temporary pause where no operations should start as we set max active in q1
143 * to 0 in stage TEST_OP1_STARTED
144 */
145 TEST_PAUSE,
146
147 /**
148 * op2 has started
149 */
150 TEST_OP2_STARTED,
151
152 /**
153 * op2 released
154 */
155 TEST_OP2_RELEASED,
156
157 /**
158 * op3 has started
159 */
160 TEST_OP3_STARTED,
161
162 /**
163 * op3 has finished
164 */
165 TEST_OP3_RELEASED,
166
167 /**
168 * op4 has started
169 */
170 TEST_OP4_STARTED,
171
172 /**
173 * op4 has released
174 */
175 TEST_OP4_RELEASED,
176
177 /**
178 * op5, op6, op7 started
179 */
180 TEST_OP5_6_7_STARTED,
181
182 /**
183 * op5 has released
184 */
185 TEST_OP5_RELEASED,
186
187 /**
188 * op6 has released
189 */
190 TEST_OP6_RELEASED,
191
192 /**
193 * op8 has began waiting
194 */
195 TEST_OP8_WAITING,
196
197 /**
198 * op7 has released
199 */
200 TEST_OP7_RELEASED,
201
202 /**
203 * op8 has started
204 */
205 TEST_OP8_STARTED,
206
207 /**
208 * op8 is inactive
209 */
210 TEST_OP8_INACTIVE_1,
211
212 /**
213 * op8 is active
214 */
215 TEST_OP8_ACTIVE,
216
217 /**
218 * op8 has been released
219 */
220 TEST_OP8_RELEASED,
221
222 /**
223 * op9 has started
224 */
225 TEST_OP9_STARTED,
226
227 /**
228 * op9 has been released
229 */
230 TEST_OP9_RELEASED
231};
232
233/**
234 * The test result
235 */
236enum Test result;
237
238
239/**
240 * Function to call to start an operation once all
241 * queues the operation is part of declare that the
242 * operation can be activated.
243 */
244static void
245start_cb (void *cls);
246
247
248/**
249 * Function to cancel an operation (release all associated resources). This can
250 * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
251 * operation generated an event) or AFTER the operation generated an event due
252 * to a call to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that
253 * a callback to the 'OperationStart' precedes the call to 'OperationRelease'.
254 * Implementations of this function are expected to clean up whatever state is
255 * in 'cls' and release all resources associated with the operation.
256 */
257static void
258release_cb (void *cls);
259
260
261/**
262 * Task to simulate artificial delay and change the test stage
263 *
264 * @param cls NULL
265 */
266static void
267step (void *cls)
268{
269 GNUNET_assert (NULL != step_task);
270 step_task = NULL;
271 switch (result)
272 {
273 case TEST_OP1_STARTED:
274 GNUNET_TESTBED_operation_release_ (op1);
275 GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 0);
276 op3 = GNUNET_TESTBED_operation_create_ (&op3, &start_cb, &release_cb);
277 GNUNET_TESTBED_operation_queue_insert2_ (q1, op3, 2);
278 GNUNET_TESTBED_operation_queue_insert2_ (q2, op3, 2);
279 GNUNET_TESTBED_operation_begin_wait_ (op3);
280 op4 = GNUNET_TESTBED_operation_create_ (&op4, &start_cb, &release_cb);
281 GNUNET_TESTBED_operation_queue_insert2_ (q1, op4, 2);
282 GNUNET_TESTBED_operation_queue_insert2_ (q2, op4, 2);
283 GNUNET_TESTBED_operation_begin_wait_ (op4);
284 break;
285
286 case TEST_OP1_RELEASED:
287 result = TEST_PAUSE;
288 GNUNET_TESTBED_operation_queue_reset_max_active_ (q1, 2);
289 break;
290
291 case TEST_OP2_STARTED:
292 GNUNET_TESTBED_operation_release_ (op2);
293 break;
294
295 case TEST_OP3_STARTED:
296 GNUNET_TESTBED_operation_release_ (op3);
297 break;
298
299 case TEST_OP4_STARTED:
300 GNUNET_TESTBED_operation_release_ (op4);
301 break;
302
303 case TEST_OP6_RELEASED:
304 op8 = GNUNET_TESTBED_operation_create_ (&op8, &start_cb, &release_cb);
305 GNUNET_TESTBED_operation_queue_insert2_ (q1, op8, 2);
306 GNUNET_TESTBED_operation_queue_insert2_ (q2, op8, 2);
307 result = TEST_OP8_WAITING;
308 GNUNET_TESTBED_operation_begin_wait_ (op8);
309 break;
310
311 case TEST_OP8_STARTED:
312 GNUNET_TESTBED_operation_inactivate_ (op8);
313 result = TEST_OP8_INACTIVE_1;
314 step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
315 break;
316
317 case TEST_OP8_INACTIVE_1:
318 GNUNET_TESTBED_operation_activate_ (op8);
319 result = TEST_OP8_ACTIVE;
320 op9 = GNUNET_TESTBED_operation_create_ (&op9, &start_cb, &release_cb);
321 GNUNET_TESTBED_operation_queue_insert2_ (q1, op9, 1);
322 GNUNET_TESTBED_operation_queue_insert2_ (q2, op9, 1);
323 GNUNET_TESTBED_operation_begin_wait_ (op9);
324 step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
325 break;
326
327 case TEST_OP8_ACTIVE:
328 GNUNET_TESTBED_operation_inactivate_ (op8);
329 /* op8 should be released by now due to above call */
330 GNUNET_assert (TEST_OP8_RELEASED == result);
331 break;
332
333 case TEST_OP9_STARTED:
334 GNUNET_TESTBED_operation_release_ (op9);
335 break;
336
337 default:
338 GNUNET_assert (0);
339 }
340}
341
342
343/**
344 * Function to call to start an operation once all
345 * queues the operation is part of declare that the
346 * operation can be activated.
347 */
348static void
349start_cb (void *cls)
350{
351 switch (result)
352 {
353 case TEST_INIT:
354 GNUNET_assert (&op1 == cls);
355 result = TEST_OP1_STARTED;
356 GNUNET_assert (NULL == step_task);
357 step_task =
358 GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
359 break;
360
361 case TEST_PAUSE:
362 GNUNET_assert (&op2 == cls);
363 result = TEST_OP2_STARTED;
364 GNUNET_assert (NULL == step_task);
365 step_task =
366 GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
367 break;
368
369 case TEST_OP2_RELEASED:
370 GNUNET_assert (&op3 == cls);
371 result = TEST_OP3_STARTED;
372 GNUNET_assert (NULL == step_task);
373 step_task =
374 GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
375 break;
376
377 case TEST_OP3_RELEASED:
378 GNUNET_assert (&op4 == cls);
379 result = TEST_OP4_STARTED;
380 GNUNET_assert (NULL == step_task);
381 step_task =
382 GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
383 break;
384
385 case TEST_OP4_RELEASED:
386 {
387 static int nops;
388
389 nops++;
390 if (nops == 3)
391 {
392 result = TEST_OP5_6_7_STARTED;
393 GNUNET_TESTBED_operation_release_ (op5);
394 op5 = NULL;
395 }
396 }
397 break;
398
399 case TEST_OP7_RELEASED:
400 GNUNET_assert (&op8 == cls);
401 result = TEST_OP8_STARTED;
402 step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
403 break;
404
405 case TEST_OP8_RELEASED:
406 GNUNET_assert (&op9 == cls);
407 result = TEST_OP9_STARTED;
408 step_task = GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
409 break;
410
411 default:
412 GNUNET_assert (0);
413 }
414}
415
416
417/**
418 * Function to cancel an operation (release all associated resources). This can
419 * be because of a call to "GNUNET_TESTBED_operation_cancel" (before the
420 * operation generated an event) or AFTER the operation generated an event due
421 * to a call to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that
422 * a callback to the 'OperationStart' precedes the call to 'OperationRelease'.
423 * Implementations of this function are expected to clean up whatever state is
424 * in 'cls' and release all resources associated with the operation.
425 */
426static void
427release_cb (void *cls)
428{
429 switch (result)
430 {
431 case TEST_OP1_STARTED:
432 GNUNET_assert (&op1 == cls);
433 result = TEST_OP1_RELEASED;
434 op1 = NULL;
435 step_task =
436 GNUNET_SCHEDULER_add_delayed (STEP_DELAY, &step, NULL);
437 break;
438
439 case TEST_OP2_STARTED:
440 GNUNET_assert (&op2 == cls);
441 result = TEST_OP2_RELEASED;
442 GNUNET_assert (NULL == step_task);
443 break;
444
445 case TEST_OP3_STARTED:
446 GNUNET_assert (&op3 == cls);
447 result = TEST_OP3_RELEASED;
448 GNUNET_assert (NULL == step_task);
449 break;
450
451 case TEST_OP4_STARTED:
452 GNUNET_assert (&op4 == cls);
453 result = TEST_OP4_RELEASED;
454 GNUNET_assert (NULL == step_task);
455 op5 = GNUNET_TESTBED_operation_create_ (&op5, &start_cb, &release_cb);
456 GNUNET_TESTBED_operation_queue_insert2_ (q1, op5, 1);
457 GNUNET_TESTBED_operation_begin_wait_ (op5);
458 op6 = GNUNET_TESTBED_operation_create_ (&op6, &start_cb, &release_cb);
459 GNUNET_TESTBED_operation_queue_insert2_ (q2, op6, 1);
460 GNUNET_TESTBED_operation_begin_wait_ (op6);
461 op7 = GNUNET_TESTBED_operation_create_ (&op7, &start_cb, &release_cb);
462 GNUNET_TESTBED_operation_queue_insert2_ (q1, op7, 1);
463 GNUNET_TESTBED_operation_queue_insert2_ (q2, op7, 1);
464 GNUNET_TESTBED_operation_begin_wait_ (op7);
465 break;
466
467 case TEST_OP5_6_7_STARTED:
468 result = TEST_OP5_RELEASED;
469 op5 = NULL;
470 GNUNET_TESTBED_operation_release_ (op6);
471 break;
472
473 case TEST_OP5_RELEASED:
474 op6 = NULL;
475 result = TEST_OP6_RELEASED;
476 GNUNET_TESTBED_operation_inactivate_ (op7);
477 step_task = GNUNET_SCHEDULER_add_now (&step, NULL);
478 break;
479
480 case TEST_OP8_WAITING:
481 GNUNET_assert (&op7 == cls);
482 op7 = NULL;
483 result = TEST_OP7_RELEASED;
484 break;
485
486 case TEST_OP8_ACTIVE:
487 result = TEST_OP8_RELEASED;
488 op8 = NULL;
489 break;
490
491 case TEST_OP9_STARTED:
492 GNUNET_assert (&op9 == cls);
493 result = TEST_OP9_RELEASED;
494 GNUNET_TESTBED_operation_queue_destroy_ (q1);
495 GNUNET_TESTBED_operation_queue_destroy_ (q2);
496 q1 = NULL;
497 q2 = NULL;
498 break;
499
500 default:
501 GNUNET_assert (0);
502 }
503}
504
505
506/**
507 * Main run function.
508 *
509 * @param cls NULL
510 * @param args arguments passed to GNUNET_PROGRAM_run
511 * @param cfgfile the path to configuration file
512 * @param cfg the configuration file handle
513 */
514static void
515run (void *cls, char *const *args, const char *cfgfile,
516 const struct GNUNET_CONFIGURATION_Handle *config)
517{
518 q1 = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED, 1);
519 GNUNET_assert (NULL != q1);
520 q2 = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED, 2);
521 GNUNET_assert (NULL != q2);
522 op1 = GNUNET_TESTBED_operation_create_ (&op1, start_cb, release_cb);
523 GNUNET_assert (NULL != op1);
524 op2 = GNUNET_TESTBED_operation_create_ (&op2, start_cb, release_cb);
525 GNUNET_TESTBED_operation_queue_insert_ (q1, op1);
526 GNUNET_TESTBED_operation_queue_insert_ (q2, op1);
527 GNUNET_TESTBED_operation_begin_wait_ (op1);
528 GNUNET_TESTBED_operation_queue_insert_ (q1, op2);
529 GNUNET_TESTBED_operation_queue_insert_ (q2, op2);
530 GNUNET_TESTBED_operation_begin_wait_ (op2);
531 result = TEST_INIT;
532}
533
534
535/**
536 * Main function
537 */
538int
539main (int argc, char **argv)
540{
541 int ret;
542 char *const argv2[] =
543 { "test_testbed_api_operations", "-c", "test_testbed_api.conf", NULL };
544 struct GNUNET_GETOPT_CommandLineOption options[] =
545 { GNUNET_GETOPT_OPTION_END };
546
547 ret =
548 GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1, argv2,
549 "test_testbed_api_operations", "nohelp", options,
550 &run, NULL);
551 if ((GNUNET_OK != ret) || (TEST_OP9_RELEASED != result))
552 return 1;
553 op1 = NULL;
554 op2 = NULL;
555 op3 = NULL;
556 op4 = NULL;
557 op5 = NULL;
558 op6 = NULL;
559 op7 = NULL;
560 op8 = NULL;
561 op9 = NULL;
562 q1 = NULL;
563 q2 = NULL;
564 return 0;
565}
566
567
568/* end of test_testbed_api_operations.c */
diff --git a/src/testbed/test_testbed_api_peer_reconfiguration.c b/src/testbed/test_testbed_api_peer_reconfiguration.c
deleted file mode 100644
index 22dd46b53..000000000
--- a/src/testbed/test_testbed_api_peer_reconfiguration.c
+++ /dev/null
@@ -1,194 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_peer_reconfiguration.c
23 * @brief testcase for testing GNUNET_TESTBED_peer_manage_service()
24 * implementation
25 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_testbed_service.h"
31
32/**
33 * Number of peers we want to start
34 */
35#define NUM_PEERS 1
36
37/**
38 * The array of peers; we get them from the testbed
39 */
40static struct GNUNET_TESTBED_Peer **peers;
41
42/**
43 * Operation handle
44 */
45static struct GNUNET_TESTBED_Operation *op;
46
47/**
48 * Abort task identifier
49 */
50static struct GNUNET_SCHEDULER_Task *abort_task;
51
52/**
53 * States in this test
54 */
55enum
56{
57 /**
58 * Test has just been initialized
59 */
60 STATE_INIT,
61
62 /**
63 * Peers have been started
64 */
65 STATE_PEER_STARTED,
66
67 /**
68 * Peer has been reconfigured. Test completed successfully
69 */
70 STATE_PEER_RECONFIGURED
71} state;
72
73/**
74 * Fail testcase
75 */
76#define FAIL_TEST(cond, ret) do { \
77 if (! (cond)) { \
78 GNUNET_break (0); \
79 if (NULL != abort_task) \
80 GNUNET_SCHEDULER_cancel (abort_task); \
81 abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); \
82 ret; \
83 } \
84} while (0)
85
86
87/**
88 * Abort task
89 *
90 * @param cls NULL
91 */
92static void
93do_abort (void *cls)
94{
95 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting\n");
96 abort_task = NULL;
97 if (NULL != op)
98 {
99 GNUNET_TESTBED_operation_done (op);
100 op = NULL;
101 }
102 GNUNET_SCHEDULER_shutdown ();
103}
104
105
106/**
107 * Signature of the event handler function called by the
108 * respective event controller.
109 *
110 * @param cls closure
111 * @param event information about the event
112 */
113static void
114controller_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
115{
116 if (STATE_PEER_STARTED != state)
117 return;
118 if (GNUNET_TESTBED_ET_OPERATION_FINISHED != event->type)
119 {
120 GNUNET_TESTBED_operation_done (op);
121 op = NULL;
122 FAIL_TEST (0, return );
123 }
124 if (NULL != event->details.operation_finished.emsg)
125 {
126 fprintf (stderr, "Operation failed: %s\n",
127 event->details.operation_finished.emsg);
128 GNUNET_TESTBED_operation_done (op);
129 op = NULL;
130 FAIL_TEST (0, return );
131 }
132 GNUNET_TESTBED_operation_done (op);
133 state = STATE_PEER_RECONFIGURED;
134 GNUNET_SCHEDULER_cancel (abort_task);
135 abort_task = NULL;
136 GNUNET_SCHEDULER_shutdown ();
137}
138
139
140/**
141 * Signature of a main function for a testcase.
142 *
143 * @param cls closure
144 * @param h the run handle
145 * @param num_peers number of peers in 'peers'
146 * @param peers_ handle to peers run in the testbed
147 * @param links_succeeded the number of overlay link connection attempts that
148 * succeeded
149 * @param links_failed the number of overlay link connection attempts that
150 * failed
151 */
152static void
153test_master (void *cls,
154 struct GNUNET_TESTBED_RunHandle *h,
155 unsigned int num_peers,
156 struct GNUNET_TESTBED_Peer **peers_,
157 unsigned int links_succeeded,
158 unsigned int links_failed)
159{
160 struct GNUNET_CONFIGURATION_Handle *cfg;
161
162 FAIL_TEST (NUM_PEERS == num_peers, return );
163 state = STATE_PEER_STARTED;
164 peers = peers_;
165 cfg = GNUNET_CONFIGURATION_create ();
166 FAIL_TEST (GNUNET_OK == GNUNET_CONFIGURATION_load
167 (cfg, "test_testbed_api_testbed_run_topologyrandom.conf"),
168 return );
169 op = GNUNET_TESTBED_peer_update_configuration (peers[0], cfg);
170 GNUNET_CONFIGURATION_destroy (cfg);
171 FAIL_TEST (NULL != op, return );
172 abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
173 (GNUNET_TIME_UNIT_SECONDS, 30),
174 &do_abort, NULL);
175}
176
177
178/**
179 * Main function
180 */
181int
182main (int argc, char **argv)
183{
184 state = STATE_INIT;
185 (void) GNUNET_TESTBED_test_run ("test_testbed_api_peer_reconfiguration",
186 "test_testbed_api.conf",
187 NUM_PEERS,
188 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED,
189 &controller_cb, NULL,
190 &test_master, NULL);
191 if (STATE_PEER_RECONFIGURED != state)
192 return 1;
193 return 0;
194}
diff --git a/src/testbed/test_testbed_api_peers_manage_services.c b/src/testbed/test_testbed_api_peers_manage_services.c
deleted file mode 100644
index 93b0da550..000000000
--- a/src/testbed/test_testbed_api_peers_manage_services.c
+++ /dev/null
@@ -1,216 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_peers_manage_services.c
23 * @brief testcase for testing GNUNET_TESTBED_peer_manage_service()
24 * implementation
25 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_testbed_service.h"
31
32/**
33 * Number of peers we want to start
34 */
35#define NUM_PEERS 2
36
37/**
38 * The array of peers; we get them from the testbed
39 */
40static struct GNUNET_TESTBED_Peer **peers;
41
42/**
43 * Operation handle
44 */
45static struct GNUNET_TESTBED_Operation *op;
46
47/**
48 * dummy pointer
49 */
50static void *dummy_cls = (void *) 0xDEAD0001;
51
52/**
53 * Abort task identifier
54 */
55static struct GNUNET_SCHEDULER_Task *abort_task;
56
57/**
58 * States in this test
59 */
60enum
61{
62 /**
63 * Test has just been initialized
64 */
65 STATE_INIT,
66
67 /**
68 * Peers have been started
69 */
70 STATE_PEERS_STARTED,
71
72 /**
73 * statistics service went down
74 */
75 STATE_SERVICE_DOWN,
76
77 /**
78 * statistics service went up
79 */
80 STATE_SERVICE_UP,
81
82 /**
83 * Testing completed successfully
84 */
85 STATE_OK
86} state;
87
88/**
89 * Fail testcase
90 */
91#define FAIL_TEST(cond, ret) do { \
92 if (! (cond)) { \
93 GNUNET_break (0); \
94 if (NULL != abort_task) \
95 GNUNET_SCHEDULER_cancel (abort_task); \
96 abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); \
97 ret; \
98 } \
99} while (0)
100
101
102/**
103 * Abort task
104 *
105 * @param cls NULL
106 */
107static void
108do_abort (void *cls)
109{
110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting\n");
111 abort_task = NULL;
112 if (NULL != op)
113 {
114 GNUNET_TESTBED_operation_done (op);
115 op = NULL;
116 }
117 GNUNET_SCHEDULER_shutdown ();
118}
119
120
121/**
122 * Callback to be called when an operation is completed
123 *
124 * @param cls the callback closure from functions generating an operation
125 * @param op the operation that has been finished
126 * @param emsg error message in case the operation has failed; will be NULL if
127 * operation has executed successfully.
128 */
129static void
130op_comp_cb (void *cls,
131 struct GNUNET_TESTBED_Operation *op,
132 const char *emsg)
133{
134 FAIL_TEST (cls == dummy_cls, return );
135 FAIL_TEST (NULL == emsg, return );
136 GNUNET_TESTBED_operation_done (op);
137 op = NULL;
138 switch (state)
139 {
140 case STATE_PEERS_STARTED:
141 state = STATE_SERVICE_DOWN;
142 op = GNUNET_TESTBED_peer_manage_service (dummy_cls,
143 peers[1],
144 "topology",
145 op_comp_cb,
146 dummy_cls,
147 0);
148 GNUNET_assert (NULL != op);
149 break;
150
151 case STATE_SERVICE_DOWN:
152 state = STATE_SERVICE_UP;
153 GNUNET_SCHEDULER_cancel (abort_task);
154 abort_task = NULL;
155 state = STATE_OK;
156 GNUNET_SCHEDULER_shutdown ();
157 break;
158
159 default:
160 FAIL_TEST (0, return );
161 }
162}
163
164
165/**
166 * Signature of a main function for a testcase.
167 *
168 * @param cls closure
169 * @param h the run handle
170 * @param num_peers number of peers in 'peers'
171 * @param peers_ handle to peers run in the testbed
172 * @param links_succeeded the number of overlay link connection attempts that
173 * succeeded
174 * @param links_failed the number of overlay link connection attempts that
175 * failed
176 */
177static void
178test_master (void *cls,
179 struct GNUNET_TESTBED_RunHandle *h,
180 unsigned int num_peers,
181 struct GNUNET_TESTBED_Peer **peers_,
182 unsigned int links_succeeded,
183 unsigned int links_failed)
184{
185 FAIL_TEST (NUM_PEERS == num_peers, return );
186 state = STATE_PEERS_STARTED;
187 peers = peers_;
188 op = GNUNET_TESTBED_peer_manage_service (dummy_cls,
189 peers[1],
190 "topology",
191 op_comp_cb,
192 dummy_cls,
193 1);
194 FAIL_TEST (NULL != op, return );
195 abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
196 (GNUNET_TIME_UNIT_MINUTES, 1),
197 &do_abort, NULL);
198}
199
200
201/**
202 * Main function
203 */
204int
205main (int argc, char **argv)
206{
207 state = STATE_INIT;
208 (void) GNUNET_TESTBED_test_run ("test_testbed_api_peers_manage_services",
209 "test_testbed_api.conf",
210 NUM_PEERS,
211 1LL, NULL, NULL,
212 &test_master, NULL);
213 if (STATE_OK != state)
214 return 1;
215 return 0;
216}
diff --git a/src/testbed/test_testbed_api_sd.c b/src/testbed/test_testbed_api_sd.c
deleted file mode 100644
index 816f8e9a6..000000000
--- a/src/testbed/test_testbed_api_sd.c
+++ /dev/null
@@ -1,111 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21
22/**
23 * @file testbed/testbed_api_sd.c
24 * @brief test cases for calculating standard deviation
25 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "testbed_api_sd.h"
31
32/**
33 * Global return value
34 */
35static int ret;
36
37/**
38 * Main run function.
39 *
40 * @param cls NULL
41 * @param args arguments passed to GNUNET_PROGRAM_run
42 * @param cfgfile the path to configuration file
43 * @param cfg the configuration file handle
44 */
45static void
46run (void *cls, char *const *args, const char *cfgfile,
47 const struct GNUNET_CONFIGURATION_Handle *config)
48{
49 struct SDHandle *h = GNUNET_TESTBED_SD_init_ (20);
50 int sd;
51
52 ret = 0;
53 GNUNET_TESTBED_SD_add_data_ (h, 40);
54 if (GNUNET_SYSERR != GNUNET_TESTBED_SD_deviation_factor_ (h, 10, &sd))
55 {
56 GNUNET_break (0);
57 ret = 1;
58 goto err;
59 }
60 GNUNET_TESTBED_SD_add_data_ (h, 30);
61 if (GNUNET_SYSERR == GNUNET_TESTBED_SD_deviation_factor_ (h, 80, &sd))
62 {
63 GNUNET_break (0);
64 ret = 1;
65 goto err;
66 }
67 GNUNET_TESTBED_SD_add_data_ (h, 40);
68 if ((GNUNET_SYSERR == GNUNET_TESTBED_SD_deviation_factor_ (h, 30, &sd))
69 || (-2 != sd))
70 {
71 GNUNET_break (0);
72 ret = 1;
73 goto err;
74 }
75 GNUNET_TESTBED_SD_add_data_ (h, 10);
76 GNUNET_TESTBED_SD_add_data_ (h, 30);
77 if ((GNUNET_SYSERR == GNUNET_TESTBED_SD_deviation_factor_ (h, 60, &sd))
78 || (3 != sd))
79 {
80 GNUNET_break (0);
81 ret = 1;
82 goto err;
83 }
84
85err:
86 GNUNET_TESTBED_SD_destroy_ (h);
87}
88
89
90/**
91 * Main function
92 */
93int
94main (int argc, char **argv)
95{
96 struct GNUNET_GETOPT_CommandLineOption options[] = {
97 GNUNET_GETOPT_OPTION_END
98 };
99 int result;
100
101 result = GNUNET_SYSERR;
102 result =
103 GNUNET_PROGRAM_run (argc, argv,
104 "test_testbed_api_sd", "nohelp", options, &run, NULL);
105 if ((GNUNET_OK != result))
106 return 1;
107 return ret;
108}
109
110
111/* end of test_testbed_api_sd.c */
diff --git a/src/testbed/test_testbed_api_statistics.c b/src/testbed/test_testbed_api_statistics.c
deleted file mode 100644
index 4d42cda6a..000000000
--- a/src/testbed/test_testbed_api_statistics.c
+++ /dev/null
@@ -1,205 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_statistics.c
23 * @brief testcase for testing GNUNET_TESTBED_get_statistics() implementation
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30
31/**
32 * Number of peers we want to start
33 */
34#define NUM_PEERS 5
35
36/**
37 * The array of peers; we get them from the testbed
38 */
39static struct GNUNET_TESTBED_Peer **peers;
40
41/**
42 * Operation handle
43 */
44static struct GNUNET_TESTBED_Operation *op;
45
46/**
47 * dummy pointer
48 */
49static void *dummy_cls = (void *) 0xDEAD0001;
50
51/**
52 * Abort task identifier
53 */
54static struct GNUNET_SCHEDULER_Task *abort_task;
55
56/**
57 * Global testing result
58 */
59static int result;
60
61/**
62 * The peers we have seen in the statistics iterator
63 */
64static struct GNUNET_TESTBED_Peer **seen_peers;
65
66/**
67 * Number of peers in the above array
68 */
69static unsigned int num_seen_peers;
70
71
72/**
73 * Fail testcase
74 */
75#define FAIL_TEST(cond, ret) do { \
76 if (! (cond)) { \
77 GNUNET_break (0); \
78 if (NULL != abort_task) \
79 GNUNET_SCHEDULER_cancel (abort_task); \
80 abort_task = GNUNET_SCHEDULER_add_now (&do_abort, NULL); \
81 ret; \
82 } \
83} while (0)
84
85
86/**
87 * Abort task
88 *
89 * @param cls NULL
90 */
91static void
92do_abort (void *cls)
93{
94 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test timed out -- Aborting\n");
95 abort_task = NULL;
96 if (NULL != op)
97 {
98 GNUNET_TESTBED_operation_done (op);
99 op = NULL;
100 }
101 result = GNUNET_SYSERR;
102}
103
104
105/**
106 * Callback function to process statistic values from all peers.
107 *
108 * @param cls closure
109 * @param peer the peer the statistic belong to
110 * @param subsystem name of subsystem that created the statistic
111 * @param name the name of the datum
112 * @param value the current value
113 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
114 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
115 */
116static int
117stats_iterator (void *cls,
118 const struct GNUNET_TESTBED_Peer *peer,
119 const char *subsystem, const char *name, uint64_t value,
120 int is_persistent)
121{
122 unsigned int cnt;
123
124 FAIL_TEST (cls == dummy_cls, return GNUNET_SYSERR);
125 for (cnt = 0; cnt < num_seen_peers; cnt++)
126 FAIL_TEST (peer != seen_peers[cnt], return GNUNET_SYSERR);
127 FAIL_TEST (NULL != subsystem, return GNUNET_SYSERR);
128 FAIL_TEST (NULL != name, return GNUNET_SYSERR);
129 GNUNET_array_append (seen_peers, num_seen_peers,
130 (struct GNUNET_TESTBED_Peer *) peer);
131 return GNUNET_SYSERR;
132}
133
134
135/**
136 * Callback to be called when an operation is completed
137 *
138 * @param cls the callback closure from functions generating an operation
139 * @param op the operation that has been finished
140 * @param emsg error message in case the operation has failed; will be NULL if
141 * operation has executed successfully.
142 */
143static void
144op_comp_cb (void *cls,
145 struct GNUNET_TESTBED_Operation *op,
146 const char *emsg)
147{
148 FAIL_TEST (cls == dummy_cls, return );
149 result = GNUNET_OK;
150 GNUNET_TESTBED_operation_done (op);
151 op = NULL;
152 GNUNET_SCHEDULER_cancel (abort_task);
153 GNUNET_SCHEDULER_shutdown ();
154}
155
156
157/**
158 * Signature of a main function for a testcase.
159 *
160 * @param cls closure
161 * @param h the run handle
162 * @param num_peers number of peers in 'peers'
163 * @param peers_ handle to peers run in the testbed
164 * @param links_succeeded the number of overlay link connection attempts that
165 * succeeded
166 * @param links_failed the number of overlay link connection attempts that
167 * failed
168 */
169static void
170test_master (void *cls,
171 struct GNUNET_TESTBED_RunHandle *h,
172 unsigned int num_peers,
173 struct GNUNET_TESTBED_Peer **peers_,
174 unsigned int links_succeeded,
175 unsigned int links_failed)
176{
177 FAIL_TEST (NUM_PEERS == num_peers, return );
178 peers = peers_;
179 op = GNUNET_TESTBED_get_statistics (num_peers, peers,
180 NULL, NULL,
181 &stats_iterator,
182 &op_comp_cb,
183 dummy_cls);
184 abort_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
185 (GNUNET_TIME_UNIT_MINUTES, 1),
186 &do_abort, NULL);
187}
188
189
190/**
191 * Main function
192 */
193int
194main (int argc, char **argv)
195{
196 (void) GNUNET_TESTBED_test_run ("test_testbed_api_statistics",
197 "test_testbed_api_statistics.conf",
198 NUM_PEERS,
199 1LL, NULL, NULL,
200 &test_master, NULL);
201 GNUNET_free (seen_peers);
202 if (GNUNET_OK != result)
203 return 1;
204 return 0;
205}
diff --git a/src/testbed/test_testbed_api_statistics.conf b/src/testbed/test_testbed_api_statistics.conf
deleted file mode 100644
index edb2e2057..000000000
--- a/src/testbed/test_testbed_api_statistics.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = 2D_TORUS
5MAX_PARALLEL_SERVICE_CONNECTIONS = 2
6
7[statistics]
8START_ON_DEMAND = YES
9PORT = 59530
diff --git a/src/testbed/test_testbed_api_template.conf b/src/testbed/test_testbed_api_template.conf
deleted file mode 100644
index ae0368a8b..000000000
--- a/src/testbed/test_testbed_api_template.conf
+++ /dev/null
@@ -1,49 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[testbed]
5START_ON_DEMAND = NO
6PORT = 12113
7ACCEPT_FROM = 127.0.0.1;
8HOSTNAME = localhost
9OVERLAY_TOPOLOGY = NONE
10#PREFIX = xterm -geometry 100x85 -T peer1 -e libtool --mode=execute gdb --args
11
12[dhtcache]
13QUOTA = 1 MB
14DATABASE = heap
15
16[transport]
17PLUGINS = tcp
18ACCEPT_FROM6 = ::1;
19ACCEPT_FROM = 127.0.0.1;
20NEIGHBOUR_LIMIT = 50
21IMMEDIATE_START = YES
22
23# Transport requires resolver when connecting to a peer, so enable it
24[resolver]
25START_ON_DEMAND = YES
26
27[ats]
28WAN_QUOTA_OUT = 3932160
29WAN_QUOTA_IN = 3932160
30
31[core]
32USE_EPHEMERAL_KEYS = NO
33IMMEDIATE_START = YES
34
35[transport-tcp]
36TIMEOUT = 300 s
37
38[PATHS]
39GNUNET_TEST_HOME = $GNUNET_TMP/test-testbed/
40
41[nat]
42RETURN_LOCAL_ADDRESSES = YES
43
44[peerinfo]
45NO_IO = YES
46
47[rps]
48START_ON_DEMAND = NO
49IMMEDIATE_START = NO
diff --git a/src/testbed/test_testbed_api_test.c b/src/testbed/test_testbed_api_test.c
deleted file mode 100644
index f451c6555..000000000
--- a/src/testbed/test_testbed_api_test.c
+++ /dev/null
@@ -1,251 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file src/testbed/test_testbed_api_test.c
23 * @brief testing cases for testing high level testbed api helper functions
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30
31
32/**
33 * Generic logging shortcut
34 */
35#define LOG(kind, ...) \
36 GNUNET_log (kind, __VA_ARGS__)
37
38/**
39 * Number of peers we want to start
40 */
41#define NUM_PEERS 2
42
43/**
44 * Array of peers
45 */
46static struct GNUNET_TESTBED_Peer **peers;
47
48/**
49 * Operation handle
50 */
51static struct GNUNET_TESTBED_Operation *op;
52
53/**
54 * Abort task identifier
55 */
56static struct GNUNET_SCHEDULER_Task *abort_task;
57
58/**
59 * shutdown task identifier
60 */
61static struct GNUNET_SCHEDULER_Task *shutdown_task;
62
63/**
64 * Testing result
65 */
66static int result;
67
68
69/**
70 * Shutdown nicely
71 *
72 * @param cls NULL
73 */
74static void
75do_shutdown (void *cls)
76{
77 shutdown_task = NULL;
78 if (NULL != abort_task)
79 GNUNET_SCHEDULER_cancel (abort_task);
80 if (NULL != op)
81 GNUNET_TESTBED_operation_done (op);
82 GNUNET_SCHEDULER_shutdown ();
83}
84
85
86/**
87 * shortcut to exit during failure
88 */
89#define FAIL_TEST(cond) do { \
90 if (! (cond)) { \
91 GNUNET_break (0); \
92 if (NULL != abort_task) \
93 GNUNET_SCHEDULER_cancel (abort_task); \
94 abort_task = NULL; \
95 if (NULL == shutdown_task) \
96 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); \
97 return; \
98 } \
99} while (0)
100
101
102/**
103 * abort task to run on test timed out
104 *
105 * @param cls NULL
106 */
107static void
108do_abort (void *cls)
109{
110 LOG (GNUNET_ERROR_TYPE_WARNING, "Test timedout -- Aborting\n");
111 abort_task = NULL;
112 if (NULL != shutdown_task)
113 GNUNET_SCHEDULER_cancel (shutdown_task);
114 do_shutdown (cls);
115}
116
117
118/**
119 * Callback to be called when the requested peer information is available
120 *
121 * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
122 * @param op the operation this callback corresponds to
123 * @param pinfo the result; will be NULL if the operation has failed
124 * @param emsg error message if the operation has failed; will be NULL if the
125 * operation is successful
126 */
127static void
128peerinfo_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op_,
129 const struct GNUNET_TESTBED_PeerInformation *pinfo,
130 const char *emsg)
131{
132 FAIL_TEST (op == op_);
133 FAIL_TEST (NULL == cb_cls);
134 FAIL_TEST (NULL == emsg);
135 FAIL_TEST (GNUNET_TESTBED_PIT_IDENTITY == pinfo->pit);
136 FAIL_TEST (NULL != pinfo->result.id);
137 GNUNET_TESTBED_operation_done (op);
138 op = NULL;
139 result = GNUNET_OK;
140 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
141}
142
143
144/**
145 * Callback to be called when an operation is completed
146 *
147 * @param cls the callback closure from functions generating an operation
148 * @param op the operation that has been finished
149 * @param emsg error message in case the operation has failed; will be NULL if
150 * operation has executed successfully.
151 */
152static void
153op_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op_, const char *emsg)
154{
155 FAIL_TEST (NULL == cls);
156 FAIL_TEST (op == op_);
157 if (NULL != emsg)
158 {
159 LOG (GNUNET_ERROR_TYPE_WARNING, "%s\n", emsg);
160 FAIL_TEST (0);
161 }
162 GNUNET_TESTBED_operation_done (op);
163 op = GNUNET_TESTBED_peer_get_information (peers[0],
164 GNUNET_TESTBED_PIT_IDENTITY,
165 &peerinfo_cb, NULL);
166}
167
168
169/**
170 * Controller event callback
171 *
172 * @param cls NULL
173 * @param event the controller event
174 */
175static void
176controller_event_cb (void *cls,
177 const struct GNUNET_TESTBED_EventInformation *event)
178{
179 switch (event->type)
180 {
181 case GNUNET_TESTBED_ET_CONNECT:
182 FAIL_TEST (event->details.peer_connect.peer1 == peers[0]);
183 FAIL_TEST (event->details.peer_connect.peer2 == peers[1]);
184 break;
185
186 default:
187 FAIL_TEST (0);
188 }
189}
190
191
192/**
193 * Signature of a main function for a testcase.
194 *
195 * @param cls closure
196 * @param h the run handle
197 * @param num_peers number of peers in 'peers'
198 * @param peers- handle to peers run in the testbed
199 * @param links_succeeded the number of overlay link connection attempts that
200 * succeeded
201 * @param links_failed the number of overlay link connection attempts that
202 * failed
203 */
204static void
205test_master (void *cls,
206 struct GNUNET_TESTBED_RunHandle *h,
207 unsigned int num_peers,
208 struct GNUNET_TESTBED_Peer **peers_,
209 unsigned int links_succeeded,
210 unsigned int links_failed)
211{
212 unsigned int peer;
213
214 FAIL_TEST (NULL == cls);
215 FAIL_TEST (NUM_PEERS == num_peers);
216 FAIL_TEST (NULL != peers_);
217 for (peer = 0; peer < num_peers; peer++)
218 FAIL_TEST (NULL != peers_[peer]);
219 peers = peers_;
220 op = GNUNET_TESTBED_overlay_connect (NULL, &op_comp_cb, NULL, peers[0],
221 peers[1]);
222 abort_task =
223 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
224 (GNUNET_TIME_UNIT_MINUTES, 3), &do_abort,
225 NULL);
226}
227
228
229/**
230 * Main function
231 */
232int
233main (int argc, char **argv)
234{
235 uint64_t event_mask;
236
237 result = GNUNET_SYSERR;
238 event_mask = 0;
239 event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
240 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
241 (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
242 "test_testbed_api.conf", NUM_PEERS,
243 event_mask, &controller_event_cb, NULL,
244 &test_master, NULL);
245 if (GNUNET_OK != result)
246 return 1;
247 return 0;
248}
249
250
251/* end of test_testbed_api_test.c */
diff --git a/src/testbed/test_testbed_api_test_timeout.c b/src/testbed/test_testbed_api_test_timeout.c
deleted file mode 100644
index fe76ad441..000000000
--- a/src/testbed/test_testbed_api_test_timeout.c
+++ /dev/null
@@ -1,126 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file src/testbed/test_testbed_api_test.c
23 * @brief testing cases for testing notifications via test master callback upon
24 * timeout while setting up testbed using functions
25 * GNUNET_TESTBED_test_run()
26 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
27 */
28
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_testbed_service.h"
32
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) \
38 GNUNET_log (kind, __VA_ARGS__)
39
40/**
41 * Number of peers we want to start
42 */
43#define NUM_PEERS 25
44
45/**
46 * Testing result
47 */
48static int result;
49
50
51/**
52 * shortcut to exit during failure
53 */
54#define FAIL_TEST(cond) do { \
55 if (! (cond)) { \
56 GNUNET_break (0); \
57 GNUNET_SCHEDULER_shutdown (); \
58 return; \
59 } \
60} while (0)
61
62
63/**
64 * Controller event callback
65 *
66 * @param cls NULL
67 * @param event the controller event
68 */
69static void
70controller_event_cb (void *cls,
71 const struct GNUNET_TESTBED_EventInformation *event)
72{
73 FAIL_TEST (0);
74}
75
76
77/**
78 * Signature of a main function for a testcase.
79 *
80 * @param cls closure
81 * @param h the run handle
82 * @param num_peers number of peers in 'peers'
83 * @param peers- handle to peers run in the testbed
84 * @param links_succeeded the number of overlay link connection attempts that
85 * succeeded
86 * @param links_failed the number of overlay link connection attempts that
87 * failed
88 */
89static void
90test_master (void *cls,
91 struct GNUNET_TESTBED_RunHandle *h,
92 unsigned int num_peers,
93 struct GNUNET_TESTBED_Peer **peers_,
94 unsigned int links_succeeded,
95 unsigned int links_failed)
96{
97 FAIL_TEST (NULL == cls);
98 FAIL_TEST (0 == num_peers);
99 FAIL_TEST (NULL == peers_);
100 result = GNUNET_OK;
101 GNUNET_SCHEDULER_shutdown ();
102}
103
104
105/**
106 * Main function
107 */
108int
109main (int argc, char **argv)
110{
111 uint64_t event_mask;
112
113 result = GNUNET_SYSERR;
114 event_mask = 0;
115 (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
116 "test_testbed_api_test_timeout.conf",
117 NUM_PEERS,
118 event_mask, &controller_event_cb, NULL,
119 &test_master, NULL);
120 if (GNUNET_OK != result)
121 return 1;
122 return 0;
123}
124
125
126/* end of test_testbed_api_test.c */
diff --git a/src/testbed/test_testbed_api_test_timeout.conf b/src/testbed/test_testbed_api_test_timeout.conf
deleted file mode 100644
index 8e283664d..000000000
--- a/src/testbed/test_testbed_api_test_timeout.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = CLIQUE
5SETUP_TIMEOUT = 2 ms
diff --git a/src/testbed/test_testbed_api_testbed_run.c b/src/testbed/test_testbed_api_testbed_run.c
deleted file mode 100644
index fda5c3223..000000000
--- a/src/testbed/test_testbed_api_testbed_run.c
+++ /dev/null
@@ -1,242 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_api_testbed_run.c
23 * @brief Test cases for testing high-level testbed management
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30
31/**
32 * Number of peers we want to start
33 */
34#define NUM_PEERS 5
35
36/**
37 * The array of peers; we fill this as the peers are given to us by the testbed
38 */
39static struct GNUNET_TESTBED_Peer *peers[NUM_PEERS];
40
41/**
42 * Operation handle
43 */
44static struct GNUNET_TESTBED_Operation *op;
45
46/**
47 * Abort task identifier
48 */
49static struct GNUNET_SCHEDULER_Task *abort_task;
50
51/**
52 * Current peer id
53 */
54static unsigned int peer_id;
55
56/**
57 * Testing result
58 */
59static int result;
60
61/**
62 * Should we wait forever after testbed is initialized?
63 */
64static int wait_forever;
65
66
67/**
68 * Shutdown nicely
69 *
70 * @param cls NULL
71 */
72static void
73do_shutdown (void *cls)
74{
75 if (NULL != abort_task)
76 GNUNET_SCHEDULER_cancel (abort_task);
77 GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */
78}
79
80
81/**
82 * abort task to run on test timed out
83 *
84 * @param cls NULL
85 */
86static void
87do_abort (void *cls)
88{
89 abort_task = NULL;
90 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
91 "Test timed out -- Aborting\n");
92 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
93}
94
95
96/**
97 * Signature of a main function for a testcase.
98 *
99 * @param cls closure
100 * @param h the run handle
101 * @param num_peers number of peers in 'peers'
102 * @param peers_ handle to peers run in the testbed
103 * @param links_succeeded the number of overlay link connection attempts that
104 * succeeded
105 * @param links_failed the number of overlay link connection attempts that
106 * failed
107 */
108static void
109test_master (void *cls,
110 struct GNUNET_TESTBED_RunHandle *h,
111 unsigned int num_peers,
112 struct GNUNET_TESTBED_Peer **peers_,
113 unsigned int links_succeeded,
114 unsigned int links_failed)
115{
116 result = GNUNET_OK;
117 if (GNUNET_YES == wait_forever)
118 {
119 if (NULL == abort_task)
120 return; /* abort already scheduled */
121 GNUNET_SCHEDULER_cancel (abort_task);
122 abort_task = NULL;
123 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
124 return;
125 }
126 GNUNET_assert (NULL != peers[0]);
127 op = GNUNET_TESTBED_peer_stop (NULL, peers[0], NULL, NULL);
128 GNUNET_assert (NULL != op);
129}
130
131
132/**
133 * Controller event callback
134 *
135 * @param cls NULL
136 * @param event the controller event
137 */
138static void
139controller_event_cb (void *cls,
140 const struct GNUNET_TESTBED_EventInformation *event)
141{
142 switch (event->type)
143 {
144 case GNUNET_TESTBED_ET_PEER_START:
145 GNUNET_assert (NULL == peers[peer_id]);
146 GNUNET_assert (NULL != event->details.peer_start.peer);
147 peers[peer_id++] = event->details.peer_start.peer;
148 break;
149
150 case GNUNET_TESTBED_ET_PEER_STOP:
151 GNUNET_assert (NULL != op);
152 GNUNET_TESTBED_operation_done (op);
153 GNUNET_assert (peers[0] == event->details.peer_stop.peer);
154 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
155 break;
156
157 default:
158 GNUNET_assert (0);
159 }
160}
161
162
163/**
164 * Main run function.
165 *
166 * @param cls NULL
167 * @param args arguments passed to GNUNET_PROGRAM_run
168 * @param cfgfile the path to configuration file
169 * @param cfg the configuration file handle
170 */
171static void
172run (void *cls,
173 char *const *args,
174 const char *cfgfile,
175 const struct GNUNET_CONFIGURATION_Handle *config)
176{
177 uint64_t event_mask;
178
179 event_mask = 0;
180 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
181 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
182 GNUNET_TESTBED_run (NULL, config, NUM_PEERS, event_mask,
183 &controller_event_cb, NULL,
184 &test_master, NULL);
185 abort_task =
186 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
187 (GNUNET_TIME_UNIT_SECONDS, 300),
188 &do_abort,
189 NULL);
190}
191
192
193/**
194 * Main function
195 */
196int
197main (int argc, char **argv)
198{
199 char *argv2[] = {
200 "test_testbed_api_testbed_run",
201 "-c", NULL,
202 NULL
203 };
204 struct GNUNET_GETOPT_CommandLineOption options[] = {
205 GNUNET_GETOPT_OPTION_END
206 };
207 char *testname;
208 char *config_filename;
209 int ret;
210
211 if (NULL == (testname = strrchr (argv[0], (int) '_')))
212 {
213 GNUNET_break (0);
214 return 1;
215 }
216 testname++;
217 testname = GNUNET_strdup (testname);
218
219 if (0 == strcmp ("waitforever", testname))
220 wait_forever = GNUNET_YES;
221 if ((GNUNET_YES != wait_forever) && (0 != strcmp ("run", testname)))
222 {
223 GNUNET_asprintf (&config_filename, "test_testbed_api_testbed_run_%s.conf",
224 testname);
225 }
226 else
227 config_filename = GNUNET_strdup ("test_testbed_api.conf");
228 GNUNET_free (testname);
229 argv2[2] = config_filename;
230 result = GNUNET_SYSERR;
231 ret =
232 GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1, argv2,
233 "test_testbed_api_testbed_run", "nohelp", options,
234 &run, NULL);
235 GNUNET_free (config_filename);
236 if ((GNUNET_OK != ret) || (GNUNET_OK != result))
237 return 1;
238 return 0;
239}
240
241
242/* end of test_testbed_api_testbed_run.c */
diff --git a/src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf b/src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf
deleted file mode 100644
index 72704e80e..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topology2dtorus.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = 2D_TORUS
5
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyclique.conf b/src/testbed/test_testbed_api_testbed_run_topologyclique.conf
deleted file mode 100644
index 9c5b8f439..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologyclique.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = CLIQUE
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf b/src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf
deleted file mode 100644
index b0e28227c..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologyfromfile.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = FROM_FILE
5OVERLAY_TOPOLOGY_FILE = overlay_topology.txt
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyline.conf b/src/testbed/test_testbed_api_testbed_run_topologyline.conf
deleted file mode 100644
index f8e0343e0..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologyline.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = LINE
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyrandom.conf b/src/testbed/test_testbed_api_testbed_run_topologyrandom.conf
deleted file mode 100644
index c2bd85b01..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologyrandom.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = RANDOM
5OVERLAY_RANDOM_LINKS = 5
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyring.conf b/src/testbed/test_testbed_api_testbed_run_topologyring.conf
deleted file mode 100644
index 810edd91a..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologyring.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = RING
diff --git a/src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf b/src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf
deleted file mode 100644
index 0f89ca83a..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologyscalefree.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = SCALE_FREE
5SCALE_FREE_TOPOLOGY_CAP = 70
6SCALE_FREE_TOPOLOGY_M = 5
diff --git a/src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf b/src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf
deleted file mode 100644
index ba13a325c..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologysmallworld.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = SMALL_WORLD
5OVERLAY_RANDOM_LINKS = 3
diff --git a/src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf b/src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf
deleted file mode 100644
index 0e1b32f13..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologysmallworldring.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = SMALL_WORLD_RING
5OVERLAY_RANDOM_LINKS = 3
diff --git a/src/testbed/test_testbed_api_testbed_run_topologystar.conf b/src/testbed/test_testbed_api_testbed_run_topologystar.conf
deleted file mode 100644
index 13f8d1784..000000000
--- a/src/testbed/test_testbed_api_testbed_run_topologystar.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = STAR
diff --git a/src/testbed/test_testbed_api_topology.c b/src/testbed/test_testbed_api_topology.c
deleted file mode 100644
index dada7286f..000000000
--- a/src/testbed/test_testbed_api_topology.c
+++ /dev/null
@@ -1,189 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file src/testbed/test_testbed_api_topology.c
23 * @brief testing cases for testing high level testbed api helper functions
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30
31/**
32 * Number of peers we want to start
33 */
34#define NUM_PEERS 10
35
36/**
37 * Array of peers
38 */
39static struct GNUNET_TESTBED_Peer **peers;
40
41/**
42 * Operation handle
43 */
44static struct GNUNET_TESTBED_Operation *op;
45
46/**
47 * Shutdown task
48 */
49static struct GNUNET_SCHEDULER_Task *shutdown_task;
50
51/**
52 * Testing result
53 */
54static int result;
55
56/**
57 * Counter for counting overlay connections
58 */
59static unsigned int overlay_connects;
60
61
62/**
63 * Shutdown nicely
64 *
65 * @param cls NULL
66 */
67static void
68do_shutdown (void *cls)
69{
70 shutdown_task = NULL;
71 if (NULL != op)
72 {
73 GNUNET_TESTBED_operation_done (op);
74 op = NULL;
75 }
76 GNUNET_SCHEDULER_shutdown ();
77}
78
79
80/**
81 * Controller event callback
82 *
83 * @param cls NULL
84 * @param event the controller event
85 */
86static void
87controller_event_cb (void *cls,
88 const struct GNUNET_TESTBED_EventInformation *event)
89{
90 switch (event->type)
91 {
92 case GNUNET_TESTBED_ET_CONNECT:
93 overlay_connects++;
94 if ((NUM_PEERS) == overlay_connects)
95 {
96 result = GNUNET_OK;
97 GNUNET_SCHEDULER_cancel (shutdown_task);
98 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
99 }
100 break;
101
102 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
103 GNUNET_assert (NULL != event->details.operation_finished.emsg);
104 break;
105
106 default:
107 GNUNET_break (0);
108 if ((GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type) &&
109 (NULL != event->details.operation_finished.emsg))
110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
111 "An operation failed with error: %s\n",
112 event->details.operation_finished.emsg);
113 result = GNUNET_SYSERR;
114 GNUNET_SCHEDULER_cancel (shutdown_task);
115 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
116 }
117}
118
119
120/**
121 * Signature of a main function for a testcase.
122 *
123 * @param cls closure
124 * @param h the run handle
125 * @param num_peers number of peers in 'peers'
126 * @param peers_ handle to peers run in the testbed
127 * @param links_succeeded the number of overlay link connection attempts that
128 * succeeded
129 * @param links_failed the number of overlay link connection attempts that
130 * failed
131 */
132static void
133test_master (void *cls,
134 struct GNUNET_TESTBED_RunHandle *h,
135 unsigned int num_peers,
136 struct GNUNET_TESTBED_Peer **peers_,
137 unsigned int links_succeeded,
138 unsigned int links_failed)
139{
140 unsigned int peer;
141
142 GNUNET_assert (NULL == cls);
143 if (NULL == peers_)
144 {
145 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test due to timeout\n");
146 return;
147 }
148 GNUNET_assert (NUM_PEERS == num_peers);
149 for (peer = 0; peer < num_peers; peer++)
150 GNUNET_assert (NULL != peers_[peer]);
151 peers = peers_;
152 overlay_connects = 0;
153 op = GNUNET_TESTBED_overlay_configure_topology (NULL, NUM_PEERS, peers, NULL,
154 NULL,
155 NULL,
156 GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI,
157 NUM_PEERS,
158 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
159 GNUNET_assert (NULL != op);
160 shutdown_task =
161 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
162 (GNUNET_TIME_UNIT_SECONDS, 300),
163 do_shutdown, NULL);
164}
165
166
167/**
168 * Main function
169 */
170int
171main (int argc, char **argv)
172{
173 uint64_t event_mask;
174
175 result = GNUNET_SYSERR;
176 event_mask = 0;
177 event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
178 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
179 (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
180 "test_testbed_api.conf", NUM_PEERS,
181 event_mask, &controller_event_cb, NULL,
182 &test_master, NULL);
183 if (GNUNET_OK != result)
184 return 1;
185 return 0;
186}
187
188
189/* end of test_testbed_api_topology.c */
diff --git a/src/testbed/test_testbed_api_topology_clique.c b/src/testbed/test_testbed_api_topology_clique.c
deleted file mode 100644
index 33c21a69c..000000000
--- a/src/testbed/test_testbed_api_topology_clique.c
+++ /dev/null
@@ -1,185 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file src/testbed/test_testbed_api_topology.c
23 * @brief testing cases for testing high level testbed api helper functions
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30
31/**
32 * Number of peers we want to start
33 */
34#define NUM_PEERS 10
35
36/**
37 * Array of peers
38 */
39static struct GNUNET_TESTBED_Peer **peers;
40
41/**
42 * Operation handle
43 */
44static struct GNUNET_TESTBED_Operation *op;
45
46/**
47 * Shutdown task
48 */
49static struct GNUNET_SCHEDULER_Task *shutdown_task;
50
51/**
52 * Testing result
53 */
54static int result;
55
56/**
57 * Counter for counting overlay connections
58 */
59static unsigned int overlay_connects;
60
61
62/**
63 * Shutdown nicely
64 *
65 * @param cls NULL
66 */
67static void
68do_shutdown (void *cls)
69{
70 shutdown_task = NULL;
71 if (NULL != op)
72 {
73 GNUNET_TESTBED_operation_done (op);
74 op = NULL;
75 }
76 GNUNET_SCHEDULER_shutdown ();
77}
78
79
80/**
81 * Controller event callback
82 *
83 * @param cls NULL
84 * @param event the controller event
85 */
86static void
87controller_event_cb (void *cls,
88 const struct GNUNET_TESTBED_EventInformation *event)
89{
90 switch (event->type)
91 {
92 case GNUNET_TESTBED_ET_CONNECT:
93 overlay_connects++;
94 if ((NUM_PEERS * (NUM_PEERS - 1)) == overlay_connects)
95 {
96 result = GNUNET_OK;
97 GNUNET_SCHEDULER_cancel (shutdown_task);
98 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
99 }
100 break;
101
102 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
103 GNUNET_assert (NULL != event->details.operation_finished.emsg);
104 break;
105
106 default:
107 GNUNET_break (0);
108 result = GNUNET_SYSERR;
109 GNUNET_SCHEDULER_cancel (shutdown_task);
110 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
111 }
112}
113
114
115/**
116 * Signature of a main function for a testcase.
117 *
118 * @param cls closure
119 * @param h the run handle
120 * @param num_peers number of peers in 'peers'
121 * @param peers_ handle to peers run in the testbed
122 * @param links_succeeded the number of overlay link connection attempts that
123 * succeeded
124 * @param links_failed the number of overlay link connection attempts that
125 * failed
126 */
127static void
128test_master (void *cls,
129 struct GNUNET_TESTBED_RunHandle *h,
130 unsigned int num_peers,
131 struct GNUNET_TESTBED_Peer **peers_,
132 unsigned int links_succeeded,
133 unsigned int links_failed)
134{
135 unsigned int peer;
136
137 GNUNET_assert (NULL == cls);
138 if (NULL == peers_)
139 {
140 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test due to timeout\n");
141 return;
142 }
143 GNUNET_assert (NUM_PEERS == num_peers);
144 for (peer = 0; peer < num_peers; peer++)
145 GNUNET_assert (NULL != peers_[peer]);
146 peers = peers_;
147 overlay_connects = 0;
148 op = GNUNET_TESTBED_overlay_configure_topology (NULL, NUM_PEERS, peers, NULL,
149 NULL,
150 NULL,
151 GNUNET_TESTBED_TOPOLOGY_CLIQUE,
152 /* GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI, */
153 /* NUM_PEERS, */
154 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
155 GNUNET_assert (NULL != op);
156 shutdown_task =
157 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
158 (GNUNET_TIME_UNIT_SECONDS, 300),
159 do_shutdown, NULL);
160}
161
162
163/**
164 * Main function
165 */
166int
167main (int argc, char **argv)
168{
169 uint64_t event_mask;
170
171 result = GNUNET_SYSERR;
172 event_mask = 0;
173 event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
174 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
175 (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
176 "test_testbed_api.conf", NUM_PEERS,
177 event_mask, &controller_event_cb, NULL,
178 &test_master, NULL);
179 if (GNUNET_OK != result)
180 return 1;
181 return 0;
182}
183
184
185/* end of test_testbed_api_topology.c */
diff --git a/src/testbed/test_testbed_underlay.c b/src/testbed/test_testbed_underlay.c
deleted file mode 100644
index 8b706ff83..000000000
--- a/src/testbed/test_testbed_underlay.c
+++ /dev/null
@@ -1,174 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/test_testbed_underlay.c
23 * @brief testcase binary for testing testbed underlay restrictions
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30
31
32/**
33 * Number of peers we start in this test case
34 */
35#define NUM_PEERS 3
36
37/**
38 * Result of this test case
39 */
40static int result;
41
42static struct GNUNET_TESTBED_Operation *op;
43
44
45/**
46 * Shutdown testcase
47 *
48 * @param cls NULL
49 * @param tc scheduler task context
50 */
51static void
52do_shutdown (void *cls)
53{
54 if (NULL != op)
55 GNUNET_TESTBED_operation_done (op);
56 op = NULL;
57}
58
59
60/**
61 * Callback to be called when an operation is completed
62 *
63 * @param cls the callback closure from functions generating an operation
64 * @param op the operation that has been finished
65 * @param emsg error message in case the operation has failed; will be NULL if
66 * operation has executed successfully.
67 */
68static void
69overlay_connect_status (void *cls,
70 struct GNUNET_TESTBED_Operation *op_,
71 const char *emsg)
72{
73 GNUNET_assert (op_ == op);
74 GNUNET_TESTBED_operation_done (op);
75 op = NULL;
76 if (NULL == emsg)
77 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
78 "Peers 0 and 2 should not get connected\n");
79 else
80 {
81 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
82 "Peers 0 and 2 not connected: %s. Success!\n", emsg);
83 result = GNUNET_OK;
84 }
85 GNUNET_SCHEDULER_shutdown ();
86}
87
88
89/**
90 * Signature of a main function for a testcase.
91 *
92 * @param cls closure
93 * @param h the run handle
94 * @param num_peers number of peers in 'peers'
95 * @param peers_ handle to peers run in the testbed
96 * @param links_succeeded the number of overlay link connection attempts that
97 * succeeded
98 * @param links_failed the number of overlay link connection attempts that
99 * failed
100 */
101static void
102test_master (void *cls,
103 struct GNUNET_TESTBED_RunHandle *h,
104 unsigned int num_peers,
105 struct GNUNET_TESTBED_Peer **peers_,
106 unsigned int links_succeeded,
107 unsigned int links_failed)
108{
109 GNUNET_assert (NULL == cls);
110 if (NULL == peers_)
111 {
112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failing test due to timeout\n");
113 GNUNET_SCHEDULER_shutdown ();
114 return;
115 }
116 GNUNET_assert (NUM_PEERS == num_peers);
117 op = GNUNET_TESTBED_overlay_connect (NULL,
118 &overlay_connect_status,
119 NULL,
120 peers_[0],
121 peers_[2]);
122 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
123 GNUNET_TIME_UNIT_SECONDS,
124 60),
125 &do_shutdown, NULL);
126}
127
128
129#ifndef PATH_MAX
130/**
131 * Assumed maximum path length (for the log file name).
132 */
133#define PATH_MAX 4096
134#endif
135
136
137/**
138 * Main function
139 */
140int
141main (int argc, char **argv)
142{
143 struct GNUNET_CONFIGURATION_Handle *cfg;
144 char pwd[PATH_MAX];
145 char *dbfile;
146 uint64_t event_mask;
147
148 result = GNUNET_SYSERR;
149 event_mask = 0;
150 cfg = GNUNET_CONFIGURATION_create ();
151 GNUNET_assert (GNUNET_YES ==
152 GNUNET_CONFIGURATION_parse (cfg,
153 "test_testbed_underlay.conf.in"));
154 if (NULL == getcwd (pwd, PATH_MAX))
155 return 1;
156 GNUNET_assert (0 < GNUNET_asprintf (&dbfile, "%s/%s", pwd,
157 "test-underlay.sqlite"));
158 GNUNET_CONFIGURATION_set_value_string (cfg, "TESTBED-UNDERLAY", "DBFILE",
159 dbfile);
160 GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_write
161 (cfg, "test_testbed_underlay.conf"));
162 GNUNET_CONFIGURATION_destroy (cfg);
163 cfg = NULL;
164 GNUNET_free (dbfile);
165 dbfile = NULL;
166 (void) GNUNET_TESTBED_test_run ("test_testbed_underlay",
167 "test_testbed_underlay.conf", NUM_PEERS,
168 event_mask, NULL, NULL,
169 &test_master, NULL);
170 (void) unlink ("test_testbed_underlay.conf");
171 if (GNUNET_OK != result)
172 return 1;
173 return 0;
174}
diff --git a/src/testbed/test_testbed_underlay.conf.in b/src/testbed/test_testbed_underlay.conf.in
deleted file mode 100644
index 1916cc59d..000000000
--- a/src/testbed/test_testbed_underlay.conf.in
+++ /dev/null
@@ -1,13 +0,0 @@
1@INLINE@ test_testbed_api_template.conf
2
3[testbed]
4OVERLAY_TOPOLOGY = LINE
5OPERATION_TIMEOUT = 5 s
6
7[testbed-underlay]
8START_ON_DEMAND = NO
9DBFILE = /will/be/overwritten/by/testcase
10IMMEDIATE_START = YES
11
12[dv]
13START_ON_DEMAND = NO
diff --git a/src/testbed/testbed.conf.in b/src/testbed/testbed.conf.in
deleted file mode 100644
index c1d64b324..000000000
--- a/src/testbed/testbed.conf.in
+++ /dev/null
@@ -1,116 +0,0 @@
1[testbed]
2START_ON_DEMAND = NO
3@JAVAPORT@ PORT = 2101
4HOSTNAME = localhost
5BINARY = gnunet-service-testbed
6
7# How long should operations wait?
8OPERATION_TIMEOUT = 30 s
9
10# Set this to the path where the testbed helper is installed. By default the
11# helper binary is searched in @prefix@/lib/gnunet/libexec/
12# HELPER_BINARY_PATH = @prefix@/lib/gnunet/libexec/gnunet-helper-testbed
13
14# Add your local network address here. For example, if you want to run
15# testbed on a group of hosts connected to network 192.168.1.0/24, then set
16# ACCEPT_FROM = 127.0.0.1; 192.168.1.0/24;
17# Multiple network addresses can be given. They should be separated by `;'
18ACCEPT_FROM = 127.0.0.1;
19ACCEPT_FROM6 = ::1;
20
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-testbed.sock
22UNIX_MATCH_UID = YES
23UNIX_MATCH_GID = YES
24
25# How many maximum number of operations can be run in parallel. This number
26# should be decreased if the system is getting overloaded and to reduce the load
27# exerted by the emulation.
28MAX_PARALLEL_OPERATIONS = 1000
29MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS = 1
30
31# What topology should be generated by the helper functions GNUNET_TESTBED_run()
32# and GNUNET_TESTBED_test_run(). This option has no effect if testbed is
33# initialized with other functions. Valid values can be found at:
34# https://gnunet.org/supported-topologies
35OVERLAY_TOPOLOGY = NONE
36
37# Number of random links to be included to the generate the above topology.
38# Note that not all topologies require this option and ignore it. Topologies
39# requiring this option are RANDOM, SMALL_WORLD and SMALL_WORLD ring.
40# OVERLAY_RANDOM_LINKS =
41
42# This option is required if the OVERLAY_TOPOLOGY is set to FROM_FILE. It is
43# ignored for all other topologies. This option should contain the path to
44# the file containing the topology information. The format of the file is
45# presented at: https://gnunet.org/topology-file-format
46# OVERLAY_TOPOLOGY_FILE = /path/to/topology-file
47
48# The following options are required if the OVERLAY_TOPOLOGY is set to
49# SCALE_FREE. They are ignored in all other cases.
50# The number of maximum peers which can connect to a peer
51SCALE_FREE_TOPOLOGY_CAP = 70
52# The minimum number of peers which a peer has to connect
53SCALE_FREE_TOPOLOGY_M = 5
54
55# How many maximum number of handles to peers' services should be kept open at
56# any time. This number also keeps a check on the number of open descriptors as
57# opening a service connection results in opening a file descriptor.
58MAX_PARALLEL_SERVICE_CONNECTIONS = 256
59
60# Size of the internal testbed cache. It is used to cache handles to peers
61# while trying to connect them.
62CACHE_SIZE = 30
63
64# Maximum number of file descriptors a testbed controller is permitted to keep
65# open.
66MAX_OPEN_FDS = 512
67
68# How long should we wait for testbed to setup while using helper functions
69# GNUNET_TESTBED_test_run() and GNUNET_TESTBED_run()
70SETUP_TIMEOUT = 5 m
71
72# Where should testbed write load statistics data
73# STATS_DIR = /tmp/load
74
75# What services should be shared among peers.
76# Format is "[<service:share>] [<service:share>] ...". The shared services are
77# started standalone without any other peer services or a hostkey. For this
78# reason, only services which doesn't depend on other services can only be
79# shared. Example: To share peerinfo among every 10 peers. The following spec
80# will start 5 peerinfo services when 50 peers are started:
81#
82# SHARED_SERVICES = peerinfo:10
83#
84# To share multiple services
85#
86# SHARED_SERVICES = service1:n_share1 service2:n_share2 ...
87#
88# Default is to share no services
89SHARED_SERVICES =
90
91
92[testbed-barrier]
93START_ON_DEMAND = NO
94@UNIXONLY@ PORT = 2103
95HOSTNAME = localhost
96UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-testbed-barrier.sock
97UNIX_MATCH_UID = YES
98UNIX_MATCH_GID = YES
99
100
101# This section is related to configuring underlay restrictions to simulate
102# connectivity restrictions of NAT boxes
103[testbed-underlay]
104START_ON_DEMAND = NO
105NOARMBIND = YES
106BINARY = gnunet-daemon-testbed-underlay
107# The sqlite3 database file containing information about what underlay
108# restrictions to apply
109# DBFILE =
110
111[latency-logger]
112START_ON_DEMAND = NO
113NOARMBIND = YES
114BINARY = gnunet-daemon-latency-logger
115# The sqlite3 database file where the latency values are to be stored
116# DBFILE =
diff --git a/src/testbed/testbed.h b/src/testbed/testbed.h
deleted file mode 100644
index 0f86c149b..000000000
--- a/src/testbed/testbed.h
+++ /dev/null
@@ -1,866 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed.h
23 * @brief IPC messages between testing API and service ("controller")
24 * @author Christian Grothoff
25 */
26
27#ifndef TESTBED_H
28#define TESTBED_H
29
30#include "gnunet_util_lib.h"
31
32GNUNET_NETWORK_STRUCT_BEGIN
33/**
34 * Initial message from a client to a testing control service.
35 */
36struct GNUNET_TESTBED_InitMessage
37{
38 /**
39 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_INIT
40 */
41 struct GNUNET_MessageHeader header;
42
43 /**
44 * Host ID that the controller is either given (if this is the
45 * dominating client) or assumed to have (for peer-connections
46 * between controllers). A controller must check that all
47 * connections make consistent claims...
48 */
49 uint32_t host_id GNUNET_PACKED;
50
51 /**
52 * Event mask that specifies which events this client
53 * is interested in. In NBO.
54 */
55 uint64_t event_mask GNUNET_PACKED;
56
57 /* Followed by 0-terminated hostname of the controller */
58};
59
60
61/**
62 * Notify the service about a host that we intend to use.
63 */
64struct GNUNET_TESTBED_AddHostMessage
65{
66 /**
67 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST
68 */
69 struct GNUNET_MessageHeader header;
70
71 /**
72 * Unique ID for the host (in NBO).
73 */
74 uint32_t host_id GNUNET_PACKED;
75
76 /**
77 * SSH port to use, 0 for default (in NBO).
78 */
79 uint16_t ssh_port GNUNET_PACKED;
80
81 /**
82 * Number of bytes in the user name that follows;
83 * 0 to use no user name; otherwise 'strlen (username)',
84 * excluding 0-termination!
85 */
86 uint16_t username_length GNUNET_PACKED;
87
88 /**
89 * Number of bytes in the host name (excluding 0-termination) that follows the
90 * user name; cannot be 0
91 */
92 uint16_t hostname_length GNUNET_PACKED;
93
94 /**
95 * The length of the uncompressed configuration
96 */
97 uint16_t config_size GNUNET_PACKED;
98
99 /* followed by non 0-terminated user name */
100
101 /* followed by non 0-terminated host name */
102
103 /* followed by gzip compressed configuration to start or connect to a
104 controller on this host. While starting the controller this configuration
105 is used as a template */
106};
107
108
109/**
110 * Confirmation from the service that adding a host
111 * worked (or failed).
112 * FIXME: Where is this required?
113 */
114struct GNUNET_TESTBED_HostConfirmedMessage
115{
116 /**
117 * Type is GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS
118 */
119 struct GNUNET_MessageHeader header;
120
121 /**
122 * Unique ID for the host (in NBO).
123 */
124 uint32_t host_id GNUNET_PACKED;
125
126 /* followed by the 0-terminated error message (on failure)
127 * (typical errors include host-id already in use) */
128};
129
130
131/**
132 * Client notifies controller that it should delegate
133 * requests for a particular client to a particular
134 * sub-controller.
135 */
136struct GNUNET_TESTBED_ControllerLinkRequest
137{
138 /**
139 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS
140 */
141 struct GNUNET_MessageHeader header;
142
143 /**
144 * For which host should requests be delegated? NBO.
145 */
146 uint32_t delegated_host_id GNUNET_PACKED;
147
148 /**
149 * The id of the operation which created this message
150 */
151 uint64_t operation_id GNUNET_PACKED;
152
153 /**
154 * Which host is responsible for managing the delegation? NBO
155 */
156 uint32_t slave_host_id GNUNET_PACKED;
157
158 /**
159 * Set to 1 if the receiving controller is the master controller for
160 * the slave host (and thus responsible for starting it?). 0 if not
161 */
162 uint8_t is_subordinate;
163};
164
165
166/**
167 * Response message for ControllerLinkRequest message
168 */
169struct GNUNET_TESTBED_ControllerLinkResponse
170{
171 /**
172 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT
173 */
174 struct GNUNET_MessageHeader header;
175
176 /**
177 * The size of the compressed configuration. Can be ZERO if the controller is
178 * not started (depends on the ControllerLinkRequest). NBO.
179 */
180 uint16_t config_size GNUNET_PACKED;
181
182 /**
183 * Set to #GNUNET_YES to signify SUCCESS; #GNUNET_NO to signify failure
184 */
185 uint16_t success GNUNET_PACKED;
186
187 /**
188 * The id of the operation which created this message. NBO
189 */
190 uint64_t operation_id GNUNET_PACKED;
191
192 /* If controller linking is successful and configuration is present, then here
193 * comes the serialized gzip configuration with which the controller is
194 * running at the delegate host */
195
196 /* In case of failure, here comes the error message (without \0 termination)*/
197};
198
199
200/**
201 * Message sent from client to testing service to
202 * create (configure, but not start) a peer.
203 */
204struct GNUNET_TESTBED_PeerCreateMessage
205{
206 /**
207 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER
208 */
209 struct GNUNET_MessageHeader header;
210
211 /**
212 * On which host should the peer be started?
213 */
214 uint32_t host_id GNUNET_PACKED;
215
216 /**
217 * Unique operation id
218 */
219 uint64_t operation_id GNUNET_PACKED;
220
221 /**
222 * Unique ID for the peer.
223 */
224 uint32_t peer_id GNUNET_PACKED;
225
226 /**
227 * Size of the uncompressed configuration
228 */
229 uint16_t config_size GNUNET_PACKED;
230
231 /* followed by serialized peer configuration;
232 * gzip'ed configuration file in INI format */
233};
234
235
236/**
237 * Message sent from client to testing service to
238 * reconfigure a (stopped) a peer.
239 */
240struct GNUNET_TESTBED_PeerReconfigureMessage
241{
242 /**
243 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER
244 */
245 struct GNUNET_MessageHeader header;
246
247 /**
248 * Unique ID for the peer.
249 */
250 uint32_t peer_id GNUNET_PACKED;
251
252 /**
253 * Operation ID that is used to identify this operation.
254 */
255 uint64_t operation_id GNUNET_PACKED;
256
257 /**
258 * The length of the serialized configuration when uncompressed
259 */
260 uint16_t config_size GNUNET_PACKED;
261
262 /* followed by serialized peer configuration;
263 * gzip'ed configuration file in INI format */
264};
265
266
267/**
268 * Message sent from client to testing service to
269 * start a peer.
270 */
271struct GNUNET_TESTBED_PeerStartMessage
272{
273 /**
274 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_START_PEER
275 */
276 struct GNUNET_MessageHeader header;
277
278 /**
279 * Unique ID for the peer.
280 */
281 uint32_t peer_id GNUNET_PACKED;
282
283 /**
284 * Operation ID that is used to identify this operation.
285 */
286 uint64_t operation_id GNUNET_PACKED;
287};
288
289
290/**
291 * Message sent from client to testing service to
292 * stop a peer.
293 */
294struct GNUNET_TESTBED_PeerStopMessage
295{
296 /**
297 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER
298 */
299 struct GNUNET_MessageHeader header;
300
301 /**
302 * Unique ID for the peer.
303 */
304 uint32_t peer_id GNUNET_PACKED;
305
306 /**
307 * Operation ID that is used to identify this operation.
308 */
309 uint64_t operation_id GNUNET_PACKED;
310};
311
312
313/**
314 * Message sent from client to testing service to
315 * destroy a (stopped) peer.
316 */
317struct GNUNET_TESTBED_PeerDestroyMessage
318{
319 /**
320 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER
321 */
322 struct GNUNET_MessageHeader header;
323
324 /**
325 * Unique ID for the peer.
326 */
327 uint32_t peer_id GNUNET_PACKED;
328
329 /**
330 * Operation ID that is used to identify this operation.
331 */
332 uint64_t operation_id GNUNET_PACKED;
333};
334
335
336/**
337 * Message sent from client to testing service to
338 * (re)configure a "physical" link between two peers.
339 */
340struct GNUNET_TESTBED_ConfigureUnderlayLinkMessage
341{
342 /**
343 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_CONFIGURE_UNDERLAY_LINK
344 */
345 struct GNUNET_MessageHeader header;
346
347 /**
348 * 'enum GNUNET_TESTBED_ConnectOption' of the option to change
349 */
350 int32_t connect_option GNUNET_PACKED;
351
352 /**
353 * Unique ID for the first peer.
354 */
355 uint32_t peer1 GNUNET_PACKED;
356
357 /**
358 * Unique ID for the second peer.
359 */
360 uint32_t peer2 GNUNET_PACKED;
361
362 /**
363 * Operation ID that is used to identify this operation.
364 */
365 uint64_t operation_id GNUNET_PACKED;
366
367 /* followed by option-dependent variable-size values */
368};
369
370
371/**
372 * Message sent from client to testing service to
373 * connect two peers.
374 */
375struct GNUNET_TESTBED_OverlayConnectMessage
376{
377 /**
378 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT
379 */
380 struct GNUNET_MessageHeader header;
381
382 /**
383 * Unique ID for the first peer.
384 */
385 uint32_t peer1 GNUNET_PACKED;
386
387 /**
388 * Operation ID that is used to identify this operation.
389 */
390 uint64_t operation_id GNUNET_PACKED;
391
392 /**
393 * Unique ID for the second peer.
394 */
395 uint32_t peer2 GNUNET_PACKED;
396
397 /**
398 * The ID of the host which runs peer2
399 */
400 uint32_t peer2_host_id GNUNET_PACKED;
401};
402
403
404/**
405 * Message sent from host controller of a peer(A) to the host controller of
406 * another peer(B) to request B to connect to A
407 */
408struct GNUNET_TESTBED_RemoteOverlayConnectMessage
409{
410 /**
411 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT
412 */
413 struct GNUNET_MessageHeader header;
414
415 /**
416 * The Unique ID of B
417 */
418 uint32_t peer GNUNET_PACKED;
419
420 /**
421 * The Operation ID that is used to identify this operation
422 */
423 uint64_t operation_id GNUNET_PACKED;
424
425 /**
426 * Identity of A
427 */
428 struct GNUNET_PeerIdentity peer_identity;
429
430 /**
431 * To be followed by the HELLO message of A
432 */
433 struct GNUNET_MessageHeader hello[0];
434 // FIXME: we usually do not use this gcc-hack as some
435 // compilers / tools really get messed up by it...
436};
437
438
439/**
440 * Event notification from a controller to a client.
441 */
442struct GNUNET_TESTBED_PeerEventMessage
443{
444 /**
445 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT
446 */
447 struct GNUNET_MessageHeader header;
448
449 /**
450 * `enum GNUNET_TESTBED_EventType` (in NBO);
451 * either #GNUNET_TESTBED_ET_PEER_START or #GNUNET_TESTBED_ET_PEER_STOP.
452 */
453 int32_t event_type GNUNET_PACKED;
454
455 /**
456 * Host where the peer is running.
457 */
458 uint32_t host_id GNUNET_PACKED;
459
460 /**
461 * Peer that was started or stopped.
462 */
463 uint32_t peer_id GNUNET_PACKED;
464
465 /**
466 * Operation ID that is used to identify this operation.
467 */
468 uint64_t operation_id GNUNET_PACKED;
469};
470
471
472/**
473 * Event notification from a controller to a client.
474 */
475struct GNUNET_TESTBED_ConnectionEventMessage
476{
477 /**
478 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT
479 */
480 struct GNUNET_MessageHeader header;
481
482 /**
483 * 'enum GNUNET_TESTBED_EventType' (in NBO);
484 * either #GNUNET_TESTBED_ET_CONNECT or #GNUNET_TESTBED_ET_DISCONNECT.
485 */
486 int32_t event_type GNUNET_PACKED;
487
488 /**
489 * First peer.
490 */
491 uint32_t peer1 GNUNET_PACKED;
492
493 /**
494 * Second peer.
495 */
496 uint32_t peer2 GNUNET_PACKED;
497
498 /**
499 * Operation ID that is used to identify this operation.
500 */
501 uint64_t operation_id GNUNET_PACKED;
502};
503
504
505/**
506 * Event notification from a controller to a client.
507 */
508struct GNUNET_TESTBED_OperationFailureEventMessage
509{
510 /**
511 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT
512 */
513 struct GNUNET_MessageHeader header;
514
515 /**
516 * 'enum GNUNET_TESTBED_EventType' (in NBO);
517 * #GNUNET_TESTBED_ET_OPERATION_FINISHED.
518 */
519 int32_t event_type GNUNET_PACKED;
520
521 /**
522 * Operation ID of the operation that created this event.
523 */
524 uint64_t operation_id GNUNET_PACKED;
525
526 /* followed by 0-terminated error message */
527};
528
529
530/**
531 * Event notification from a controller to a client.
532 */
533struct GNUNET_TESTBED_PeerCreateSuccessEventMessage
534{
535 /**
536 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS
537 */
538 struct GNUNET_MessageHeader header;
539
540 /**
541 * Peer identity of the peer that was created.
542 */
543 uint32_t peer_id GNUNET_PACKED;
544
545 /**
546 * Operation ID of the operation that created this event.
547 */
548 uint64_t operation_id GNUNET_PACKED;
549};
550
551
552/**
553 * Event notification from a controller to a client for
554 * a generic operational success where the operation does
555 * not return any data.
556 */
557struct GNUNET_TESTBED_GenericOperationSuccessEventMessage
558{
559 /**
560 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS
561 */
562 struct GNUNET_MessageHeader header;
563
564 /**
565 * 'enum GNUNET_TESTBED_EventType' (in NBO);
566 * #GNUNET_TESTBED_ET_OPERATION_FINISHED.
567 */
568 int32_t event_type GNUNET_PACKED;
569
570 /**
571 * Operation ID of the operation that created this event.
572 */
573 uint64_t operation_id GNUNET_PACKED;
574};
575
576
577/**
578 * Message sent from client to testing service to
579 * obtain the configuration of a peer.
580 */
581struct GNUNET_TESTBED_PeerGetConfigurationMessage
582{
583 /**
584 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION
585 */
586 struct GNUNET_MessageHeader header;
587
588 /**
589 * Unique ID for the peer.
590 */
591 uint32_t peer_id GNUNET_PACKED;
592
593 /**
594 * Operation ID that is used to identify this operation.
595 */
596 uint64_t operation_id GNUNET_PACKED;
597};
598
599
600/**
601 * Peer configuration and identity reply from controller to a client.
602 */
603struct GNUNET_TESTBED_PeerConfigurationInformationMessage
604{
605 /**
606 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION
607 */
608 struct GNUNET_MessageHeader header;
609
610 /**
611 * The id of the peer relevant to this information
612 */
613 uint32_t peer_id GNUNET_PACKED;
614
615 /**
616 * Operation ID of the operation that created this event.
617 */
618 uint64_t operation_id GNUNET_PACKED;
619
620 /**
621 * Identity of the peer.
622 */
623 struct GNUNET_PeerIdentity peer_identity;
624
625 /**
626 * The size of configuration when uncompressed
627 */
628 uint16_t config_size GNUNET_PACKED;
629
630 /* followed by gzip-compressed configuration of the peer */
631};
632
633
634/**
635 * Message to request configuration of a slave controller
636 */
637struct GNUNET_TESTBED_SlaveGetConfigurationMessage
638{
639 /**
640 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION
641 */
642 struct GNUNET_MessageHeader header;
643
644 /**
645 * The id of the slave host
646 */
647 uint32_t slave_id GNUNET_PACKED;
648
649 /**
650 * Operation ID
651 */
652 uint64_t operation_id GNUNET_PACKED;
653};
654
655
656/**
657 * Reply to #GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION message
658 */
659struct GNUNET_TESTBED_SlaveConfiguration
660{
661 /**
662 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION
663 */
664 struct GNUNET_MessageHeader header;
665
666 /**
667 * The id of the host where the slave is running
668 */
669 uint32_t slave_id GNUNET_PACKED;
670
671 /**
672 * Operation ID
673 */
674 uint64_t operation_id GNUNET_PACKED;
675
676 /**
677 * The size of the configuration when uncompressed
678 */
679 uint16_t config_size GNUNET_PACKED;
680
681 /* followed by gzip-compressed configuration of the peer */
682};
683
684
685/**
686 * Shutdown peers message
687 */
688struct GNUNET_TESTBED_ShutdownPeersMessage
689{
690 /**
691 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS
692 */
693 struct GNUNET_MessageHeader header;
694
695 /**
696 * Operation ID
697 */
698 uint64_t operation_id GNUNET_PACKED;
699};
700
701
702/**
703 * Message to start/stop services of a peer
704 */
705struct GNUNET_TESTBED_ManagePeerServiceMessage
706{
707 /**
708 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS
709 */
710 struct GNUNET_MessageHeader header;
711
712 /**
713 * Unique ID of the peer whose service has to be managed.
714 */
715 uint32_t peer_id GNUNET_PACKED;
716
717 /**
718 * Operation ID
719 */
720 uint64_t operation_id GNUNET_PACKED;
721
722 /**
723 * set this to 1 to start the service; 0 to stop the service
724 */
725 uint8_t start;
726
727 /**
728 * The NULL-terminated name of the service to start/stop follows here
729 */
730};
731
732
733/**
734 * Message to send underlay link model of a peer. This message will be
735 * forwarded to the controller running the peer.
736 */
737struct GNUNET_TESTBED_UnderlayLinkModelMsg
738{
739 /**
740 * Type is #GNUNET_MESSAGE_TYPE_UNDERLAYLINKMODELMSG
741 */
742 struct GNUNET_MessageHeader header;
743
744 /**
745 * The number of peer entries contained in this message
746 */
747 uint32_t nentries GNUNET_PACKED;
748
749 /**
750 * The number of link properties contained in this message
751 */
752 uint32_t nprops GNUNET_PACKED;
753
754 /**
755 * Array of ids of peers to be in the blacklist/whitelist. Each id is of type
756 * uint32_t. Number of ids should be equal to nentries.
757 */
758
759 /**
760 * Array of link properties. Each link property is to be arraged in a
761 * sequence of four integers of type uint32_t: peer_id, latency, loss and
762 * bandwidth.
763 */
764};
765
766
767/**************************************/
768/* Barriers IPC messages and protocol */
769/**************************************/
770
771
772/**
773 * The environmental variable which when available refers to the configuration
774 * file the local testbed controller is using
775 */
776#define ENV_TESTBED_CONFIG "GNUNET_TESTBED_CONTROLLER_CONFIG"
777
778
779/**
780 * Message to initialise a barrier
781 */
782struct GNUNET_TESTBED_BarrierInit
783{
784 /**
785 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT
786 */
787 struct GNUNET_MessageHeader header;
788
789 /**
790 * The quorum percentage needed for crossing the barrier
791 */
792 uint8_t quorum;
793
794 /**
795 * name of the barrier. Non NULL-terminated.
796 */
797 char name[0];
798};
799
800
801/**
802 * Message to cancel a barrier
803 */
804struct GNUNET_TESTBED_BarrierCancel
805{
806 /**
807 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL
808 */
809 struct GNUNET_MessageHeader header;
810
811 /**
812 * The barrier name. Non NULL terminated
813 */
814 char name[0];
815};
816
817
818/**
819 * Message for signalling status changes of a barrier
820 */
821struct GNUNET_TESTBED_BarrierStatusMsg
822{
823 /**
824 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS
825 */
826 struct GNUNET_MessageHeader header;
827
828 /**
829 * status. Use enumerated values of enum BarrierStatus
830 */
831 uint16_t status GNUNET_PACKED;
832
833 /**
834 * strlen of the barrier name
835 */
836 uint16_t name_len GNUNET_PACKED;
837
838 /**
839 * the barrier name (0-terminated) concatenated with an error message
840 * (0-terminated) if the status were to indicate an error
841 */
842 char data[0];
843};
844
845
846/**
847 * Message sent from peers to the testbed-barrier service to indicate that they
848 * have reached a barrier and are waiting for it to be crossed
849 */
850struct GNUNET_TESTBED_BarrierWait
851{
852 /**
853 * Type is #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT
854 */
855 struct GNUNET_MessageHeader header;
856
857 /**
858 * The name of the barrier they have reached. Non-NULL terminated.
859 */
860 char name[0];
861};
862
863
864GNUNET_NETWORK_STRUCT_END
865#endif
866/* end of testbed.h */
diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c
deleted file mode 100644
index 2ae0a1703..000000000
--- a/src/testbed/testbed_api.c
+++ /dev/null
@@ -1,2427 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api.c
23 * @brief API for accessing the GNUnet testing service.
24 * This library is supposed to make it easier to write
25 * testcases and script large-scale benchmarks.
26 * @author Christian Grothoff
27 * @author Sree Harsha Totakura
28 */
29#include "platform.h"
30#include "gnunet_testbed_service.h"
31#include "gnunet_core_service.h"
32#include "gnunet_constants.h"
33#include "gnunet_transport_service.h"
34#include "gnunet_hello_lib.h"
35#include <zlib.h>
36
37#include "testbed.h"
38#include "testbed_api.h"
39#include "testbed_api_hosts.h"
40#include "testbed_api_peers.h"
41#include "testbed_api_operations.h"
42#include "testbed_api_sd.h"
43
44/**
45 * Generic logging shorthand
46 */
47#define LOG(kind, ...) GNUNET_log_from (kind, "testbed-api", __VA_ARGS__)
48
49/**
50 * Debug logging
51 */
52#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
53
54/**
55 * Relative time seconds shorthand
56 */
57#define TIME_REL_SECS(sec) \
58 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, sec)
59
60
61/**
62 * Default server message sending retry timeout
63 */
64#define TIMEOUT_REL TIME_REL_SECS (1)
65
66
67/**
68 * Context data for forwarded Operation
69 */
70struct ForwardedOperationData
71{
72 /**
73 * The callback to call when reply is available
74 */
75 GNUNET_MQ_MessageCallback cc;
76
77 /**
78 * The closure for the above callback
79 */
80 void *cc_cls;
81};
82
83
84/**
85 * Context data for get slave config operations
86 */
87struct GetSlaveConfigData
88{
89 /**
90 * The id of the slave controller
91 */
92 uint32_t slave_id;
93};
94
95
96/**
97 * Context data for controller link operations
98 */
99struct ControllerLinkData
100{
101 /**
102 * The controller link message
103 */
104 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
105
106 /**
107 * The id of the host which is hosting the controller to be linked
108 */
109 uint32_t host_id;
110};
111
112
113/**
114 * Date context for OP_SHUTDOWN_PEERS operations
115 */
116struct ShutdownPeersData
117{
118 /**
119 * The operation completion callback to call
120 */
121 GNUNET_TESTBED_OperationCompletionCallback cb;
122
123 /**
124 * The closure for the above callback
125 */
126 void *cb_cls;
127};
128
129
130/**
131 * An entry in the stack for keeping operations which are about to expire
132 */
133struct ExpireOperationEntry
134{
135 /**
136 * DLL head; new entries are to be inserted here
137 */
138 struct ExpireOperationEntry *next;
139
140 /**
141 * DLL tail; entries are deleted from here
142 */
143 struct ExpireOperationEntry *prev;
144
145 /**
146 * The operation. This will be a dangling pointer when the operation is freed
147 */
148 const struct GNUNET_TESTBED_Operation *op;
149};
150
151
152/**
153 * DLL head for list of operations marked for expiry
154 */
155static struct ExpireOperationEntry *exop_head;
156
157/**
158 * DLL tail for list of operation marked for expiry
159 */
160static struct ExpireOperationEntry *exop_tail;
161
162
163/**
164 * Inserts an operation into the list of operations marked for expiry
165 *
166 * @param op the operation to insert
167 */
168static void
169exop_insert (struct GNUNET_TESTBED_Operation *op)
170{
171 struct ExpireOperationEntry *entry;
172
173 entry = GNUNET_new (struct ExpireOperationEntry);
174 entry->op = op;
175 GNUNET_CONTAINER_DLL_insert_tail (exop_head, exop_tail, entry);
176}
177
178
179/**
180 * Checks if an operation is present in the list of operations marked for
181 * expiry. If the operation is found, it and the tail of operations after it
182 * are removed from the list.
183 *
184 * @param op the operation to check
185 * @return GNUNET_NO if the operation is not present in the list; GNUNET_YES if
186 * the operation is found in the list (the operation is then removed
187 * from the list -- calling this function again with the same
188 * paramenter will return GNUNET_NO)
189 */
190static int
191exop_check (const struct GNUNET_TESTBED_Operation *const op)
192{
193 struct ExpireOperationEntry *entry;
194 struct ExpireOperationEntry *entry2;
195 int found;
196
197 found = GNUNET_NO;
198 entry = exop_head;
199 while (NULL != entry)
200 {
201 if (op == entry->op)
202 {
203 found = GNUNET_YES;
204 break;
205 }
206 entry = entry->next;
207 }
208 if (GNUNET_NO == found)
209 return GNUNET_NO;
210 /* Truncate the tail */
211 while (NULL != entry)
212 {
213 entry2 = entry->next;
214 GNUNET_CONTAINER_DLL_remove (exop_head, exop_tail, entry);
215 GNUNET_free (entry);
216 entry = entry2;
217 }
218 return GNUNET_YES;
219}
220
221
222/**
223 * Context information to be used while searching for operation contexts
224 */
225struct SearchContext
226{
227 /**
228 * The result of the search
229 */
230 struct OperationContext *opc;
231
232 /**
233 * The id of the operation context we are searching for
234 */
235 uint64_t id;
236};
237
238
239/**
240 * Search iterator for searching an operation context
241 *
242 * @param cls the search context
243 * @param key current key code
244 * @param value value in the hash map
245 * @return #GNUNET_YES if we should continue to iterate,
246 * #GNUNET_NO if not.
247 */
248static int
249opc_search_iterator (void *cls, uint32_t key, void *value)
250{
251 struct SearchContext *sc = cls;
252 struct OperationContext *opc = value;
253
254 GNUNET_assert (NULL != opc);
255 GNUNET_assert (NULL == sc->opc);
256 if (opc->id != sc->id)
257 return GNUNET_YES;
258 sc->opc = opc;
259 return GNUNET_NO;
260}
261
262
263/**
264 * Returns the operation context with the given id if found in the Operation
265 * context queues of the controller
266 *
267 * @param c the controller whose operation context map is searched
268 * @param id the id which has to be checked
269 * @return the matching operation context; NULL if no match found
270 */
271static struct OperationContext *
272find_opc (const struct GNUNET_TESTBED_Controller *c, const uint64_t id)
273{
274 struct SearchContext sc;
275
276 sc.id = id;
277 sc.opc = NULL;
278 GNUNET_assert (NULL != c->opc_map);
279 if (GNUNET_SYSERR !=
280 GNUNET_CONTAINER_multihashmap32_get_multiple (c->opc_map,
281 (uint32_t) id,
282 &opc_search_iterator,
283 &sc))
284 return NULL;
285 return sc.opc;
286}
287
288
289/**
290 * Inserts the given operation context into the operation context map of the
291 * given controller. Creates the operation context map if one does not exist
292 * for the controller
293 *
294 * @param c the controller
295 * @param opc the operation context to be inserted
296 */
297void
298GNUNET_TESTBED_insert_opc_ (struct GNUNET_TESTBED_Controller *c,
299 struct OperationContext *opc)
300{
301 if (NULL == c->opc_map)
302 c->opc_map = GNUNET_CONTAINER_multihashmap32_create (256);
303 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap32_put (
304 c->opc_map,
305 (uint32_t) opc->id,
306 opc,
307 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
308}
309
310
311/**
312 * Removes the given operation context from the operation context map of the
313 * given controller
314 *
315 * @param c the controller
316 * @param opc the operation context to remove
317 */
318void
319GNUNET_TESTBED_remove_opc_ (const struct GNUNET_TESTBED_Controller *c,
320 struct OperationContext *opc)
321{
322 GNUNET_assert (NULL != c->opc_map);
323 GNUNET_assert (GNUNET_YES ==
324 GNUNET_CONTAINER_multihashmap32_remove (c->opc_map,
325 (uint32_t) opc->id,
326 opc));
327 if ((0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map)) &&
328 (NULL != c->opcq_empty_cb))
329 c->opcq_empty_cb (c->opcq_empty_cls);
330}
331
332
333/**
334 * Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message is well-formed.
335 *
336 * @param cls the controller handler
337 * @param msg message received
338 * @return #GNUNET_OK if message is well-formed
339 */
340static int
341check_add_host_confirm (void *cls,
342 const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
343{
344 const char *emsg;
345 uint16_t msg_size;
346
347 msg_size = ntohs (msg->header.size) - sizeof(*msg);
348 if (0 == msg_size)
349 return GNUNET_OK;
350 /* We have an error message */
351 emsg = (const char *) &msg[1];
352 if ('\0' != emsg[msg_size - 1])
353 {
354 GNUNET_break (0);
355 return GNUNET_SYSERR;
356 }
357 return GNUNET_OK;
358}
359
360
361/**
362 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTCONFIRM message from
363 * controller (testbed service)
364 *
365 * @param cls the controller handler
366 * @param msg message received
367 */
368static void
369handle_add_host_confirm (void *cls,
370 const struct GNUNET_TESTBED_HostConfirmedMessage *msg)
371{
372 struct GNUNET_TESTBED_Controller *c = cls;
373 struct GNUNET_TESTBED_HostRegistrationHandle *rh = c->rh;
374 const char *emsg;
375 uint16_t msg_size;
376
377 if (NULL == rh)
378 return;
379 if (GNUNET_TESTBED_host_get_id_ (rh->host) != ntohl (msg->host_id))
380 {
381 LOG_DEBUG ("Mismatch in host id's %u, %u of host confirm msg\n",
382 GNUNET_TESTBED_host_get_id_ (rh->host),
383 ntohl (msg->host_id));
384 return;
385 }
386 c->rh = NULL;
387 msg_size = ntohs (msg->header.size) - sizeof(*msg);
388 if (0 == msg_size)
389 {
390 LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
391 GNUNET_TESTBED_mark_host_registered_at_ (rh->host, c);
392 rh->cc (rh->cc_cls, NULL);
393 GNUNET_free (rh);
394 return;
395 }
396 /* We have an error message */
397 emsg = (const char *) &msg[1];
398 LOG (GNUNET_ERROR_TYPE_ERROR,
399 _ ("Adding host %u failed with error: %s\n"),
400 ntohl (msg->host_id),
401 emsg);
402 rh->cc (rh->cc_cls, emsg);
403 GNUNET_free (rh);
404}
405
406
407/**
408 * Handler for forwarded operations
409 *
410 * @param cls the controller handle
411 * @param opc the operation context
412 * @param msg the message
413 */
414static void
415handle_forwarded_operation_msg (void *cls,
416 struct OperationContext *opc,
417 const struct GNUNET_MessageHeader *msg)
418{
419 struct GNUNET_TESTBED_Controller *c = cls;
420 struct ForwardedOperationData *fo_data;
421
422 fo_data = opc->data;
423 if (NULL != fo_data->cc)
424 fo_data->cc (fo_data->cc_cls, msg);
425 GNUNET_TESTBED_remove_opc_ (c, opc);
426 GNUNET_free (fo_data);
427 GNUNET_free (opc);
428}
429
430
431/**
432 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS message from
433 * controller (testbed service)
434 *
435 * @param cls the controller handler
436 * @param msg message received
437 */
438static void
439handle_opsuccess (
440 void *cls,
441 const struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg)
442{
443 struct GNUNET_TESTBED_Controller *c = cls;
444 struct OperationContext *opc;
445 GNUNET_TESTBED_OperationCompletionCallback op_comp_cb;
446 void *op_comp_cb_cls;
447 struct GNUNET_TESTBED_EventInformation event;
448 uint64_t op_id;
449
450 op_id = GNUNET_ntohll (msg->operation_id);
451 LOG_DEBUG ("Operation %llu successful\n",
452 (unsigned long long) op_id);
453 if (NULL == (opc = find_opc (c, op_id)))
454 {
455 LOG_DEBUG ("Operation not found\n");
456 return;
457 }
458 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
459 event.op = opc->op;
460 event.op_cls = opc->op_cls;
461 event.details.operation_finished.emsg = NULL;
462 event.details.operation_finished.generic = NULL;
463 op_comp_cb = NULL;
464 op_comp_cb_cls = NULL;
465 switch (opc->type)
466 {
467 case OP_FORWARDED: {
468 handle_forwarded_operation_msg (c,
469 opc,
470 (const struct
471 GNUNET_MessageHeader *) msg);
472 return;
473 }
474 break;
475
476 case OP_PEER_DESTROY: {
477 struct GNUNET_TESTBED_Peer *peer;
478
479 peer = opc->data;
480 GNUNET_TESTBED_peer_deregister_ (peer);
481 GNUNET_free (peer);
482 opc->data = NULL;
483 // PEERDESTROYDATA
484 }
485 break;
486
487 case OP_SHUTDOWN_PEERS: {
488 struct ShutdownPeersData *data;
489
490 data = opc->data;
491 op_comp_cb = data->cb;
492 op_comp_cb_cls = data->cb_cls;
493 GNUNET_free (data);
494 opc->data = NULL;
495 GNUNET_TESTBED_cleanup_peers_ ();
496 }
497 break;
498
499 case OP_MANAGE_SERVICE: {
500 struct ManageServiceData *data;
501
502 GNUNET_assert (NULL != (data = opc->data));
503 op_comp_cb = data->cb;
504 op_comp_cb_cls = data->cb_cls;
505 GNUNET_free (data);
506 opc->data = NULL;
507 }
508 break;
509
510 case OP_PEER_RECONFIGURE:
511 break;
512
513 default:
514 GNUNET_assert (0);
515 }
516 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
517 opc->state = OPC_STATE_FINISHED;
518 exop_insert (event.op);
519 if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
520 {
521 if (NULL != c->cc)
522 c->cc (c->cc_cls, &event);
523 if (GNUNET_NO == exop_check (event.op))
524 return;
525 }
526 else
527 LOG_DEBUG ("Not calling callback\n");
528 if (NULL != op_comp_cb)
529 op_comp_cb (op_comp_cb_cls, event.op, NULL);
530 /* You could have marked the operation as done by now */
531 GNUNET_break (GNUNET_NO == exop_check (event.op));
532}
533
534
535/**
536 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS message from
537 * controller (testbed service)
538 *
539 * @param cls the controller handle
540 * @param msg message received
541 */
542static void
543handle_peer_create_success (
544 void *cls,
545 const struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *msg)
546{
547 struct GNUNET_TESTBED_Controller *c = cls;
548 struct OperationContext *opc;
549 struct PeerCreateData *data;
550 struct GNUNET_TESTBED_Peer *peer;
551 struct GNUNET_TESTBED_Operation *op;
552 GNUNET_TESTBED_PeerCreateCallback cb;
553 void *cb_cls;
554 uint64_t op_id;
555
556 GNUNET_assert (sizeof(struct GNUNET_TESTBED_PeerCreateSuccessEventMessage) ==
557 ntohs (msg->header.size));
558 op_id = GNUNET_ntohll (msg->operation_id);
559 if (NULL == (opc = find_opc (c, op_id)))
560 {
561 LOG_DEBUG ("Operation context for PeerCreateSuccessEvent not found\n");
562 return;
563 }
564 if (OP_FORWARDED == opc->type)
565 {
566 handle_forwarded_operation_msg (c,
567 opc,
568 (const struct GNUNET_MessageHeader *) msg);
569 return;
570 }
571 GNUNET_assert (OP_PEER_CREATE == opc->type);
572 GNUNET_assert (NULL != opc->data);
573 data = opc->data;
574 GNUNET_assert (NULL != data->peer);
575 peer = data->peer;
576 GNUNET_assert (peer->unique_id == ntohl (msg->peer_id));
577 peer->state = TESTBED_PS_CREATED;
578 GNUNET_TESTBED_peer_register_ (peer);
579 cb = data->cb;
580 cb_cls = data->cls;
581 op = opc->op;
582 GNUNET_free (opc->data);
583 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
584 opc->state = OPC_STATE_FINISHED;
585 exop_insert (op);
586 if (NULL != cb)
587 cb (cb_cls, peer, NULL);
588 /* You could have marked the operation as done by now */
589 GNUNET_break (GNUNET_NO == exop_check (op));
590}
591
592
593/**
594 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT message from
595 * controller (testbed service)
596 *
597 * @param cls the controller handler
598 * @param msg message received
599 */
600static void
601handle_peer_event (void *cls, const struct GNUNET_TESTBED_PeerEventMessage *msg)
602{
603 struct GNUNET_TESTBED_Controller *c = cls;
604 struct OperationContext *opc;
605 struct GNUNET_TESTBED_Peer *peer;
606 struct PeerEventData *data;
607 GNUNET_TESTBED_PeerChurnCallback pcc;
608 void *pcc_cls;
609 struct GNUNET_TESTBED_EventInformation event;
610 uint64_t op_id;
611 uint64_t mask;
612
613 GNUNET_assert (sizeof(struct GNUNET_TESTBED_PeerEventMessage) ==
614 ntohs (msg->header.size));
615 op_id = GNUNET_ntohll (msg->operation_id);
616 if (NULL == (opc = find_opc (c, op_id)))
617 {
618 LOG_DEBUG ("Operation not found\n");
619 return;
620 }
621 if (OP_FORWARDED == opc->type)
622 {
623 handle_forwarded_operation_msg (c,
624 opc,
625 (const struct GNUNET_MessageHeader *) msg);
626 return;
627 }
628 GNUNET_assert ((OP_PEER_START == opc->type) || (OP_PEER_STOP == opc->type));
629 data = opc->data;
630 GNUNET_assert (NULL != data);
631 peer = data->peer;
632 GNUNET_assert (NULL != peer);
633 event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
634 event.op = opc->op;
635 event.op_cls = opc->op_cls;
636 switch (event.type)
637 {
638 case GNUNET_TESTBED_ET_PEER_START:
639 peer->state = TESTBED_PS_STARTED;
640 event.details.peer_start.host = peer->host;
641 event.details.peer_start.peer = peer;
642 break;
643
644 case GNUNET_TESTBED_ET_PEER_STOP:
645 peer->state = TESTBED_PS_STOPPED;
646 event.details.peer_stop.peer = peer;
647 break;
648
649 default:
650 GNUNET_assert (0); /* We should never reach this state */
651 }
652 pcc = data->pcc;
653 pcc_cls = data->pcc_cls;
654 GNUNET_free (data);
655 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
656 opc->state = OPC_STATE_FINISHED;
657 exop_insert (event.op);
658 mask = 1LL << GNUNET_TESTBED_ET_PEER_START;
659 mask |= 1LL << GNUNET_TESTBED_ET_PEER_STOP;
660 if (0 != (mask & c->event_mask))
661 {
662 if (NULL != c->cc)
663 c->cc (c->cc_cls, &event);
664 if (GNUNET_NO == exop_check (event.op))
665 return;
666 }
667 if (NULL != pcc)
668 pcc (pcc_cls, NULL);
669 /* You could have marked the operation as done by now */
670 GNUNET_break (GNUNET_NO == exop_check (event.op));
671}
672
673
674/**
675 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT message from
676 * controller (testbed service)
677 *
678 * @param cls the controller handler
679 * @param msg message received
680 */
681static void
682handle_peer_conevent (void *cls,
683 const struct GNUNET_TESTBED_ConnectionEventMessage *msg)
684{
685 struct GNUNET_TESTBED_Controller *c = cls;
686 struct OperationContext *opc;
687 struct OverlayConnectData *data;
688 GNUNET_TESTBED_OperationCompletionCallback cb;
689 void *cb_cls;
690 struct GNUNET_TESTBED_EventInformation event;
691 uint64_t op_id;
692 uint64_t mask;
693
694 op_id = GNUNET_ntohll (msg->operation_id);
695 if (NULL == (opc = find_opc (c, op_id)))
696 {
697 LOG_DEBUG ("Operation not found\n");
698 return;
699 }
700 if (OP_FORWARDED == opc->type)
701 {
702 handle_forwarded_operation_msg (c,
703 opc,
704 (const struct GNUNET_MessageHeader *) msg);
705 return;
706 }
707 GNUNET_assert (OP_OVERLAY_CONNECT == opc->type);
708 GNUNET_assert (NULL != (data = opc->data));
709 GNUNET_assert ((ntohl (msg->peer1) == data->p1->unique_id) &&
710 (ntohl (msg->peer2) == data->p2->unique_id));
711 event.type = (enum GNUNET_TESTBED_EventType) ntohl (msg->event_type);
712 event.op = opc->op;
713 event.op_cls = opc->op_cls;
714 switch (event.type)
715 {
716 case GNUNET_TESTBED_ET_CONNECT:
717 event.details.peer_connect.peer1 = data->p1;
718 event.details.peer_connect.peer2 = data->p2;
719 break;
720
721 case GNUNET_TESTBED_ET_DISCONNECT:
722 GNUNET_assert (0); /* FIXME: implement */
723 break;
724
725 default:
726 GNUNET_assert (0); /* Should never reach here */
727 break;
728 }
729 cb = data->cb;
730 cb_cls = data->cb_cls;
731 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
732 opc->state = OPC_STATE_FINISHED;
733 exop_insert (event.op);
734 mask = 1LL << GNUNET_TESTBED_ET_CONNECT;
735 mask |= 1LL << GNUNET_TESTBED_ET_DISCONNECT;
736 if (0 != (mask & c->event_mask))
737 {
738 if (NULL != c->cc)
739 c->cc (c->cc_cls, &event);
740 if (GNUNET_NO == exop_check (event.op))
741 return;
742 }
743 if (NULL != cb)
744 cb (cb_cls, opc->op, NULL);
745 /* You could have marked the operation as done by now */
746 GNUNET_break (GNUNET_NO == exop_check (event.op));
747}
748
749
750/**
751 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
752 * controller (testbed service)
753 *
754 * @param cls the controller handler
755 * @param msg message received
756 */
757static int
758check_peer_config (
759 void *cls,
760 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
761{
762 /* anything goes? */
763 return GNUNET_OK;
764}
765
766
767/**
768 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION message from
769 * controller (testbed service)
770 *
771 * @param cls the controller handler
772 * @param msg message received
773 */
774static void
775handle_peer_config (
776 void *cls,
777 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *msg)
778{
779 struct GNUNET_TESTBED_Controller *c = cls;
780 struct OperationContext *opc;
781 struct GNUNET_TESTBED_Peer *peer;
782 struct PeerInfoData *data;
783 struct GNUNET_TESTBED_PeerInformation *pinfo;
784 GNUNET_TESTBED_PeerInfoCallback cb;
785 void *cb_cls;
786 uint64_t op_id;
787
788 op_id = GNUNET_ntohll (msg->operation_id);
789 if (NULL == (opc = find_opc (c, op_id)))
790 {
791 LOG_DEBUG ("Operation not found\n");
792 return;
793 }
794 if (OP_FORWARDED == opc->type)
795 {
796 handle_forwarded_operation_msg (c, opc, &msg->header);
797 return;
798 }
799 data = opc->data;
800 GNUNET_assert (NULL != data);
801 peer = data->peer;
802 GNUNET_assert (NULL != peer);
803 GNUNET_assert (ntohl (msg->peer_id) == peer->unique_id);
804 pinfo = GNUNET_new (struct GNUNET_TESTBED_PeerInformation);
805 pinfo->pit = data->pit;
806 cb = data->cb;
807 cb_cls = data->cb_cls;
808 GNUNET_assert (NULL != cb);
809 GNUNET_free (data);
810 opc->data = NULL;
811 switch (pinfo->pit)
812 {
813 case GNUNET_TESTBED_PIT_IDENTITY:
814 pinfo->result.id = GNUNET_new (struct GNUNET_PeerIdentity);
815 GNUNET_memcpy (pinfo->result.id,
816 &msg->peer_identity,
817 sizeof(struct GNUNET_PeerIdentity));
818 break;
819
820 case GNUNET_TESTBED_PIT_CONFIGURATION:
821 pinfo->result.cfg = /* Freed in oprelease_peer_getinfo */
822 GNUNET_TESTBED_extract_config_ (&msg->header);
823 break;
824
825 case GNUNET_TESTBED_PIT_GENERIC:
826 GNUNET_assert (0); /* never reach here */
827 break;
828 }
829 opc->data = pinfo;
830 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
831 opc->state = OPC_STATE_FINISHED;
832 cb (cb_cls, opc->op, pinfo, NULL);
833 /* We dont check whether the operation is marked as done here as the
834 operation contains data (cfg/identify) which will be freed at a later point
835 */
836}
837
838
839/**
840 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
841 * controller (testbed service)
842 *
843 * @param cls the controller handler
844 * @param msg message received
845 * @return #GNUNET_OK if message is well-formed
846 */
847static int
848check_op_fail_event (
849 void *cls,
850 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
851{
852 /* we accept anything as a valid error message */
853 return GNUNET_OK;
854}
855
856
857/**
858 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT message from
859 * controller (testbed service)
860 *
861 * @param cls the controller handler
862 * @param msg message received
863 */
864static void
865handle_op_fail_event (
866 void *cls,
867 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
868{
869 struct GNUNET_TESTBED_Controller *c = cls;
870 struct OperationContext *opc;
871 const char *emsg;
872 uint64_t op_id;
873 uint64_t mask;
874 struct GNUNET_TESTBED_EventInformation event;
875
876 op_id = GNUNET_ntohll (msg->operation_id);
877 if (NULL == (opc = find_opc (c, op_id)))
878 {
879 LOG_DEBUG ("Operation not found\n");
880 return;
881 }
882 if (OP_FORWARDED == opc->type)
883 {
884 handle_forwarded_operation_msg (c,
885 opc,
886 (const struct GNUNET_MessageHeader *) msg);
887 return;
888 }
889 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
890 opc->state = OPC_STATE_FINISHED;
891 emsg = GNUNET_TESTBED_parse_error_string_ (msg);
892 if (NULL == emsg)
893 emsg = "Unknown error";
894 if (OP_PEER_INFO == opc->type)
895 {
896 struct PeerInfoData *data;
897
898 data = opc->data;
899 if (NULL != data->cb)
900 data->cb (data->cb_cls, opc->op, NULL, emsg);
901 GNUNET_free (data);
902 return; /* We do not call controller callback for peer info */
903 }
904 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
905 event.op = opc->op;
906 event.op_cls = opc->op_cls;
907 event.details.operation_finished.emsg = emsg;
908 event.details.operation_finished.generic = NULL;
909 mask = (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
910 if ((0 != (mask & c->event_mask)) && (NULL != c->cc))
911 {
912 exop_insert (event.op);
913 c->cc (c->cc_cls, &event);
914 if (GNUNET_NO == exop_check (event.op))
915 return;
916 }
917 switch (opc->type)
918 {
919 case OP_PEER_CREATE: {
920 struct PeerCreateData *data;
921
922 data = opc->data;
923 GNUNET_free (data->peer);
924 if (NULL != data->cb)
925 data->cb (data->cls, NULL, emsg);
926 GNUNET_free (data);
927 }
928 break;
929
930 case OP_PEER_START:
931 case OP_PEER_STOP: {
932 struct PeerEventData *data;
933
934 data = opc->data;
935 if (NULL != data->pcc)
936 data->pcc (data->pcc_cls, emsg);
937 GNUNET_free (data);
938 }
939 break;
940
941 case OP_PEER_DESTROY:
942 break;
943
944 case OP_PEER_INFO:
945 GNUNET_assert (0);
946
947 case OP_OVERLAY_CONNECT: {
948 struct OverlayConnectData *data;
949
950 data = opc->data;
951 GNUNET_TESTBED_operation_mark_failed (opc->op);
952 if (NULL != data->cb)
953 data->cb (data->cb_cls, opc->op, emsg);
954 }
955 break;
956
957 case OP_FORWARDED:
958 GNUNET_assert (0);
959
960 case OP_LINK_CONTROLLERS: /* No secondary callback */
961 break;
962
963 case OP_SHUTDOWN_PEERS: {
964 struct ShutdownPeersData *data;
965
966 data = opc->data;
967 GNUNET_free (data); /* FIXME: Decide whether we call data->op_cb */
968 opc->data = NULL;
969 }
970 break;
971
972 case OP_MANAGE_SERVICE: {
973 struct ManageServiceData *data = opc->data;
974 GNUNET_TESTBED_OperationCompletionCallback cb;
975 void *cb_cls;
976
977 GNUNET_assert (NULL != data);
978 cb = data->cb;
979 cb_cls = data->cb_cls;
980 GNUNET_free (data);
981 opc->data = NULL;
982 exop_insert (event.op);
983 if (NULL != cb)
984 cb (cb_cls, opc->op, emsg);
985 /* You could have marked the operation as done by now */
986 GNUNET_break (GNUNET_NO == exop_check (event.op));
987 }
988 break;
989
990 default:
991 GNUNET_break (0);
992 }
993}
994
995
996/**
997 * Function to build GET_SLAVE_CONFIG message
998 *
999 * @param op_id the id this message should contain in its operation id field
1000 * @param slave_id the id this message should contain in its slave id field
1001 * @return newly allocated SlaveGetConfigurationMessage
1002 */
1003static struct GNUNET_TESTBED_SlaveGetConfigurationMessage *
1004GNUNET_TESTBED_generate_slavegetconfig_msg_ (uint64_t op_id, uint32_t slave_id)
1005{
1006 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1007 uint16_t msize;
1008
1009 msize = sizeof(struct GNUNET_TESTBED_SlaveGetConfigurationMessage);
1010 msg = GNUNET_malloc (msize);
1011 msg->header.size = htons (msize);
1012 msg->header.type =
1013 htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION);
1014 msg->operation_id = GNUNET_htonll (op_id);
1015 msg->slave_id = htonl (slave_id);
1016 return msg;
1017}
1018
1019
1020/**
1021 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_INFORMATION message from
1022 * controller (testbed service)
1023 *
1024 * @param c the controller handler
1025 * @param msg message received
1026 */
1027static int
1028check_slave_config (void *cls,
1029 const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1030{
1031 /* anything goes? */
1032 return GNUNET_OK;
1033}
1034
1035
1036/**
1037 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION message from controller
1038 * (testbed service)
1039 *
1040 * @param cls the controller handler
1041 * @param msg message received
1042 */
1043static void
1044handle_slave_config (void *cls,
1045 const struct GNUNET_TESTBED_SlaveConfiguration *msg)
1046{
1047 struct GNUNET_TESTBED_Controller *c = cls;
1048 struct OperationContext *opc;
1049 uint64_t op_id;
1050 uint64_t mask;
1051 struct GNUNET_TESTBED_EventInformation event;
1052
1053 op_id = GNUNET_ntohll (msg->operation_id);
1054 if (NULL == (opc = find_opc (c, op_id)))
1055 {
1056 LOG_DEBUG ("Operation not found\n");
1057 return;
1058 }
1059 if (OP_GET_SLAVE_CONFIG != opc->type)
1060 {
1061 GNUNET_break (0);
1062 return;
1063 }
1064 opc->state = OPC_STATE_FINISHED;
1065 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1066 mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
1067 if ((0 != (mask & c->event_mask)) && (NULL != c->cc))
1068 {
1069 opc->data = GNUNET_TESTBED_extract_config_ (&msg->header);
1070 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1071 event.op = opc->op;
1072 event.op_cls = opc->op_cls;
1073 event.details.operation_finished.generic = opc->data;
1074 event.details.operation_finished.emsg = NULL;
1075 c->cc (c->cc_cls, &event);
1076 }
1077}
1078
1079
1080/**
1081 * Check #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1082 * (testbed service)
1083 *
1084 * @param c the controller handler
1085 * @param msg message received
1086 * @return #GNUNET_OK if @a msg is well-formed
1087 */
1088static int
1089check_link_controllers_result (
1090 void *cls,
1091 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1092{
1093 /* actual check to be implemented */
1094 return GNUNET_OK;
1095}
1096
1097
1098/**
1099 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT message from controller
1100 * (testbed service)
1101 *
1102 * @param cls the controller handler
1103 * @param msg message received
1104 */
1105static void
1106handle_link_controllers_result (
1107 void *cls,
1108 const struct GNUNET_TESTBED_ControllerLinkResponse *msg)
1109{
1110 struct GNUNET_TESTBED_Controller *c = cls;
1111 struct OperationContext *opc;
1112 struct ControllerLinkData *data;
1113 struct GNUNET_CONFIGURATION_Handle *cfg;
1114 struct GNUNET_TESTBED_Host *host;
1115 char *emsg;
1116 uint64_t op_id;
1117 struct GNUNET_TESTBED_EventInformation event;
1118
1119 op_id = GNUNET_ntohll (msg->operation_id);
1120 if (NULL == (opc = find_opc (c, op_id)))
1121 {
1122 LOG_DEBUG ("Operation not found\n");
1123 return;
1124 }
1125 if (OP_FORWARDED == opc->type)
1126 {
1127 handle_forwarded_operation_msg (c,
1128 opc,
1129 (const struct GNUNET_MessageHeader *) msg);
1130 return;
1131 }
1132 if (OP_LINK_CONTROLLERS != opc->type)
1133 {
1134 GNUNET_break (0);
1135 return;
1136 }
1137 GNUNET_assert (NULL != (data = opc->data));
1138 host = GNUNET_TESTBED_host_lookup_by_id_ (data->host_id);
1139 GNUNET_assert (NULL != host);
1140 GNUNET_free (data);
1141 opc->data = NULL;
1142 opc->state = OPC_STATE_FINISHED;
1143 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1144 event.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
1145 event.op = opc->op;
1146 event.op_cls = opc->op_cls;
1147 event.details.operation_finished.emsg = NULL;
1148 event.details.operation_finished.generic = NULL;
1149 emsg = NULL;
1150 cfg = NULL;
1151 if (GNUNET_NO == ntohs (msg->success))
1152 {
1153 emsg =
1154 GNUNET_malloc (ntohs (msg->header.size)
1155 - sizeof(struct GNUNET_TESTBED_ControllerLinkResponse)
1156 + 1);
1157 GNUNET_memcpy (emsg,
1158 &msg[1],
1159 ntohs (msg->header.size)
1160 - sizeof(struct GNUNET_TESTBED_ControllerLinkResponse));
1161 event.details.operation_finished.emsg = emsg;
1162 }
1163 else
1164 {
1165 if (0 != ntohs (msg->config_size))
1166 {
1167 cfg = GNUNET_TESTBED_extract_config_ (
1168 (const struct GNUNET_MessageHeader *) msg);
1169 GNUNET_assert (NULL != cfg);
1170 GNUNET_TESTBED_host_replace_cfg_ (host, cfg);
1171 }
1172 }
1173 if (0 != (c->event_mask & (1L << GNUNET_TESTBED_ET_OPERATION_FINISHED)))
1174 {
1175 if (NULL != c->cc)
1176 c->cc (c->cc_cls, &event);
1177 }
1178 else
1179 LOG_DEBUG ("Not calling callback\n");
1180 if (NULL != cfg)
1181 GNUNET_CONFIGURATION_destroy (cfg);
1182 GNUNET_free (emsg);
1183}
1184
1185
1186/**
1187 * Validate #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS message.
1188 *
1189 * @param cls the controller handle to determine the connection this message
1190 * belongs to
1191 * @param msg the barrier status message
1192 * @return #GNUNET_OK if the message is valid; #GNUNET_SYSERR to tear it
1193 * down signalling an error (message malformed)
1194 */
1195static int
1196check_barrier_status (void *cls,
1197 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1198{
1199 uint16_t msize;
1200 uint16_t name_len;
1201 int status;
1202 const char *name;
1203 size_t emsg_len;
1204
1205 msize = ntohs (msg->header.size);
1206 name = msg->data;
1207 name_len = ntohs (msg->name_len);
1208
1209 if (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg) + name_len + 1 > msize)
1210 {
1211 GNUNET_break_op (0);
1212 return GNUNET_SYSERR;
1213 }
1214 if ('\0' != name[name_len])
1215 {
1216 GNUNET_break_op (0);
1217 return GNUNET_SYSERR;
1218 }
1219 status = ntohs (msg->status);
1220 if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1221 {
1222 emsg_len = msize - (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg)
1223 + name_len + 1); /* +1!? */
1224 if (0 == emsg_len)
1225 {
1226 GNUNET_break_op (0);
1227 return GNUNET_SYSERR;
1228 }
1229 }
1230 return GNUNET_OK;
1231}
1232
1233
1234/**
1235 * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages
1236 *
1237 * @param cls the controller handle to determine the connection this message
1238 * belongs to
1239 * @param msg the barrier status message
1240 */
1241static void
1242handle_barrier_status (void *cls,
1243 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
1244{
1245 struct GNUNET_TESTBED_Controller *c = cls;
1246 struct GNUNET_TESTBED_Barrier *barrier;
1247 char *emsg;
1248 const char *name;
1249 struct GNUNET_HashCode key;
1250 size_t emsg_len;
1251 int status;
1252 uint16_t msize;
1253 uint16_t name_len;
1254
1255 emsg = NULL;
1256 barrier = NULL;
1257 msize = ntohs (msg->header.size);
1258 if (msize <= sizeof(struct GNUNET_TESTBED_BarrierStatusMsg))
1259 {
1260 GNUNET_break_op (0);
1261 goto cleanup;
1262 }
1263 name = msg->data;
1264 name_len = ntohs (msg->name_len);
1265 if (name_len >= // name_len is strlen(barrier_name)
1266 (msize - ((sizeof msg->header) + sizeof(msg->status))))
1267 {
1268 GNUNET_break_op (0);
1269 goto cleanup;
1270 }
1271 if ('\0' != name[name_len])
1272 {
1273 GNUNET_break_op (0);
1274 goto cleanup;
1275 }
1276 LOG_DEBUG ("Received BARRIER_STATUS msg\n");
1277 status = ntohs (msg->status);
1278 if (GNUNET_TESTBED_BARRIERSTATUS_ERROR == status)
1279 {
1280 status = -1;
1281 // unlike name_len, emsg_len includes the trailing zero
1282 emsg_len = msize - (sizeof(struct GNUNET_TESTBED_BarrierStatusMsg)
1283 + (name_len + 1));
1284 if (0 == emsg_len)
1285 {
1286 GNUNET_break_op (0);
1287 goto cleanup;
1288 }
1289 if ('\0' != (msg->data[(name_len + 1) + (emsg_len - 1)]))
1290 {
1291 GNUNET_break_op (0);
1292 goto cleanup;
1293 }
1294 emsg = GNUNET_malloc (emsg_len);
1295 GNUNET_memcpy (emsg, msg->data + name_len + 1, emsg_len);
1296 }
1297 if (NULL == c->barrier_map)
1298 {
1299 GNUNET_break_op (0);
1300 goto cleanup;
1301 }
1302 GNUNET_CRYPTO_hash (name, name_len, &key);
1303 barrier = GNUNET_CONTAINER_multihashmap_get (c->barrier_map, &key);
1304 if (NULL == barrier)
1305 {
1306 GNUNET_break_op (0);
1307 goto cleanup;
1308 }
1309 GNUNET_assert (NULL != barrier->cb);
1310 if ((GNUNET_YES == barrier->echo) &&
1311 (GNUNET_TESTBED_BARRIERSTATUS_CROSSED == status))
1312 GNUNET_TESTBED_queue_message_ (c, GNUNET_copy_message (&msg->header));
1313 barrier->cb (barrier->cls, name, barrier, status, emsg);
1314 if (GNUNET_TESTBED_BARRIERSTATUS_INITIALISED == status)
1315 return; /* just initialised; skip cleanup */
1316
1317cleanup:
1318 GNUNET_free (emsg);
1319 /**
1320 * Do not remove the barrier if we did not echo the status back; this is
1321 * required at the chained testbed controller setup to ensure the only the
1322 * test-driver echos the status and the controller hierarchy properly
1323 * propagates the status.
1324 */if ((NULL != barrier) && (GNUNET_YES == barrier->echo))
1325 GNUNET_TESTBED_barrier_remove_ (barrier);
1326}
1327
1328
1329/**
1330 * Queues a message in send queue for sending to the service
1331 *
1332 * @param controller the handle to the controller
1333 * @param msg the message to queue
1334 */
1335void
1336GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
1337 struct GNUNET_MessageHeader *msg)
1338{
1339 struct GNUNET_MQ_Envelope *env;
1340 struct GNUNET_MessageHeader *m2;
1341 uint16_t type;
1342 uint16_t size;
1343
1344 type = ntohs (msg->type);
1345 size = ntohs (msg->size);
1346 GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
1347 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));
1348 env = GNUNET_MQ_msg_extra (m2, size - sizeof(*m2), type);
1349 GNUNET_memcpy (m2, msg, size);
1350 GNUNET_free (msg);
1351 GNUNET_MQ_send (controller->mq, env);
1352}
1353
1354
1355/**
1356 * Sends the given message as an operation. The given callback is called when a
1357 * reply for the operation is available. Call
1358 * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
1359 * operation context if the cc hasn't been called
1360 *
1361 * @param controller the controller to which the message has to be sent
1362 * @param operation_id the operation id of the message
1363 * @param msg the message to send
1364 * @param cc the callback to call when reply is available
1365 * @param cc_cls the closure for the above callback
1366 * @return the operation context which can be used to cancel the forwarded
1367 * operation
1368 */
1369struct OperationContext *
1370GNUNET_TESTBED_forward_operation_msg_ (
1371 struct GNUNET_TESTBED_Controller *controller,
1372 uint64_t operation_id,
1373 const struct GNUNET_MessageHeader *msg,
1374 GNUNET_MQ_MessageCallback cc,
1375 void *cc_cls)
1376{
1377 struct OperationContext *opc;
1378 struct ForwardedOperationData *data;
1379 struct GNUNET_MQ_Envelope *env;
1380 struct GNUNET_MessageHeader *m2;
1381 uint16_t type = ntohs (msg->type);
1382 uint16_t size = ntohs (msg->size);
1383
1384 env = GNUNET_MQ_msg_extra (m2, size - sizeof(*m2), type);
1385 GNUNET_memcpy (m2, msg, size);
1386 GNUNET_MQ_send (controller->mq, env);
1387 data = GNUNET_new (struct ForwardedOperationData);
1388 data->cc = cc;
1389 data->cc_cls = cc_cls;
1390 opc = GNUNET_new (struct OperationContext);
1391 opc->c = controller;
1392 opc->type = OP_FORWARDED;
1393 opc->data = data;
1394 opc->id = operation_id;
1395 GNUNET_TESTBED_insert_opc_ (controller, opc);
1396 return opc;
1397}
1398
1399
1400/**
1401 * Function to cancel an operation created by simply forwarding an operation
1402 * message.
1403 *
1404 * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
1405 */
1406void
1407GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc)
1408{
1409 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1410 GNUNET_free (opc->data);
1411 GNUNET_free (opc);
1412}
1413
1414
1415/**
1416 * Function to call to start a link-controllers type operation once all queues
1417 * the operation is part of declare that the operation can be activated.
1418 *
1419 * @param cls the closure from GNUNET_TESTBED_operation_create_()
1420 */
1421static void
1422opstart_link_controllers (void *cls)
1423{
1424 struct OperationContext *opc = cls;
1425 struct ControllerLinkData *data;
1426 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1427
1428 GNUNET_assert (NULL != opc->data);
1429 data = opc->data;
1430 msg = data->msg;
1431 data->msg = NULL;
1432 opc->state = OPC_STATE_STARTED;
1433 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1434 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1435}
1436
1437
1438/**
1439 * Callback which will be called when link-controllers type operation is released
1440 *
1441 * @param cls the closure from GNUNET_TESTBED_operation_create_()
1442 */
1443static void
1444oprelease_link_controllers (void *cls)
1445{
1446 struct OperationContext *opc = cls;
1447 struct ControllerLinkData *data;
1448
1449 data = opc->data;
1450 switch (opc->state)
1451 {
1452 case OPC_STATE_INIT:
1453 GNUNET_free (data->msg);
1454 break;
1455
1456 case OPC_STATE_STARTED:
1457 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1458 break;
1459
1460 case OPC_STATE_FINISHED:
1461 break;
1462 }
1463 GNUNET_free (data);
1464 GNUNET_free (opc);
1465}
1466
1467
1468/**
1469 * Function to be called when get slave config operation is ready
1470 *
1471 * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1472 */
1473static void
1474opstart_get_slave_config (void *cls)
1475{
1476 struct OperationContext *opc = cls;
1477 struct GetSlaveConfigData *data = opc->data;
1478 struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg;
1479
1480 GNUNET_assert (NULL != data);
1481 msg = GNUNET_TESTBED_generate_slavegetconfig_msg_ (opc->id, data->slave_id);
1482 GNUNET_free (opc->data);
1483 data = NULL;
1484 opc->data = NULL;
1485 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
1486 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
1487 opc->state = OPC_STATE_STARTED;
1488}
1489
1490
1491/**
1492 * Function to be called when get slave config operation is cancelled or finished
1493 *
1494 * @param cls the OperationContext of type OP_GET_SLAVE_CONFIG
1495 */
1496static void
1497oprelease_get_slave_config (void *cls)
1498{
1499 struct OperationContext *opc = cls;
1500
1501 switch (opc->state)
1502 {
1503 case OPC_STATE_INIT:
1504 GNUNET_free (opc->data);
1505 break;
1506
1507 case OPC_STATE_STARTED:
1508 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
1509 break;
1510
1511 case OPC_STATE_FINISHED:
1512 if (NULL != opc->data)
1513 GNUNET_CONFIGURATION_destroy (opc->data);
1514 break;
1515 }
1516 GNUNET_free (opc);
1517}
1518
1519
1520/**
1521 * Generic error handler, called with the appropriate error code and
1522 * the same closure specified at the creation of the message queue.
1523 * Not every message queue implementation supports an error handler.
1524 *
1525 * @param cls closure, a `struct GNUNET_TESTBED_Controller *`
1526 * @param error error code
1527 */
1528static void
1529mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
1530{
1531 /* struct GNUNET_TESTBED_Controller *c = cls; */
1532
1533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Encountered MQ error: %d\n", error);
1534 /* now what? */
1535 GNUNET_SCHEDULER_shutdown (); /* seems most reasonable */
1536}
1537
1538
1539/**
1540 * Start a controller process using the given configuration at the
1541 * given host.
1542 *
1543 * @param host host to run the controller on; This should be the same host if
1544 * the controller was previously started with
1545 * GNUNET_TESTBED_controller_start()
1546 * @param event_mask bit mask with set of events to call 'cc' for;
1547 * or-ed values of "1LL" shifted by the
1548 * respective 'enum GNUNET_TESTBED_EventType'
1549 * (e.g. "(1LL << GNUNET_TESTBED_ET_CONNECT) | ...")
1550 * @param cc controller callback to invoke on events
1551 * @param cc_cls closure for cc
1552 * @return handle to the controller
1553 */
1554struct GNUNET_TESTBED_Controller *
1555GNUNET_TESTBED_controller_connect (struct GNUNET_TESTBED_Host *host,
1556 uint64_t event_mask,
1557 GNUNET_TESTBED_ControllerCallback cc,
1558 void *cc_cls)
1559{
1560 struct GNUNET_TESTBED_Controller *controller =
1561 GNUNET_new (struct GNUNET_TESTBED_Controller);
1562 struct GNUNET_MQ_MessageHandler handlers[] =
1563 { GNUNET_MQ_hd_var_size (add_host_confirm,
1564 GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS,
1565 struct GNUNET_TESTBED_HostConfirmedMessage,
1566 controller),
1567 GNUNET_MQ_hd_fixed_size (peer_conevent,
1568 GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONNECT_EVENT,
1569 struct GNUNET_TESTBED_ConnectionEventMessage,
1570 controller),
1571 GNUNET_MQ_hd_fixed_size (opsuccess,
1572 GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS,
1573 struct
1574 GNUNET_TESTBED_GenericOperationSuccessEventMessage,
1575 controller),
1576 GNUNET_MQ_hd_var_size (op_fail_event,
1577 GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT,
1578 struct GNUNET_TESTBED_OperationFailureEventMessage,
1579 controller),
1580 GNUNET_MQ_hd_fixed_size (peer_create_success,
1581 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS,
1582 struct
1583 GNUNET_TESTBED_PeerCreateSuccessEventMessage,
1584 controller),
1585 GNUNET_MQ_hd_fixed_size (peer_event,
1586 GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT,
1587 struct GNUNET_TESTBED_PeerEventMessage,
1588 controller),
1589 GNUNET_MQ_hd_var_size (peer_config,
1590 GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
1591 struct
1592 GNUNET_TESTBED_PeerConfigurationInformationMessage,
1593 controller),
1594 GNUNET_MQ_hd_var_size (slave_config,
1595 GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
1596 struct GNUNET_TESTBED_SlaveConfiguration,
1597 controller),
1598 GNUNET_MQ_hd_var_size (link_controllers_result,
1599 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
1600 struct GNUNET_TESTBED_ControllerLinkResponse,
1601 controller),
1602 GNUNET_MQ_hd_var_size (barrier_status,
1603 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
1604 struct GNUNET_TESTBED_BarrierStatusMsg,
1605 controller),
1606 GNUNET_MQ_handler_end () };
1607 struct GNUNET_TESTBED_InitMessage *msg;
1608 struct GNUNET_MQ_Envelope *env;
1609 const struct GNUNET_CONFIGURATION_Handle *cfg;
1610 const char *controller_hostname;
1611 unsigned long long max_parallel_operations;
1612 unsigned long long max_parallel_service_connections;
1613 unsigned long long max_parallel_topology_config_operations;
1614 size_t slen;
1615
1616 GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
1617 if (GNUNET_OK !=
1618 GNUNET_CONFIGURATION_get_value_number (cfg,
1619 "testbed",
1620 "MAX_PARALLEL_OPERATIONS",
1621 &max_parallel_operations))
1622 {
1623 GNUNET_break (0);
1624 GNUNET_free (controller);
1625 return NULL;
1626 }
1627 if (GNUNET_OK !=
1628 GNUNET_CONFIGURATION_get_value_number (cfg,
1629 "testbed",
1630 "MAX_PARALLEL_SERVICE_CONNECTIONS",
1631 &max_parallel_service_connections))
1632 {
1633 GNUNET_break (0);
1634 GNUNET_free (controller);
1635 return NULL;
1636 }
1637 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (
1638 cfg,
1639 "testbed",
1640 "MAX_PARALLEL_TOPOLOGY_CONFIG_OPERATIONS",
1641 &max_parallel_topology_config_operations))
1642 {
1643 GNUNET_break (0);
1644 GNUNET_free (controller);
1645 return NULL;
1646 }
1647 controller->cc = cc;
1648 controller->cc_cls = cc_cls;
1649 controller->event_mask = event_mask;
1650 controller->cfg = GNUNET_CONFIGURATION_dup (cfg);
1651 controller->mq = GNUNET_CLIENT_connect (controller->cfg,
1652 "testbed",
1653 handlers,
1654 &mq_error_handler,
1655 controller);
1656 if (NULL == controller->mq)
1657 {
1658 GNUNET_break (0);
1659 GNUNET_TESTBED_controller_disconnect (controller);
1660 return NULL;
1661 }
1662 GNUNET_TESTBED_mark_host_registered_at_ (host, controller);
1663 controller->host = host;
1664 controller->opq_parallel_operations =
1665 GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1666 (unsigned int)
1667 max_parallel_operations);
1668 controller->opq_parallel_service_connections =
1669 GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
1670 (unsigned int)
1671 max_parallel_service_connections);
1672 controller->opq_parallel_topology_config_operations =
1673 GNUNET_TESTBED_operation_queue_create_ (
1674 OPERATION_QUEUE_TYPE_FIXED,
1675 (unsigned int) max_parallel_topology_config_operations);
1676 controller_hostname = GNUNET_TESTBED_host_get_hostname (host);
1677 if (NULL == controller_hostname)
1678 controller_hostname = "127.0.0.1";
1679 slen = strlen (controller_hostname) + 1;
1680 env = GNUNET_MQ_msg_extra (msg, slen, GNUNET_MESSAGE_TYPE_TESTBED_INIT);
1681 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1682 msg->event_mask = GNUNET_htonll (controller->event_mask);
1683 GNUNET_memcpy (&msg[1], controller_hostname, slen);
1684 GNUNET_MQ_send (controller->mq, env);
1685 return controller;
1686}
1687
1688
1689/**
1690 * Iterator to free opc map entries
1691 *
1692 * @param cls closure
1693 * @param key current key code
1694 * @param value value in the hash map
1695 * @return #GNUNET_YES if we should continue to iterate,
1696 * #GNUNET_NO if not.
1697 */
1698static int
1699opc_free_iterator (void *cls, uint32_t key, void *value)
1700{
1701 struct GNUNET_CONTAINER_MultiHashMap32 *map = cls;
1702 struct OperationContext *opc = value;
1703
1704 GNUNET_assert (NULL != opc);
1705 GNUNET_break (0);
1706 GNUNET_assert (GNUNET_YES ==
1707 GNUNET_CONTAINER_multihashmap32_remove (map, key, value));
1708 GNUNET_free (opc);
1709 return GNUNET_YES;
1710}
1711
1712
1713/**
1714 * Stop the given controller (also will terminate all peers and
1715 * controllers dependent on this controller). This function
1716 * blocks until the testbed has been fully terminated (!).
1717 *
1718 * @param c handle to controller to stop
1719 */
1720void
1721GNUNET_TESTBED_controller_disconnect (struct GNUNET_TESTBED_Controller *c)
1722{
1723 if (NULL != c->mq)
1724 {
1725 GNUNET_MQ_destroy (c->mq);
1726 c->mq = NULL;
1727 }
1728 if (NULL != c->host)
1729 GNUNET_TESTBED_deregister_host_at_ (c->host, c);
1730 GNUNET_CONFIGURATION_destroy (c->cfg);
1731 GNUNET_TESTBED_operation_queue_destroy_ (c->opq_parallel_operations);
1732 GNUNET_TESTBED_operation_queue_destroy_ (c->opq_parallel_service_connections);
1733 GNUNET_TESTBED_operation_queue_destroy_ (
1734 c->opq_parallel_topology_config_operations);
1735 if (NULL != c->opc_map)
1736 {
1737 GNUNET_assert (GNUNET_SYSERR !=
1738 GNUNET_CONTAINER_multihashmap32_iterate (c->opc_map,
1739 &opc_free_iterator,
1740 c->opc_map));
1741 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->opc_map));
1742 GNUNET_CONTAINER_multihashmap32_destroy (c->opc_map);
1743 }
1744 GNUNET_free (c);
1745}
1746
1747
1748/**
1749 * Compresses given configuration using zlib compress
1750 *
1751 * @param config the serialized configuration
1752 * @param size the size of config
1753 * @param xconfig will be set to the compressed configuration (memory is fresly
1754 * allocated)
1755 * @return the size of the xconfig
1756 */
1757size_t
1758GNUNET_TESTBED_compress_config_ (const char *config,
1759 size_t size,
1760 char **xconfig)
1761{
1762 size_t xsize;
1763
1764 xsize = compressBound ((uLong) size);
1765 *xconfig = GNUNET_malloc (xsize);
1766 GNUNET_assert (Z_OK == compress2 ((Bytef *) *xconfig,
1767 (uLongf *) &xsize,
1768 (const Bytef *) config,
1769 (uLongf) size,
1770 Z_BEST_SPEED));
1771 return xsize;
1772}
1773
1774
1775/**
1776 * Function to serialize and compress using zlib a configuration through a
1777 * configuration handle
1778 *
1779 * @param cfg the configuration
1780 * @param size the size of configuration when serialize. Will be set on success.
1781 * @param xsize the sizeo of the compressed configuration. Will be set on success.
1782 * @return the serialized and compressed configuration
1783 */
1784char *
1785GNUNET_TESTBED_compress_cfg_ (const struct GNUNET_CONFIGURATION_Handle *cfg,
1786 size_t *size,
1787 size_t *xsize)
1788{
1789 char *config;
1790 char *xconfig;
1791 size_t size_;
1792 size_t xsize_;
1793
1794 config = GNUNET_CONFIGURATION_serialize (cfg, &size_);
1795 xsize_ = GNUNET_TESTBED_compress_config_ (config, size_, &xconfig);
1796 GNUNET_free (config);
1797 *size = size_;
1798 *xsize = xsize_;
1799 return xconfig;
1800}
1801
1802
1803/**
1804 * Create a link from slave controller to delegated controller. Whenever the
1805 * master controller is asked to start a peer at the delegated controller the
1806 * request will be routed towards slave controller (if a route exists). The
1807 * slave controller will then route it to the delegated controller. The
1808 * configuration of the delegated controller is given and is used to either
1809 * create the delegated controller or to connect to an existing controller. Note
1810 * that while starting the delegated controller the configuration will be
1811 * modified to accommodate available free ports. the 'is_subordinate' specifies
1812 * if the given delegated controller should be started and managed by the slave
1813 * controller, or if the delegated controller already has a master and the slave
1814 * controller connects to it as a non master controller. The success or failure
1815 * of this operation will be signalled through the
1816 * GNUNET_TESTBED_ControllerCallback() with an event of type
1817 * GNUNET_TESTBED_ET_OPERATION_FINISHED
1818 *
1819 * @param op_cls the operation closure for the event which is generated to
1820 * signal success or failure of this operation
1821 * @param master handle to the master controller who creates the association
1822 * @param delegated_host requests to which host should be delegated; cannot be NULL
1823 * @param slave_host which host is used to run the slave controller; use NULL to
1824 * make the master controller connect to the delegated host
1825 * @param is_subordinate GNUNET_YES if the controller at delegated_host should
1826 * be started by the slave controller; GNUNET_NO if the slave
1827 * controller has to connect to the already started delegated
1828 * controller via TCP/IP
1829 * @return the operation handle
1830 */
1831struct GNUNET_TESTBED_Operation *
1832GNUNET_TESTBED_controller_link (void *op_cls,
1833 struct GNUNET_TESTBED_Controller *master,
1834 struct GNUNET_TESTBED_Host *delegated_host,
1835 struct GNUNET_TESTBED_Host *slave_host,
1836 int is_subordinate)
1837{
1838 struct OperationContext *opc;
1839 struct GNUNET_TESTBED_ControllerLinkRequest *msg;
1840 struct ControllerLinkData *data;
1841 uint32_t slave_host_id;
1842 uint32_t delegated_host_id;
1843 uint16_t msg_size;
1844
1845 GNUNET_assert (GNUNET_YES ==
1846 GNUNET_TESTBED_is_host_registered_ (delegated_host, master));
1847 slave_host_id = GNUNET_TESTBED_host_get_id_ (
1848 (NULL != slave_host) ? slave_host : master->host);
1849 delegated_host_id = GNUNET_TESTBED_host_get_id_ (delegated_host);
1850 if ((NULL != slave_host) && (0 != slave_host_id))
1851 GNUNET_assert (GNUNET_YES ==
1852 GNUNET_TESTBED_is_host_registered_ (slave_host, master));
1853 msg_size = sizeof(struct GNUNET_TESTBED_ControllerLinkRequest);
1854 msg = GNUNET_malloc (msg_size);
1855 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS);
1856 msg->header.size = htons (msg_size);
1857 msg->delegated_host_id = htonl (delegated_host_id);
1858 msg->slave_host_id = htonl (slave_host_id);
1859 msg->is_subordinate = (GNUNET_YES == is_subordinate) ? 1 : 0;
1860 data = GNUNET_new (struct ControllerLinkData);
1861 data->msg = msg;
1862 data->host_id = delegated_host_id;
1863 opc = GNUNET_new (struct OperationContext);
1864 opc->c = master;
1865 opc->data = data;
1866 opc->type = OP_LINK_CONTROLLERS;
1867 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
1868 opc->state = OPC_STATE_INIT;
1869 opc->op_cls = op_cls;
1870 msg->operation_id = GNUNET_htonll (opc->id);
1871 opc->op = GNUNET_TESTBED_operation_create_ (opc,
1872 &opstart_link_controllers,
1873 &oprelease_link_controllers);
1874 GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1875 opc->op);
1876 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1877 return opc->op;
1878}
1879
1880
1881/**
1882 * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
1883 * check. Another difference is that this function takes the id of the slave
1884 * host.
1885 *
1886 * @param op_cls the closure for the operation
1887 * @param master the handle to master controller
1888 * @param slave_host_id id of the host where the slave controller is running to
1889 * the slave_host should remain valid until this operation is cancelled
1890 * or marked as finished
1891 * @return the operation handle;
1892 */
1893struct GNUNET_TESTBED_Operation *
1894GNUNET_TESTBED_get_slave_config_ (void *op_cls,
1895 struct GNUNET_TESTBED_Controller *master,
1896 uint32_t slave_host_id)
1897{
1898 struct OperationContext *opc;
1899 struct GetSlaveConfigData *data;
1900
1901 data = GNUNET_new (struct GetSlaveConfigData);
1902 data->slave_id = slave_host_id;
1903 opc = GNUNET_new (struct OperationContext);
1904 opc->state = OPC_STATE_INIT;
1905 opc->c = master;
1906 opc->id = GNUNET_TESTBED_get_next_op_id (master);
1907 opc->type = OP_GET_SLAVE_CONFIG;
1908 opc->data = data;
1909 opc->op_cls = op_cls;
1910 opc->op = GNUNET_TESTBED_operation_create_ (opc,
1911 &opstart_get_slave_config,
1912 &oprelease_get_slave_config);
1913 GNUNET_TESTBED_operation_queue_insert_ (master->opq_parallel_operations,
1914 opc->op);
1915 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
1916 return opc->op;
1917}
1918
1919
1920struct GNUNET_TESTBED_Operation *
1921GNUNET_TESTBED_get_slave_config (void *op_cls,
1922 struct GNUNET_TESTBED_Controller *master,
1923 struct GNUNET_TESTBED_Host *slave_host)
1924{
1925 if (GNUNET_NO == GNUNET_TESTBED_is_host_registered_ (slave_host, master))
1926 return NULL;
1927 return GNUNET_TESTBED_get_slave_config_ (op_cls,
1928 master,
1929 GNUNET_TESTBED_host_get_id_ (
1930 slave_host));
1931}
1932
1933
1934void
1935GNUNET_TESTBED_overlay_write_topology_to_file (
1936 struct GNUNET_TESTBED_Controller *controller,
1937 const char *filename)
1938{
1939 GNUNET_break (0);
1940}
1941
1942
1943/**
1944 * Creates a helper initialization message. This function is here because we
1945 * want to use this in testing
1946 *
1947 * @param trusted_ip the ip address of the controller which will be set as TRUSTED
1948 * HOST(all connections form this ip are permitted by the testbed) when
1949 * starting testbed controller at host. This can either be a single ip
1950 * address or a network address in CIDR notation.
1951 * @param hostname the hostname of the destination this message is intended for
1952 * @param cfg the configuration that has to used to start the testbed service
1953 * thru helper
1954 * @return the initialization message
1955 */
1956struct GNUNET_TESTBED_HelperInit *
1957GNUNET_TESTBED_create_helper_init_msg_ (
1958 const char *trusted_ip,
1959 const char *hostname,
1960 const struct GNUNET_CONFIGURATION_Handle *cfg)
1961{
1962 struct GNUNET_TESTBED_HelperInit *msg;
1963 char *config;
1964 char *xconfig;
1965 size_t config_size;
1966 size_t xconfig_size;
1967 uint16_t trusted_ip_len;
1968 uint16_t hostname_len;
1969 uint16_t msg_size;
1970
1971 config = GNUNET_CONFIGURATION_serialize (cfg, &config_size);
1972 GNUNET_assert (NULL != config);
1973 xconfig_size =
1974 GNUNET_TESTBED_compress_config_ (config, config_size, &xconfig);
1975 GNUNET_free (config);
1976 trusted_ip_len = strlen (trusted_ip);
1977 hostname_len = (NULL == hostname) ? 0 : strlen (hostname);
1978 msg_size = xconfig_size + trusted_ip_len + 1
1979 + sizeof(struct GNUNET_TESTBED_HelperInit);
1980 msg_size += hostname_len;
1981 msg = GNUNET_realloc (xconfig, msg_size);
1982 (void) memmove (((void *) &msg[1]) + trusted_ip_len + 1 + hostname_len,
1983 msg,
1984 xconfig_size);
1985 msg->header.size = htons (msg_size);
1986 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT);
1987 msg->trusted_ip_size = htons (trusted_ip_len);
1988 msg->hostname_size = htons (hostname_len);
1989 msg->config_size = htons (config_size);
1990 (void) strcpy ((char *) &msg[1], trusted_ip);
1991 if (0 != hostname_len)
1992 GNUNET_memcpy ((char *) &msg[1] + trusted_ip_len + 1,
1993 hostname,
1994 hostname_len);
1995 return msg;
1996}
1997
1998
1999/**
2000 * This function is used to signal that the event information (struct
2001 * GNUNET_TESTBED_EventInformation) from an operation has been fully processed
2002 * i.e. if the event callback is ever called for this operation. If the event
2003 * callback for this operation has not yet been called, calling this function
2004 * cancels the operation, frees its resources and ensures the no event is
2005 * generated with respect to this operation. Note that however cancelling an
2006 * operation does NOT guarantee that the operation will be fully undone (or that
2007 * nothing ever happened).
2008 *
2009 * This function MUST be called for every operation to fully remove the
2010 * operation from the operation queue. After calling this function, if
2011 * operation is completed and its event information is of type
2012 * GNUNET_TESTBED_ET_OPERATION_FINISHED, the 'op_result' becomes invalid (!).
2013
2014 * If the operation is generated from GNUNET_TESTBED_service_connect() then
2015 * calling this function on such as operation calls the disconnect adapter if
2016 * the connect adapter was ever called.
2017 *
2018 * @param operation operation to signal completion or cancellation
2019 */
2020void
2021GNUNET_TESTBED_operation_done (struct GNUNET_TESTBED_Operation *operation)
2022{
2023 (void) exop_check (operation);
2024 GNUNET_TESTBED_operation_release_ (operation);
2025}
2026
2027
2028/**
2029 * Generates configuration by uncompressing configuration in given message. The
2030 * given message should be of the following types:
2031 * #GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION,
2032 * #GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION,
2033 * #GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
2034 * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
2035 * #GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT,
2036 *
2037 * FIXME: This API is incredibly ugly.
2038 *
2039 * @param msg the message containing compressed configuration
2040 * @return handle to the parsed configuration; NULL upon error while parsing the message
2041 */
2042struct GNUNET_CONFIGURATION_Handle *
2043GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg)
2044{
2045 struct GNUNET_CONFIGURATION_Handle *cfg;
2046 Bytef *data;
2047 const Bytef *xdata;
2048 uLong data_len;
2049 uLong xdata_len;
2050 int ret;
2051
2052 switch (ntohs (msg->type))
2053 {
2054 case GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION: {
2055 const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *imsg;
2056
2057 imsg =
2058 (const struct GNUNET_TESTBED_PeerConfigurationInformationMessage *) msg;
2059 data_len = (uLong) ntohs (imsg->config_size);
2060 xdata_len =
2061 ntohs (imsg->header.size)
2062 - sizeof(struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
2063 xdata = (const Bytef *) &imsg[1];
2064 }
2065 break;
2066
2067 case GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION: {
2068 const struct GNUNET_TESTBED_SlaveConfiguration *imsg;
2069
2070 imsg = (const struct GNUNET_TESTBED_SlaveConfiguration *) msg;
2071 data_len = (uLong) ntohs (imsg->config_size);
2072 xdata_len = ntohs (imsg->header.size)
2073 - sizeof(struct GNUNET_TESTBED_SlaveConfiguration);
2074 xdata = (const Bytef *) &imsg[1];
2075 }
2076 break;
2077
2078 case GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST: {
2079 const struct GNUNET_TESTBED_AddHostMessage *imsg;
2080 uint16_t osize;
2081
2082 imsg = (const struct GNUNET_TESTBED_AddHostMessage *) msg;
2083 data_len = (uLong) ntohs (imsg->config_size);
2084 osize = sizeof(struct GNUNET_TESTBED_AddHostMessage)
2085 + ntohs (imsg->username_length) + ntohs (imsg->hostname_length);
2086 xdata_len = ntohs (imsg->header.size) - osize;
2087 xdata = (const Bytef *) ((const void *) imsg + osize);
2088 }
2089 break;
2090
2091 case GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT: {
2092 const struct GNUNET_TESTBED_ControllerLinkResponse *imsg;
2093
2094 imsg = (const struct GNUNET_TESTBED_ControllerLinkResponse *) msg;
2095 data_len = ntohs (imsg->config_size);
2096 xdata_len = ntohs (imsg->header.size)
2097 - sizeof(const struct GNUNET_TESTBED_ControllerLinkResponse);
2098 xdata = (const Bytef *) &imsg[1];
2099 }
2100 break;
2101
2102 case GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER: {
2103 const struct GNUNET_TESTBED_PeerCreateMessage *imsg;
2104
2105 imsg = (const struct GNUNET_TESTBED_PeerCreateMessage *) msg;
2106 data_len = ntohs (imsg->config_size);
2107 xdata_len = ntohs (imsg->header.size)
2108 - sizeof(struct GNUNET_TESTBED_PeerCreateMessage);
2109 xdata = (const Bytef *) &imsg[1];
2110 }
2111 break;
2112
2113 case GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER: {
2114 const struct GNUNET_TESTBED_PeerReconfigureMessage *imsg;
2115
2116 imsg = (const struct GNUNET_TESTBED_PeerReconfigureMessage *) msg;
2117 data_len = ntohs (imsg->config_size);
2118 xdata_len = ntohs (imsg->header.size)
2119 - sizeof(struct GNUNET_TESTBED_PeerReconfigureMessage);
2120 xdata = (const Bytef *) &imsg[1];
2121 }
2122 break;
2123
2124 default:
2125 GNUNET_assert (0);
2126 }
2127 data = GNUNET_malloc (data_len);
2128 if (Z_OK != (ret = uncompress (data, &data_len, xdata, xdata_len)))
2129 {
2130 GNUNET_free (data);
2131 GNUNET_break_op (0); /* Un-compression failure */
2132 return NULL;
2133 }
2134 cfg = GNUNET_CONFIGURATION_create ();
2135 if (GNUNET_OK != GNUNET_CONFIGURATION_deserialize (cfg,
2136 (const char *) data,
2137 (size_t) data_len,
2138 NULL))
2139 {
2140 GNUNET_free (data);
2141 GNUNET_break_op (0); /* De-serialization failure */
2142 return NULL;
2143 }
2144 GNUNET_free (data);
2145 return cfg;
2146}
2147
2148
2149const char *
2150GNUNET_TESTBED_parse_error_string_ (
2151 const struct GNUNET_TESTBED_OperationFailureEventMessage *msg)
2152{
2153 uint16_t msize;
2154 const char *emsg;
2155
2156 msize = ntohs (msg->header.size);
2157 if (sizeof(struct GNUNET_TESTBED_OperationFailureEventMessage) >= msize)
2158 return NULL;
2159 msize -= sizeof(struct GNUNET_TESTBED_OperationFailureEventMessage);
2160 emsg = (const char *) &msg[1];
2161 if ('\0' != emsg[msize - 1])
2162 {
2163 GNUNET_break (0);
2164 return NULL;
2165 }
2166 return emsg;
2167}
2168
2169
2170/**
2171 * Function to return the operation id for a controller. The operation id is
2172 * created from the controllers host id and its internal operation counter.
2173 *
2174 * @param controller the handle to the controller whose operation id has to be incremented
2175 * @return the incremented operation id.
2176 */
2177uint64_t
2178GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller *controller)
2179{
2180 uint64_t op_id;
2181
2182 op_id = (uint64_t) GNUNET_TESTBED_host_get_id_ (controller->host);
2183 op_id = op_id << 32;
2184 op_id |= (uint64_t) controller->operation_counter++;
2185 return op_id;
2186}
2187
2188
2189/**
2190 * Function called when a shutdown peers operation is ready
2191 *
2192 * @param cls the closure from GNUNET_TESTBED_operation_create_()
2193 */
2194static void
2195opstart_shutdown_peers (void *cls)
2196{
2197 struct OperationContext *opc = cls;
2198 struct GNUNET_MQ_Envelope *env;
2199 struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2200
2201 opc->state = OPC_STATE_STARTED;
2202 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS);
2203 msg->operation_id = GNUNET_htonll (opc->id);
2204 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
2205 GNUNET_MQ_send (opc->c->mq, env);
2206}
2207
2208
2209/**
2210 * Callback which will be called when shutdown peers operation is released
2211 *
2212 * @param cls the closure from GNUNET_TESTBED_operation_create_()
2213 */
2214static void
2215oprelease_shutdown_peers (void *cls)
2216{
2217 struct OperationContext *opc = cls;
2218
2219 switch (opc->state)
2220 {
2221 case OPC_STATE_STARTED:
2222 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
2223
2224 /* no break; continue */
2225 case OPC_STATE_INIT:
2226 GNUNET_free (opc->data);
2227 break;
2228
2229 case OPC_STATE_FINISHED:
2230 break;
2231 }
2232 GNUNET_free (opc);
2233}
2234
2235
2236/**
2237 * Stops and destroys all peers. Is equivalent of calling
2238 * GNUNET_TESTBED_peer_stop() and GNUNET_TESTBED_peer_destroy() on all peers,
2239 * except that the peer stop event and operation finished event corresponding to
2240 * the respective functions are not generated. This function should be called
2241 * when there are no other pending operations. If there are pending operations,
2242 * it will return NULL
2243 *
2244 * @param c the controller to send this message to
2245 * @param op_cls closure for the operation
2246 * @param cb the callback to call when all peers are stopped and destroyed
2247 * @param cb_cls the closure for the callback
2248 * @return operation handle on success; NULL if any pending operations are
2249 * present
2250 */
2251struct GNUNET_TESTBED_Operation *
2252GNUNET_TESTBED_shutdown_peers (struct GNUNET_TESTBED_Controller *c,
2253 void *op_cls,
2254 GNUNET_TESTBED_OperationCompletionCallback cb,
2255 void *cb_cls)
2256{
2257 struct OperationContext *opc;
2258 struct ShutdownPeersData *data;
2259
2260 if (0 != GNUNET_CONTAINER_multihashmap32_size (c->opc_map))
2261 return NULL;
2262 data = GNUNET_new (struct ShutdownPeersData);
2263 data->cb = cb;
2264 data->cb_cls = cb_cls;
2265 opc = GNUNET_new (struct OperationContext);
2266 opc->c = c;
2267 opc->op_cls = op_cls;
2268 opc->data = data;
2269 opc->id = GNUNET_TESTBED_get_next_op_id (c);
2270 opc->type = OP_SHUTDOWN_PEERS;
2271 opc->state = OPC_STATE_INIT;
2272 opc->op = GNUNET_TESTBED_operation_create_ (opc,
2273 &opstart_shutdown_peers,
2274 &oprelease_shutdown_peers);
2275 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
2276 opc->op);
2277 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
2278 return opc->op;
2279}
2280
2281
2282/**
2283 * Return the index of the peer inside of the total peer array,
2284 * aka. the peer's "unique ID".
2285 *
2286 * @param peer Peer handle.
2287 *
2288 * @return The peer's unique ID.
2289 */
2290uint32_t
2291GNUNET_TESTBED_get_index (const struct GNUNET_TESTBED_Peer *peer)
2292{
2293 return peer->unique_id;
2294}
2295
2296
2297/**
2298 * Remove a barrier and it was the last one in the barrier hash map, destroy the
2299 * hash map
2300 *
2301 * @param barrier the barrier to remove
2302 */
2303void
2304GNUNET_TESTBED_barrier_remove_ (struct GNUNET_TESTBED_Barrier *barrier)
2305{
2306 struct GNUNET_TESTBED_Controller *c = barrier->c;
2307
2308 GNUNET_assert (NULL != c->barrier_map); /* No barriers present */
2309 GNUNET_assert (GNUNET_OK ==
2310 GNUNET_CONTAINER_multihashmap_remove (c->barrier_map,
2311 &barrier->key,
2312 barrier));
2313 GNUNET_free (barrier->name);
2314 GNUNET_free (barrier);
2315 if (0 == GNUNET_CONTAINER_multihashmap_size (c->barrier_map))
2316 {
2317 GNUNET_CONTAINER_multihashmap_destroy (c->barrier_map);
2318 c->barrier_map = NULL;
2319 }
2320}
2321
2322
2323struct GNUNET_TESTBED_Barrier *
2324GNUNET_TESTBED_barrier_init_ (struct GNUNET_TESTBED_Controller *controller,
2325 const char *name,
2326 unsigned int quorum,
2327 GNUNET_TESTBED_barrier_status_cb cb,
2328 void *cls,
2329 int echo)
2330{
2331 struct GNUNET_TESTBED_BarrierInit *msg;
2332 struct GNUNET_MQ_Envelope *env;
2333 struct GNUNET_TESTBED_Barrier *barrier;
2334 struct GNUNET_HashCode key;
2335 size_t name_len;
2336
2337 GNUNET_assert (quorum <= 100);
2338 GNUNET_assert (NULL != cb);
2339 name_len = strlen (name);
2340 GNUNET_assert (0 < name_len);
2341 GNUNET_CRYPTO_hash (name, name_len, &key);
2342 if (NULL == controller->barrier_map)
2343 controller->barrier_map =
2344 GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
2345 if (GNUNET_YES ==
2346 GNUNET_CONTAINER_multihashmap_contains (controller->barrier_map, &key))
2347 {
2348 GNUNET_break (0);
2349 return NULL;
2350 }
2351 LOG_DEBUG ("Initialising barrier `%s'\n", name);
2352 barrier = GNUNET_new (struct GNUNET_TESTBED_Barrier);
2353 barrier->c = controller;
2354 barrier->name = GNUNET_strdup (name);
2355 barrier->cb = cb;
2356 barrier->cls = cls;
2357 barrier->echo = echo;
2358 GNUNET_memcpy (&barrier->key, &key, sizeof(struct GNUNET_HashCode));
2359 GNUNET_assert (GNUNET_OK ==
2360 GNUNET_CONTAINER_multihashmap_put (
2361 controller->barrier_map,
2362 &barrier->key,
2363 barrier,
2364 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
2365
2366 env = GNUNET_MQ_msg_extra (msg,
2367 name_len,
2368 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT);
2369 msg->quorum = (uint8_t) quorum;
2370 GNUNET_memcpy (msg->name, barrier->name, name_len);
2371 GNUNET_MQ_send (barrier->c->mq, env);
2372 return barrier;
2373}
2374
2375
2376/**
2377 * Initialise a barrier and call the given callback when the required percentage
2378 * of peers (quorum) reach the barrier OR upon error.
2379 *
2380 * @param controller the handle to the controller
2381 * @param name identification name of the barrier
2382 * @param quorum the percentage of peers that is required to reach the barrier.
2383 * Peers signal reaching a barrier by calling
2384 * GNUNET_TESTBED_barrier_reached().
2385 * @param cb the callback to call when the barrier is reached or upon error.
2386 * Cannot be NULL.
2387 * @param cb_cls closure for the above callback
2388 * @return barrier handle; NULL upon error
2389 */
2390struct GNUNET_TESTBED_Barrier *
2391GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
2392 const char *name,
2393 unsigned int quorum,
2394 GNUNET_TESTBED_barrier_status_cb cb,
2395 void *cb_cls)
2396{
2397 return GNUNET_TESTBED_barrier_init_ (controller,
2398 name,
2399 quorum,
2400 cb,
2401 cb_cls,
2402 GNUNET_YES);
2403}
2404
2405
2406/**
2407 * Cancel a barrier.
2408 *
2409 * @param barrier the barrier handle
2410 */
2411void
2412GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier)
2413{
2414 struct GNUNET_MQ_Envelope *env;
2415 struct GNUNET_TESTBED_BarrierCancel *msg;
2416 size_t slen;
2417
2418 slen = strlen (barrier->name);
2419 env =
2420 GNUNET_MQ_msg_extra (msg, slen, GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL);
2421 GNUNET_memcpy (msg->name, barrier->name, slen);
2422 GNUNET_MQ_send (barrier->c->mq, env);
2423 GNUNET_TESTBED_barrier_remove_ (barrier);
2424}
2425
2426
2427/* end of testbed_api.c */
diff --git a/src/testbed/testbed_api.h b/src/testbed/testbed_api.h
deleted file mode 100644
index d4ef832ad..000000000
--- a/src/testbed/testbed_api.h
+++ /dev/null
@@ -1,521 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api.h
23 * @brief Interface for functions internally exported from testbed_api.c
24 * @author Sree Harsha Totakura
25 */
26
27#ifndef TESTBED_API_H
28#define TESTBED_API_H
29
30#include "gnunet_util_lib.h"
31#include "gnunet_testbed_service.h"
32#include "testbed.h"
33#include "testbed_helper.h"
34
35/**
36 * Testbed Helper binary name
37 */
38#define HELPER_TESTBED_BINARY "gnunet-helper-testbed"
39
40
41/**
42 * Enumeration of operations
43 */
44enum OperationType
45{
46 /**
47 * Peer create operation
48 */
49 OP_PEER_CREATE,
50
51 /**
52 * Peer start operation
53 */
54 OP_PEER_START,
55
56 /**
57 * Peer stop operation
58 */
59 OP_PEER_STOP,
60
61 /**
62 * Peer destroy operation
63 */
64 OP_PEER_DESTROY,
65
66 /**
67 * Get peer information operation
68 */
69 OP_PEER_INFO,
70
71 /**
72 * Reconfigure a peer
73 */
74 OP_PEER_RECONFIGURE,
75
76 /**
77 * Overlay connection operation
78 */
79 OP_OVERLAY_CONNECT,
80
81 /**
82 * Forwarded operation
83 */
84 OP_FORWARDED,
85
86 /**
87 * Link controllers operation
88 */
89 OP_LINK_CONTROLLERS,
90
91 /**
92 * Get slave config operation
93 */
94 OP_GET_SLAVE_CONFIG,
95
96 /**
97 * Stop and destroy all peers
98 */
99 OP_SHUTDOWN_PEERS,
100
101 /**
102 * Start/stop service at a peer
103 */
104 OP_MANAGE_SERVICE
105};
106
107
108/**
109 * Enumeration of states of OperationContext
110 */
111enum OperationContextState
112{
113 /**
114 * The initial state where the associated operation has just been created
115 * and is waiting in the operation queues to be started
116 */
117 OPC_STATE_INIT = 0,
118
119 /**
120 * The operation has been started. It may occupy some resources which are to
121 * be freed if cancelled.
122 */
123 OPC_STATE_STARTED,
124
125 /**
126 * The operation has finished. The end results of this operation may occupy
127 * some resources which are to be freed by operation_done
128 */
129 OPC_STATE_FINISHED
130};
131
132
133/**
134 * Context information for GNUNET_TESTBED_Operation
135 */
136struct OperationContext
137{
138 /**
139 * The controller to which this operation context belongs to
140 */
141 struct GNUNET_TESTBED_Controller *c;
142
143 /**
144 * The operation
145 */
146 struct GNUNET_TESTBED_Operation *op;
147
148 /**
149 * The operation closure
150 */
151 void *op_cls;
152
153 /**
154 * Data relevant to the operation
155 */
156 void *data;
157
158 /**
159 * The id of the operation
160 */
161 uint64_t id;
162
163 /**
164 * The type of operation
165 */
166 enum OperationType type;
167
168 /**
169 * The state of the operation
170 */
171 enum OperationContextState state;
172};
173
174
175/**
176 * Operation empty callback
177 *
178 * @param cls closure
179 */
180typedef void
181(*TESTBED_opcq_empty_cb) (void *cls);
182
183
184/**
185 * Handle to interact with a GNUnet testbed controller. Each
186 * controller has at least one master handle which is created when the
187 * controller is created; this master handle interacts with the
188 * controller process, destroying it destroys the controller (by
189 * closing stdin of the controller process). Additionally,
190 * controllers can interact with each other (in a P2P fashion); those
191 * links are established via TCP/IP on the controller's service port.
192 */
193struct GNUNET_TESTBED_Controller
194{
195 /**
196 * The host where the controller is running
197 */
198 struct GNUNET_TESTBED_Host *host;
199
200 /**
201 * The controller callback
202 */
203 GNUNET_TESTBED_ControllerCallback cc;
204
205 /**
206 * The closure for controller callback
207 */
208 void *cc_cls;
209
210 /**
211 * The configuration to use while connecting to controller
212 */
213 struct GNUNET_CONFIGURATION_Handle *cfg;
214
215 /**
216 * The message queue to the controller service
217 */
218 struct GNUNET_MQ_Handle *mq;
219
220 /**
221 * The host registration handle; NULL if no current registration requests are
222 * present
223 */
224 struct GNUNET_TESTBED_HostRegistrationHandle *rh;
225
226 /**
227 * The map of active operation contexts
228 */
229 struct GNUNET_CONTAINER_MultiHashMap32 *opc_map;
230
231 /**
232 * If this callback is not NULL, schedule it as a task when opc_map gets empty
233 */
234 TESTBED_opcq_empty_cb opcq_empty_cb;
235
236 /**
237 * Closure for the above task
238 */
239 void *opcq_empty_cls;
240
241 /**
242 * Operation queue for simultaneous operations
243 */
244 struct OperationQueue *opq_parallel_operations;
245
246 /**
247 * Operation queue for simultaneous service connections
248 */
249 struct OperationQueue *opq_parallel_service_connections;
250
251 /**
252 * Operation queue for simultaneous topology configuration operations
253 */
254 struct OperationQueue *opq_parallel_topology_config_operations;
255
256 /**
257 * handle for hashtable of barrier handles, values are
258 * of type `struct GNUNET_TESTBED_Barrier`.
259 */
260 struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
261
262 /**
263 * The controller event mask
264 */
265 uint64_t event_mask;
266
267 /**
268 * The operation id counter. use current value and increment
269 */
270 uint32_t operation_counter;
271};
272
273
274/**
275 * Handle for barrier
276 */
277struct GNUNET_TESTBED_Barrier
278{
279 /**
280 * hashcode identifying this barrier in the hashmap
281 */
282 struct GNUNET_HashCode key;
283
284 /**
285 * The controller handle given while initialising this barrier
286 */
287 struct GNUNET_TESTBED_Controller *c;
288
289 /**
290 * The name of the barrier
291 */
292 char *name;
293
294 /**
295 * The continuation callback to call when we have a status update on this
296 */
297 GNUNET_TESTBED_barrier_status_cb cb;
298
299 /**
300 * the closure for the above callback
301 */
302 void *cls;
303
304 /**
305 * Should the barrier crossed status message be echoed back to the controller?
306 */
307 int echo;
308};
309
310
311/**
312 * Queues a message in send queue for sending to the service
313 *
314 * @param controller the handle to the controller
315 * @param msg the message to queue
316 * @deprecated
317 */
318void
319GNUNET_TESTBED_queue_message_ (struct GNUNET_TESTBED_Controller *controller,
320 struct GNUNET_MessageHeader *msg);
321
322
323/**
324 * Inserts the given operation context into the operation context map of the
325 * given controller. Creates the operation context map if one does not exist
326 * for the controller
327 *
328 * @param c the controller
329 * @param opc the operation context to be inserted
330 */
331void
332GNUNET_TESTBED_insert_opc_ (struct GNUNET_TESTBED_Controller *c,
333 struct OperationContext *opc);
334
335
336/**
337 * Removes the given operation context from the operation context map of the
338 * given controller
339 *
340 * @param c the controller
341 * @param opc the operation context to remove
342 */
343void
344GNUNET_TESTBED_remove_opc_ (const struct GNUNET_TESTBED_Controller *c,
345 struct OperationContext *opc);
346
347
348/**
349 * Compresses given configuration using zlib compress
350 *
351 * @param config the serialized configuration
352 * @param size the size of config
353 * @param xconfig will be set to the compressed configuration (memory is fresly
354 * allocated)
355 * @return the size of the xconfig
356 */
357size_t
358GNUNET_TESTBED_compress_config_ (const char *config,
359 size_t size,
360 char **xconfig);
361
362
363/**
364 * Function to serialize and compress using zlib a configuration through a
365 * configuration handle
366 *
367 * @param cfg the configuration
368 * @param size the size of configuration when serialize. Will be set on success.
369 * @param xsize the sizeo of the compressed configuration. Will be set on success.
370 * @return the serialized and compressed configuration
371 */
372char *
373GNUNET_TESTBED_compress_cfg_ (const struct GNUNET_CONFIGURATION_Handle *cfg,
374 size_t *size,
375 size_t *xsize);
376
377
378/**
379 * Creates a helper initialization message. This function is here because we
380 * want to use this in testing
381 *
382 * @param trusted_ip the ip address of the controller which will be set as TRUSTED
383 * HOST(all connections form this ip are permitted by the testbed) when
384 * starting testbed controller at host. This can either be a single ip
385 * address or a network address in CIDR notation.
386 * @param hostname the hostname of the destination this message is intended for
387 * @param cfg the configuration that has to used to start the testbed service
388 * thru helper
389 * @return the initialization message
390 */
391struct GNUNET_TESTBED_HelperInit *
392GNUNET_TESTBED_create_helper_init_msg_ (const char *cname,
393 const char *hostname,
394 const struct
395 GNUNET_CONFIGURATION_Handle *cfg);
396
397
398/**
399 * Sends the given message as an operation. The given callback is called when a
400 * reply for the operation is available. Call
401 * GNUNET_TESTBED_forward_operation_msg_cancel_() to cleanup the returned
402 * operation context if the cc hasn't been called
403 *
404 * @param controller the controller to which the message has to be sent
405 * @param operation_id the operation id of the message
406 * @param msg the message to send
407 * @param cc the callback to call when reply is available
408 * @param cc_cls the closure for the above callback
409 * @return the operation context which can be used to cancel the forwarded
410 * operation
411 */
412struct OperationContext *
413GNUNET_TESTBED_forward_operation_msg_ (struct
414 GNUNET_TESTBED_Controller *controller,
415 uint64_t operation_id,
416 const struct GNUNET_MessageHeader *msg,
417 GNUNET_MQ_MessageCallback cc,
418 void *cc_cls);
419
420/**
421 * Function to cancel an operation created by simply forwarding an operation
422 * message.
423 *
424 * @param opc the operation context from GNUNET_TESTBED_forward_operation_msg_()
425 */
426void
427GNUNET_TESTBED_forward_operation_msg_cancel_ (struct OperationContext *opc);
428
429
430/**
431 * Generates configuration by uncompressing configuration in given message. The
432 * given message should be of the following types:
433 * #GNUNET_MESSAGE_TYPE_TESTBED_PEERCONFIG,
434 * #GNUNET_MESSAGE_TYPE_TESTBED_SLAVECONFIG
435 *
436 * @param msg the message containing compressed configuration
437 * @return handle to the parsed configuration
438 */
439struct GNUNET_CONFIGURATION_Handle *
440GNUNET_TESTBED_extract_config_ (const struct GNUNET_MessageHeader *msg);
441
442
443/**
444 * Checks the integrity of the OpeationFailureEventMessage and if good returns
445 * the error message it contains.
446 *
447 * @param msg the OperationFailureEventMessage
448 * @return the error message
449 */
450const char *
451GNUNET_TESTBED_parse_error_string_ (const struct
452 GNUNET_TESTBED_OperationFailureEventMessage
453 *msg);
454
455
456/**
457 * Function to return the operation id for a controller. The operation id is
458 * created from the controllers host id and its internal operation counter.
459 *
460 * @param controller the handle to the controller whose operation id has to be incremented
461 * @return the incremented operation id.
462 */
463uint64_t
464GNUNET_TESTBED_get_next_op_id (struct GNUNET_TESTBED_Controller *controller);
465
466
467/**
468 * Like GNUNET_TESTBED_get_slave_config(), however without the host registration
469 * check. Another difference is that this function takes the id of the slave
470 * host.
471 *
472 * @param op_cls the closure for the operation
473 * @param master the handle to master controller
474 * @param slave_host_id id of the host where the slave controller is running to
475 * the slave_host should remain valid until this operation is cancelled
476 * or marked as finished
477 * @return the operation handle;
478 */
479struct GNUNET_TESTBED_Operation *
480GNUNET_TESTBED_get_slave_config_ (void *op_cls,
481 struct GNUNET_TESTBED_Controller *master,
482 uint32_t slave_host_id);
483
484
485/**
486 * Initialise a barrier and call the given callback when the required percentage
487 * of peers (quorum) reach the barrier OR upon error.
488 *
489 * @param controller the handle to the controller
490 * @param name identification name of the barrier
491 * @param quorum the percentage of peers that is required to reach the barrier.
492 * Peers signal reaching a barrier by calling
493 * GNUNET_TESTBED_barrier_reached().
494 * @param cb the callback to call when the barrier is reached or upon error.
495 * Cannot be NULL.
496 * @param cls closure for the above callback
497 * @param echo #GNUNET_YES to echo the barrier crossed status message back to the
498 * controller
499 * @return barrier handle; NULL upon error
500 */
501struct GNUNET_TESTBED_Barrier *
502GNUNET_TESTBED_barrier_init_ (struct GNUNET_TESTBED_Controller *controller,
503 const char *name,
504 unsigned int quorum,
505 GNUNET_TESTBED_barrier_status_cb cb,
506 void *cls,
507 int echo);
508
509
510/**
511 * Remove a barrier and it was the last one in the barrier hash map, destroy the
512 * hash map
513 *
514 * @param barrier the barrier to remove
515 */
516void
517GNUNET_TESTBED_barrier_remove_ (struct GNUNET_TESTBED_Barrier *barrier);
518
519
520#endif
521/* end of testbed_api.h */
diff --git a/src/testbed/testbed_api_barriers.c b/src/testbed/testbed_api_barriers.c
deleted file mode 100644
index 6074beb12..000000000
--- a/src/testbed/testbed_api_barriers.c
+++ /dev/null
@@ -1,253 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_barriers.c
23 * @brief API implementation for testbed barriers
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26#include "platform.h"
27#include "gnunet_testbed_service.h"
28#include "testbed_api.h"
29
30/**
31 * Logging shorthand
32 */
33#define LOG(type, ...) \
34 GNUNET_log_from (type, "testbed-api-barriers", __VA_ARGS__);
35
36/**
37 * Debug logging shorthand
38 */
39#define LOG_DEBUG(...) \
40 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
41
42
43/**
44 * Barrier wait handle
45 */
46struct GNUNET_TESTBED_BarrierWaitHandle
47{
48 /**
49 * The name of the barrier
50 */
51 char *name;
52
53 /**
54 * Then configuration used for the client connection
55 */
56 struct GNUNET_CONFIGURATION_Handle *cfg;
57
58 /**
59 * The testbed-barrier service message queue.
60 */
61 struct GNUNET_MQ_Handle *mq;
62
63 /**
64 * The barrier wait callback
65 */
66 GNUNET_TESTBED_barrier_wait_cb cb;
67
68 /**
69 * The closure for @e cb.
70 */
71 void *cb_cls;
72};
73
74
75/**
76 * Check if barrier status message is well-formed.
77 *
78 * @param cls closure
79 * @param msg received message
80 * @return #GNUNET_OK if the message is well-formed.
81 */
82static int
83check_status (void *cls,
84 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
85{
86 /* FIXME: this fails to actually check that the message
87 follows the protocol spec (0-terminations!). However,
88 not critical as #handle_status() doesn't interpret the
89 variable-size part anyway right now. */
90 return GNUNET_OK;
91}
92
93
94/**
95 * Type of a function to call when we receive a message
96 * from the service.
97 *
98 * @param cls closure
99 * @param msg received message
100 */
101static void
102handle_status (void *cls,
103 const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
104{
105 struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
106
107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
108 "Got barrier status %d\n",
109 (int) ntohs (msg->status));
110 switch (ntohs (msg->status))
111 {
112 case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
113 h->cb (h->cb_cls,
114 h->name,
115 GNUNET_SYSERR);
116 break;
117
118 case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
119 h->cb (h->cb_cls,
120 h->name,
121 GNUNET_SYSERR);
122 GNUNET_break (0);
123 break;
124
125 case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
126 h->cb (h->cb_cls,
127 h->name,
128 GNUNET_OK);
129 break;
130
131 default:
132 GNUNET_break_op (0);
133 h->cb (h->cb_cls,
134 h->name,
135 GNUNET_SYSERR);
136 break;
137 }
138 GNUNET_TESTBED_barrier_wait_cancel (h);
139}
140
141
142/**
143 * Generic error handler, called with the appropriate error code and
144 * the same closure specified at the creation of the message queue.
145 * Not every message queue implementation supports an error handler.
146 *
147 * @param cls closure with the `struct GNUNET_TESTBED_BarrierWaitHandle *`
148 * @param error error code
149 */
150static void
151mq_error_handler (void *cls,
152 enum GNUNET_MQ_Error error)
153{
154 struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
155
156 h->cb (h->cb_cls,
157 h->name,
158 GNUNET_SYSERR);
159 GNUNET_TESTBED_barrier_wait_cancel (h);
160}
161
162
163struct GNUNET_TESTBED_BarrierWaitHandle *
164GNUNET_TESTBED_barrier_wait (const char *name,
165 GNUNET_TESTBED_barrier_wait_cb cb,
166 void *cb_cls)
167{
168 struct GNUNET_TESTBED_BarrierWaitHandle *h
169 = GNUNET_new (struct GNUNET_TESTBED_BarrierWaitHandle);
170 struct GNUNET_MQ_MessageHandler handlers[] = {
171 GNUNET_MQ_hd_var_size (status,
172 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
173 struct GNUNET_TESTBED_BarrierStatusMsg,
174 h),
175 GNUNET_MQ_handler_end ()
176 };
177 struct GNUNET_MQ_Envelope *env;
178 struct GNUNET_TESTBED_BarrierWait *msg;
179 const char *cfg_filename;
180 size_t name_len;
181
182 GNUNET_assert (NULL != cb);
183 cfg_filename = getenv (ENV_TESTBED_CONFIG);
184 if (NULL == cfg_filename)
185 {
186 LOG (GNUNET_ERROR_TYPE_ERROR,
187 "Are you running under testbed?\n");
188 GNUNET_free (h);
189 return NULL;
190 }
191 h->cfg = GNUNET_CONFIGURATION_create ();
192 if (GNUNET_OK !=
193 GNUNET_CONFIGURATION_load (h->cfg,
194 cfg_filename))
195 {
196 LOG (GNUNET_ERROR_TYPE_ERROR,
197 "Unable to load configuration from file `%s'\n",
198 cfg_filename);
199 GNUNET_CONFIGURATION_destroy (h->cfg);
200 GNUNET_free (h);
201 return NULL;
202 }
203 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
204 "Waiting on barrier `%s'\n",
205 name);
206 h->name = GNUNET_strdup (name);
207 h->cb = cb;
208 h->cb_cls = cb_cls;
209 h->mq = GNUNET_CLIENT_connect (h->cfg,
210 "testbed-barrier",
211 handlers,
212 &mq_error_handler,
213 h);
214 if (NULL == h->mq)
215 {
216 LOG (GNUNET_ERROR_TYPE_ERROR,
217 "Unable to connect to local testbed-barrier service\n");
218 GNUNET_TESTBED_barrier_wait_cancel (h);
219 return NULL;
220 }
221 name_len = strlen (name); /* NOTE: unusual to not have 0-termination, change? */
222 env = GNUNET_MQ_msg_extra (msg,
223 name_len,
224 GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT);
225 GNUNET_memcpy (msg->name,
226 name,
227 name_len);
228 GNUNET_MQ_send (h->mq,
229 env);
230 return h;
231}
232
233
234/**
235 * Cancel a barrier wait handle
236 *
237 * @param h the barrier wait handle
238 */
239void
240GNUNET_TESTBED_barrier_wait_cancel (struct GNUNET_TESTBED_BarrierWaitHandle *h)
241{
242 if (NULL != h->mq)
243 {
244 GNUNET_MQ_destroy (h->mq);
245 h->mq = NULL;
246 }
247 GNUNET_free (h->name);
248 GNUNET_CONFIGURATION_destroy (h->cfg);
249 GNUNET_free (h);
250}
251
252
253/* end of testbed_api_barriers.c */
diff --git a/src/testbed/testbed_api_hosts.c b/src/testbed/testbed_api_hosts.c
deleted file mode 100644
index 824bd0187..000000000
--- a/src/testbed/testbed_api_hosts.c
+++ /dev/null
@@ -1,1520 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_hosts.c
23 * @brief API for manipulating 'hosts' controlled by the GNUnet testing service;
24 * allows parsing hosts files, starting, stopping and communicating (via
25 * SSH/stdin/stdout) with the remote (or local) processes
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_testbed_service.h"
31#include "gnunet_core_service.h"
32#include "gnunet_transport_service.h"
33
34#include "testbed_api.h"
35#include "testbed_api_hosts.h"
36#include "testbed_helper.h"
37#include "testbed_api_operations.h"
38
39#include <zlib.h>
40#include <regex.h>
41
42/**
43 * Generic logging shorthand
44 */
45#define LOG(kind, ...) GNUNET_log_from (kind, "testbed-api-hosts", __VA_ARGS__);
46
47/**
48 * Debug logging shorthand
49 */
50#define LOG_DEBUG(...) LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
51
52/**
53 * Prints API violation message
54 */
55#define API_VIOLATION(cond, errstr) \
56 do \
57 { \
58 if (cond) \
59 break; \
60 LOG (GNUNET_ERROR_TYPE_ERROR, "API violation detected: %s\n", errstr); \
61 GNUNET_assert (0); \
62 } while (0)
63
64/**
65 * Log an error message at log-level 'level' that indicates a failure of the
66 * command 'cmd' with the message given by gai_strerror(rc).
67 */
68#define LOG_GAI(level, cmd, rc) \
69 do \
70 { \
71 LOG (level, \
72 _ ("`%s' failed at %s:%d with error: %s\n"), \
73 cmd, \
74 __FILE__, \
75 __LINE__, \
76 gai_strerror (rc)); \
77 } while (0)
78
79/**
80 * Number of extra elements we create space for when we grow host list
81 */
82#define HOST_LIST_GROW_STEP 10
83
84
85/**
86 * A list entry for registered controllers list
87 */
88struct RegisteredController
89{
90 /**
91 * The controller at which this host is registered
92 */
93 const struct GNUNET_TESTBED_Controller *controller;
94
95 /**
96 * The next ptr for DLL
97 */
98 struct RegisteredController *next;
99
100 /**
101 * The prev ptr for DLL
102 */
103 struct RegisteredController *prev;
104};
105
106
107/**
108 * Opaque handle to a host running experiments managed by the testing framework.
109 * The master process must be able to SSH to this host without password (via
110 * ssh-agent).
111 */
112struct GNUNET_TESTBED_Host
113{
114 /**
115 * The hostname of the host; NULL for localhost
116 */
117 const char *hostname;
118
119 /**
120 * The username to be used for SSH login
121 */
122 const char *username;
123
124 /**
125 * the configuration to use as a template while starting a controller on this
126 * host. Operation queue size specific to a host are also read from this
127 * configuration handle. After starting the controller, it points to the actual
128 * configuration with which the controller is running
129 */
130 struct GNUNET_CONFIGURATION_Handle *cfg;
131
132 /**
133 * The head for the list of controllers where this host is registered
134 */
135 struct RegisteredController *rc_head;
136
137 /**
138 * The tail for the list of controllers where this host is registered
139 */
140 struct RegisteredController *rc_tail;
141
142 /**
143 * Operation queue for simultaneous overlay connect operations target at this
144 * host
145 */
146 struct OperationQueue *opq_parallel_overlay_connect_operations;
147
148 /**
149 * Is a controller started on this host? FIXME: Is this needed?
150 */
151 int controller_started;
152
153 /**
154 * Is this host locked by GNUNET_TESTBED_controller_start()?
155 */
156 int locked;
157
158 /**
159 * Global ID we use to refer to a host on the network
160 */
161 uint32_t id;
162
163 /**
164 * The port which is to be used for SSH
165 */
166 uint16_t port;
167};
168
169
170/**
171 * Array of available hosts
172 */
173static struct GNUNET_TESTBED_Host **host_list;
174
175/**
176 * The size of the available hosts list
177 */
178static unsigned int host_list_size;
179
180
181/**
182 * Lookup a host by ID.
183 *
184 * @param id global host ID assigned to the host; 0 is
185 * reserved to always mean 'localhost'
186 * @return handle to the host, NULL if host not found
187 */
188struct GNUNET_TESTBED_Host *
189GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id)
190{
191 if (host_list_size <= id)
192 return NULL;
193 return host_list[id];
194}
195
196
197/**
198 * Create a host by ID; given this host handle, we could not
199 * run peers at the host, but we can talk about the host
200 * internally.
201 *
202 * @param id global host ID assigned to the host; 0 is
203 * reserved to always mean 'localhost'
204 * @param cfg the configuration to use as a template while starting a controller
205 * on this host. Operation queue sizes specific to a host are also
206 * read from this configuration handle
207 * @return handle to the host, NULL on error
208 */
209struct GNUNET_TESTBED_Host *
210GNUNET_TESTBED_host_create_by_id_ (
211 uint32_t id,
212 const struct GNUNET_CONFIGURATION_Handle *cfg)
213{
214 return GNUNET_TESTBED_host_create_with_id (id, NULL, NULL, cfg, 0);
215}
216
217
218uint32_t
219GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host)
220{
221 return host->id;
222}
223
224
225/**
226 * Obtain the host's hostname.
227 *
228 * @param host handle to the host, NULL means 'localhost'
229 * @return hostname of the host
230 */
231const char *
232GNUNET_TESTBED_host_get_hostname (const struct GNUNET_TESTBED_Host *host)
233{
234 return host->hostname;
235}
236
237
238/**
239 * Obtain the host's username
240 *
241 * @param host handle to the host, NULL means 'localhost'
242 * @return username to login to the host
243 */
244const char *
245GNUNET_TESTBED_host_get_username_ (const struct GNUNET_TESTBED_Host *host)
246{
247 return host->username;
248}
249
250
251/**
252 * Obtain the host's ssh port
253 *
254 * @param host handle to the host, NULL means 'localhost'
255 * @return username to login to the host
256 */
257uint16_t
258GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host *host)
259{
260 return host->port;
261}
262
263
264/**
265 * Check whether a controller is already started on the given host
266 *
267 * @param host the handle to the host
268 * @return GNUNET_YES if the controller is already started; GNUNET_NO if not
269 */
270int
271GNUNET_TESTBED_host_controller_started (const struct GNUNET_TESTBED_Host *host)
272{
273 return host->controller_started;
274}
275
276
277/**
278 * Obtain the host's configuration template
279 *
280 * @param host handle to the host
281 * @return the host's configuration template
282 */
283const struct GNUNET_CONFIGURATION_Handle *
284GNUNET_TESTBED_host_get_cfg_ (const struct GNUNET_TESTBED_Host *host)
285{
286 return host->cfg;
287}
288
289
290/**
291 * Function to replace host's configuration
292 *
293 * @param host the host handle
294 * @param new_cfg the new configuration to replace the old one
295 */
296void
297GNUNET_TESTBED_host_replace_cfg_ (
298 struct GNUNET_TESTBED_Host *host,
299 const struct GNUNET_CONFIGURATION_Handle *new_cfg)
300{
301 GNUNET_CONFIGURATION_destroy (host->cfg);
302 host->cfg = GNUNET_CONFIGURATION_dup (new_cfg);
303}
304
305
306/**
307 * Create a host to run peers and controllers on.
308 *
309 * @param id global host ID assigned to the host; 0 is
310 * reserved to always mean 'localhost'
311 * @param hostname name of the host, use "NULL" for localhost
312 * @param username username to use for the login; may be NULL
313 * @param cfg the configuration to use as a template while starting a controller
314 * on this host. Operation queue sizes specific to a host are also
315 * read from this configuration handle
316 * @param port port number to use for ssh; use 0 to let ssh decide
317 * @return handle to the host, NULL on error
318 */
319struct GNUNET_TESTBED_Host *
320GNUNET_TESTBED_host_create_with_id (
321 uint32_t id,
322 const char *hostname,
323 const char *username,
324 const struct GNUNET_CONFIGURATION_Handle *cfg,
325 uint16_t port)
326{
327 struct GNUNET_TESTBED_Host *host;
328 unsigned int new_size;
329
330 if ((id < host_list_size) && (NULL != host_list[id]))
331 {
332 LOG (GNUNET_ERROR_TYPE_WARNING, "Host with id: %u already created\n", id);
333 return NULL;
334 }
335 host = GNUNET_new (struct GNUNET_TESTBED_Host);
336 host->hostname = (NULL != hostname) ? GNUNET_strdup (hostname) : NULL;
337 host->username = (NULL != username) ? GNUNET_strdup (username) : NULL;
338 host->id = id;
339 host->port = (0 == port) ? 22 : port;
340 host->cfg = GNUNET_CONFIGURATION_dup (cfg);
341 host->opq_parallel_overlay_connect_operations =
342 GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_ADAPTIVE,
343 UINT_MAX);
344 new_size = host_list_size;
345 while (id >= new_size)
346 new_size += HOST_LIST_GROW_STEP;
347 if (new_size != host_list_size)
348 GNUNET_array_grow (host_list, host_list_size, new_size);
349 GNUNET_assert (id < host_list_size);
350 LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding host with id: %u\n", host->id);
351 host_list[id] = host;
352 return host;
353}
354
355
356/**
357 * Create a host to run peers and controllers on.
358 *
359 * @param hostname name of the host, use "NULL" for localhost
360 * @param username username to use for the login; may be NULL
361 * @param cfg the configuration to use as a template while starting a controller
362 * on this host. Operation queue sizes specific to a host are also
363 * read from this configuration handle
364 * @param port port number to use for ssh; use 0 to let ssh decide
365 * @return handle to the host, NULL on error
366 */
367struct GNUNET_TESTBED_Host *
368GNUNET_TESTBED_host_create (const char *hostname,
369 const char *username,
370 const struct GNUNET_CONFIGURATION_Handle *cfg,
371 uint16_t port)
372{
373 static uint32_t uid_generator;
374
375 if (NULL == hostname)
376 return GNUNET_TESTBED_host_create_with_id (0,
377 hostname,
378 username,
379 cfg,
380 port);
381 return GNUNET_TESTBED_host_create_with_id (++uid_generator,
382 hostname,
383 username,
384 cfg,
385 port);
386}
387
388
389unsigned int
390GNUNET_TESTBED_hosts_load_from_file (
391 const char *filename,
392 const struct GNUNET_CONFIGURATION_Handle *cfg,
393 struct GNUNET_TESTBED_Host ***hosts)
394{
395 struct GNUNET_TESTBED_Host *starting_host;
396 char *data;
397 char *buf;
398 char *username;
399 char *hostname;
400 regex_t rex;
401 regmatch_t pmatch[6];
402 uint64_t fs;
403 short int port;
404 unsigned int offset;
405 unsigned int count;
406
407
408 GNUNET_assert (NULL != filename);
409 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
410 {
411 LOG (GNUNET_ERROR_TYPE_WARNING, _ ("Hosts file %s not found\n"), filename);
412 return 0;
413 }
414 if (GNUNET_OK !=
415 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
416 fs = 0;
417 if (0 == fs)
418 {
419 LOG (GNUNET_ERROR_TYPE_WARNING,
420 _ ("Hosts file %s has no data\n"),
421 filename);
422 return 0;
423 }
424 data = GNUNET_malloc (fs);
425 if (fs != GNUNET_DISK_fn_read (filename, data, fs))
426 {
427 GNUNET_free (data);
428 LOG (GNUNET_ERROR_TYPE_WARNING,
429 _ ("Hosts file %s cannot be read\n"),
430 filename);
431 return 0;
432 }
433 buf = data;
434 offset = 0;
435 starting_host = NULL;
436 count = 0;
437 /* refer RFC 952 and RFC 1123 for valid hostnames */
438 GNUNET_assert (0 == regcomp (&rex,
439 "^(([[:alnum:]]+)@)?" /* username */
440 "([[:alnum:]]+[-[:alnum:]_\\.]+)" /* hostname */
441 "(:([[:digit:]]{1,5}))?", /* port */
442 REG_EXTENDED | REG_ICASE));
443 while (offset < (fs - 1))
444 {
445 offset++;
446 if (((data[offset] == '\n')) && (buf != &data[offset]))
447 {
448 unsigned int size;
449
450 data[offset] = '\0';
451 username = NULL;
452 hostname = NULL;
453 port = 0;
454 if ((REG_NOMATCH == regexec (&rex, buf, 6, pmatch, 0)) ||
455 (-1 == pmatch[3].rm_so))
456 {
457 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
458 "Error reading line `%s' in hostfile\n",
459 buf);
460 buf = &data[offset + 1];
461 continue;
462 }
463 if (-1 != pmatch[2].rm_so)
464 {
465 size = pmatch[2].rm_eo - pmatch[2].rm_so;
466 username = GNUNET_malloc (size + 1);
467 GNUNET_assert (
468 0 != GNUNET_strlcpy (username, buf + pmatch[2].rm_so, size + 1));
469 }
470 if (-1 != pmatch[5].rm_so)
471 {
472 (void) sscanf (buf + pmatch[5].rm_so, "%5hd", &port);
473 }
474 size = pmatch[3].rm_eo - pmatch[3].rm_so;
475 hostname = GNUNET_malloc (size + 1);
476 GNUNET_assert (
477 0 != GNUNET_strlcpy (hostname, buf + pmatch[3].rm_so, size + 1));
478 LOG (GNUNET_ERROR_TYPE_DEBUG,
479 "Successfully read host %s, port %d and user %s from file\n",
480 (NULL == hostname) ? "NULL" : hostname,
481 port,
482 (NULL == username) ? "NULL" : username);
483 /* We store hosts in a static list; hence we only require the starting
484 * host pointer in that list to access the newly created list of hosts */
485 if (NULL == starting_host)
486 starting_host =
487 GNUNET_TESTBED_host_create (hostname, username, cfg, port);
488 else
489 (void) GNUNET_TESTBED_host_create (hostname, username, cfg, port);
490 count++;
491 GNUNET_free (username);
492 GNUNET_free (hostname);
493 buf = &data[offset + 1];
494 }
495 else if ((data[offset] == '\n') || (data[offset] == '\0'))
496 buf = &data[offset + 1];
497 }
498 regfree (&rex);
499 GNUNET_free (data);
500 if (NULL == starting_host)
501 return 0;
502 *hosts = GNUNET_malloc (sizeof(struct GNUNET_TESTBED_Host *) * count);
503 GNUNET_memcpy (*hosts,
504 &host_list[GNUNET_TESTBED_host_get_id_ (starting_host)],
505 sizeof(struct GNUNET_TESTBED_Host *) * count);
506 return count;
507}
508
509
510/**
511 * Resolves a hostname using getaddrinfo
512 *
513 * @param host the hostname
514 * @return the string representing the IPv4 address of the given host; NULL upon error
515 */
516const char *
517simple_resolve (const char *host)
518{
519 struct addrinfo *res;
520 const struct sockaddr_in *in_addr;
521 char *hostip;
522 struct addrinfo hint;
523 unsigned int rc;
524
525 hint.ai_family = AF_INET; /* IPv4 */
526 hint.ai_socktype = 0;
527 hint.ai_protocol = 0;
528 hint.ai_addrlen = 0;
529 hint.ai_addr = NULL;
530 hint.ai_canonname = NULL;
531 hint.ai_next = NULL;
532 hint.ai_flags = AI_NUMERICSERV;
533 res = NULL;
534 LOG_DEBUG ("Resolving [%s]\n", host);
535 if (0 != (rc = getaddrinfo (host, "22", &hint, &res)))
536 {
537 LOG_GAI (GNUNET_ERROR_TYPE_ERROR, "getaddrinfo", rc);
538 return NULL;
539 }
540 GNUNET_assert (NULL != res);
541 GNUNET_assert (NULL != res->ai_addr);
542 GNUNET_assert (sizeof(struct sockaddr_in) == res->ai_addrlen);
543 in_addr = (const struct sockaddr_in *) res->ai_addr;
544 hostip = inet_ntoa (in_addr->sin_addr);
545 GNUNET_assert (NULL != hostip);
546 freeaddrinfo (res);
547 LOG_DEBUG ("Resolved [%s] to [%s]\n", host, hostip);
548 return hostip;
549}
550
551
552/**
553 * Destroy a host handle. Must only be called once everything
554 * running on that host has been stopped.
555 *
556 * @param host handle to destroy
557 */
558void
559GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host)
560{
561 GNUNET_assert (host->id < host_list_size);
562 GNUNET_assert (host_list[host->id] == host);
563 host_list[host->id] = NULL;
564 /* clear registered controllers list */
565 for (struct RegisteredController *rc = host->rc_head;
566 NULL != rc;
567 rc = host->rc_head)
568 {
569 GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
570 GNUNET_free (rc);
571 }
572 GNUNET_free_nz ((char *) host->username);
573 GNUNET_free_nz ((char *) host->hostname);
574 GNUNET_TESTBED_operation_queue_destroy_ (
575 host->opq_parallel_overlay_connect_operations);
576 GNUNET_CONFIGURATION_destroy (host->cfg);
577 GNUNET_free (host);
578 while (host_list_size >= HOST_LIST_GROW_STEP)
579 {
580 uint32_t id;
581
582 for (id = host_list_size - 1; id > host_list_size - HOST_LIST_GROW_STEP;
583 id--)
584 if (NULL != host_list[id])
585 break;
586 if (id != host_list_size - HOST_LIST_GROW_STEP)
587 break;
588 if (NULL != host_list[id])
589 break;
590 host_list_size -= HOST_LIST_GROW_STEP;
591 }
592 host_list =
593 GNUNET_realloc (host_list,
594 sizeof(struct GNUNET_TESTBED_Host *) * host_list_size);
595}
596
597
598/**
599 * Marks a host as registered with a controller
600 *
601 * @param host the host to mark
602 * @param controller the controller at which this host is registered
603 */
604void
605GNUNET_TESTBED_mark_host_registered_at_ (
606 struct GNUNET_TESTBED_Host *host,
607 const struct GNUNET_TESTBED_Controller *const controller)
608{
609 struct RegisteredController *rc;
610
611 for (rc = host->rc_head; NULL != rc; rc = rc->next)
612 {
613 if (controller == rc->controller) /* already registered at controller */
614 {
615 GNUNET_break (0);
616 return;
617 }
618 }
619 rc = GNUNET_new (struct RegisteredController);
620 rc->controller = controller;
621 GNUNET_CONTAINER_DLL_insert_tail (host->rc_head, host->rc_tail, rc);
622}
623
624
625/**
626 * Unmarks a host registered at a controller
627 *
628 * @param host the host to unmark
629 * @param controller the controller at which this host has to be unmarked
630 */
631void
632GNUNET_TESTBED_deregister_host_at_ (
633 struct GNUNET_TESTBED_Host *host,
634 const struct GNUNET_TESTBED_Controller *const controller)
635{
636 struct RegisteredController *rc;
637
638 for (rc = host->rc_head; NULL != rc; rc = rc->next)
639 if (controller == rc->controller)
640 break;
641 if (NULL == rc)
642 {
643 GNUNET_break (0);
644 return;
645 }
646 GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
647 GNUNET_free (rc);
648}
649
650
651/**
652 * Checks whether a host has been registered
653 *
654 * @param host the host to check
655 * @param controller the controller at which host's registration is checked
656 * @return GNUNET_YES if registered; GNUNET_NO if not
657 */
658int
659GNUNET_TESTBED_is_host_registered_ (
660 const struct GNUNET_TESTBED_Host *host,
661 const struct GNUNET_TESTBED_Controller *const controller)
662{
663 struct RegisteredController *rc;
664
665 for (rc = host->rc_head; NULL != rc; rc = rc->next)
666 {
667 if (controller == rc->controller) /* already registered at controller */
668 {
669 return GNUNET_YES;
670 }
671 }
672 return GNUNET_NO;
673}
674
675
676/**
677 * Handle for controller process
678 */
679struct GNUNET_TESTBED_ControllerProc
680{
681 /**
682 * The process handle
683 */
684 struct GNUNET_HELPER_Handle *helper;
685
686 /**
687 * The arguments used to start the helper
688 */
689 char **helper_argv;
690
691 /**
692 * The host where the helper is run
693 */
694 struct GNUNET_TESTBED_Host *host;
695
696 /**
697 * The controller error callback
698 */
699 GNUNET_TESTBED_ControllerStatusCallback cb;
700
701 /**
702 * The closure for the above callback
703 */
704 void *cls;
705
706 /**
707 * The send handle for the helper
708 */
709 struct GNUNET_HELPER_SendHandle *shandle;
710
711 /**
712 * The message corresponding to send handle
713 */
714 struct GNUNET_MessageHeader *msg;
715};
716
717
718/**
719 * Function to copy NULL terminated list of arguments
720 *
721 * @param argv the NULL terminated list of arguments. Cannot be NULL.
722 * @return the copied NULL terminated arguments
723 */
724static char **
725copy_argv (const char *const *argv)
726{
727 char **argv_dup;
728 unsigned int argp;
729
730 GNUNET_assert (NULL != argv);
731 for (argp = 0; NULL != argv[argp]; argp++)
732 ;
733 argv_dup = GNUNET_malloc (sizeof(char *) * (argp + 1));
734 for (argp = 0; NULL != argv[argp]; argp++)
735 argv_dup[argp] = GNUNET_strdup (argv[argp]);
736 return argv_dup;
737}
738
739
740/**
741 * Function to join NULL terminated list of arguments
742 *
743 * @param argv1 the NULL terminated list of arguments. Cannot be NULL.
744 * @param argv2 the NULL terminated list of arguments. Cannot be NULL.
745 * @return the joined NULL terminated arguments
746 */
747static char **
748join_argv (const char *const *argv1, const char *const *argv2)
749{
750 char **argvj;
751 char *argv;
752 unsigned int carg;
753 unsigned int cnt;
754
755 carg = 0;
756 argvj = NULL;
757 for (cnt = 0; NULL != argv1[cnt]; cnt++)
758 {
759 argv = GNUNET_strdup (argv1[cnt]);
760 GNUNET_array_append (argvj, carg, argv);
761 }
762 for (cnt = 0; NULL != argv2[cnt]; cnt++)
763 {
764 argv = GNUNET_strdup (argv2[cnt]);
765 GNUNET_array_append (argvj, carg, argv);
766 }
767 GNUNET_array_append (argvj, carg, NULL);
768 return argvj;
769}
770
771
772/**
773 * Frees the given NULL terminated arguments
774 *
775 * @param argv the NULL terminated list of arguments
776 */
777static void
778free_argv (char **argv)
779{
780 unsigned int argp;
781
782 for (argp = 0; NULL != argv[argp]; argp++)
783 GNUNET_free (argv[argp]);
784 GNUNET_free (argv);
785}
786
787
788/**
789 * Generates arguments for opening a remote shell. Builds up the arguments
790 * from the environment variable GNUNET_TESTBED_RSH_CMD. The variable
791 * should not mention `-p' (port) option and destination address as these will
792 * be set locally in the function from its parameteres. If the environmental
793 * variable is not found then it defaults to `ssh -o BatchMode=yes -o
794 * NoHostAuthenticationForLocalhost=yes -o StrictHostkeyChecking=no -o
795 * PasswordAuthentication=noc'
796 *
797 * @param port the destination port number
798 * @param hostname the hostname of the target host
799 * @param username the username to use while connecting to target host
800 * @return NULL terminated list of arguments
801 */
802static char **
803gen_rsh_args (const char *port, const char *hostname, const char *username)
804{
805 static const char *default_ssh_args[] =
806 { "ssh",
807 "-o",
808 "BatchMode=yes",
809 "-o",
810 "NoHostAuthenticationForLocalhost=yes",
811 "-o",
812 "StrictHostKeyChecking=no",
813 "-o",
814 "PasswordAuthentication=no",
815 "%h",
816 NULL };
817 char **ssh_args;
818 char *ssh_cmd;
819 char *ssh_cmd_cp;
820 char *arg;
821 const char *new_arg;
822 unsigned int size;
823 unsigned int cnt;
824
825 ssh_args = NULL;
826 if (NULL != (ssh_cmd = getenv ("GNUNET_TESTBED_RSH_CMD")))
827 {
828 ssh_cmd = GNUNET_strdup (ssh_cmd);
829 ssh_cmd_cp = ssh_cmd;
830 for (size = 0; NULL != (arg = strtok (ssh_cmd, " ")); ssh_cmd = NULL)
831 GNUNET_array_append (ssh_args, size, GNUNET_strdup (arg));
832 GNUNET_free (ssh_cmd_cp);
833 }
834 else
835 {
836 ssh_args = copy_argv (default_ssh_args);
837 size = (sizeof(default_ssh_args)) / (sizeof(const char *));
838 GNUNET_array_grow (ssh_args, size, size - 1);
839 }
840 for (cnt = 0; cnt < size; cnt++)
841 {
842 arg = ssh_args[cnt];
843 if ('%' != arg[0])
844 continue;
845 switch (arg[1])
846 {
847 case 'p':
848 new_arg = port;
849 break;
850
851 case 'u':
852 new_arg = username;
853 break;
854
855 case 'h':
856 new_arg = hostname;
857 break;
858
859 default:
860 continue;
861 }
862 if (NULL == new_arg)
863 continue;
864 GNUNET_free (arg);
865 ssh_args[cnt] = GNUNET_strdup (new_arg);
866 }
867 GNUNET_array_append (ssh_args, size, NULL);
868 return ssh_args;
869}
870
871
872/**
873 * Generates the arguments needed for executing the given binary in a remote
874 * shell. Builds the arguments from the environmental variable
875 * GNUNET_TETSBED_RSH_CMD_SUFFIX. If the environmental variable is not found,
876 * only the given binary name will be present in the returned arguments
877 *
878 * @param append_args the arguments to append after generating the suffix
879 * arguments. Can be NULL; if not must be NULL terminated 'char *' array
880 * @return NULL-terminated args
881 */
882static char **
883gen_rsh_suffix_args (const char *const *append_args)
884{
885 char **rshell_args;
886 char *rshell_cmd;
887 char *rshell_cmd_cp;
888 char *arg;
889 unsigned int cnt;
890 unsigned int append_cnt;
891
892 rshell_args = NULL;
893 cnt = 0;
894 if (NULL != (rshell_cmd = getenv ("GNUNET_TESTBED_RSH_CMD_SUFFIX")))
895 {
896 rshell_cmd = GNUNET_strdup (rshell_cmd);
897 rshell_cmd_cp = rshell_cmd;
898 for (; NULL != (arg = strtok (rshell_cmd, " ")); rshell_cmd = NULL)
899 GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (arg));
900 GNUNET_free (rshell_cmd_cp);
901 }
902 if (NULL != append_args)
903 {
904 for (append_cnt = 0; NULL != append_args[append_cnt]; append_cnt++)
905 GNUNET_array_append (rshell_args,
906 cnt,
907 GNUNET_strdup (append_args[append_cnt]));
908 }
909 GNUNET_array_append (rshell_args, cnt, NULL);
910 return rshell_args;
911}
912
913
914/**
915 * Functions with this signature are called whenever a
916 * complete message is received by the tokenizer.
917 *
918 * Do not call GNUNET_SERVER_mst_destroy in callback
919 *
920 * @param cls closure
921 * @param message the actual message
922 *
923 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
924 */
925static int
926helper_mst (void *cls, const struct GNUNET_MessageHeader *message)
927{
928 struct GNUNET_TESTBED_ControllerProc *cp = cls;
929 const struct GNUNET_TESTBED_HelperReply *msg;
930 const char *hostname;
931 char *config;
932 uLongf config_size;
933 uLongf xconfig_size;
934
935 msg = (const struct GNUNET_TESTBED_HelperReply *) message;
936 GNUNET_assert (sizeof(struct GNUNET_TESTBED_HelperReply) <
937 ntohs (msg->header.size));
938 GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
939 ntohs (msg->header.type));
940 config_size = (uLongf) ntohs (msg->config_size);
941 xconfig_size = (uLongf) (ntohs (msg->header.size)
942 - sizeof(struct GNUNET_TESTBED_HelperReply));
943 config = GNUNET_malloc (config_size);
944 GNUNET_assert (Z_OK == uncompress ((Bytef *) config,
945 &config_size,
946 (const Bytef *) &msg[1],
947 xconfig_size));
948 /* Replace the configuration template present in the host with the
949 controller's running configuration */
950 GNUNET_CONFIGURATION_destroy (cp->host->cfg);
951 cp->host->cfg = GNUNET_CONFIGURATION_create ();
952 GNUNET_assert (GNUNET_CONFIGURATION_deserialize (cp->host->cfg,
953 config,
954 config_size,
955 NULL));
956 GNUNET_free (config);
957 if (NULL == (hostname = GNUNET_TESTBED_host_get_hostname (cp->host)))
958 hostname = "localhost";
959 /* Change the hostname so that we can connect to it */
960 GNUNET_CONFIGURATION_set_value_string (cp->host->cfg,
961 "testbed",
962 "hostname",
963 hostname);
964 cp->host->locked = GNUNET_NO;
965 cp->host->controller_started = GNUNET_YES;
966 cp->cb (cp->cls, cp->host->cfg, GNUNET_OK);
967 return GNUNET_OK;
968}
969
970
971/**
972 * Continuation function from GNUNET_HELPER_send()
973 *
974 * @param cls closure
975 * @param result GNUNET_OK on success,
976 * GNUNET_NO if helper process died
977 * GNUNET_SYSERR during GNUNET_HELPER_stop
978 */
979static void
980clear_msg (void *cls, int result)
981{
982 struct GNUNET_TESTBED_ControllerProc *cp = cls;
983
984 GNUNET_assert (NULL != cp->shandle);
985 cp->shandle = NULL;
986 GNUNET_free (cp->msg);
987 cp->msg = NULL;
988}
989
990
991/**
992 * Callback that will be called when the helper process dies. This is not called
993 * when the helper process is stopped using GNUNET_HELPER_stop()
994 *
995 * @param cls the closure from GNUNET_HELPER_start()
996 */
997static void
998helper_exp_cb (void *cls)
999{
1000 struct GNUNET_TESTBED_ControllerProc *cp = cls;
1001 GNUNET_TESTBED_ControllerStatusCallback cb;
1002 void *cb_cls;
1003
1004 cb = cp->cb;
1005 cb_cls = cp->cls;
1006 cp->helper = NULL;
1007 GNUNET_TESTBED_controller_stop (cp);
1008 if (NULL != cb)
1009 cb (cb_cls, NULL, GNUNET_SYSERR);
1010}
1011
1012
1013/**
1014 * Starts a controller process at the given host. The given host's configuration
1015 * is used as a Template configuration to use for the remote controller; the
1016 * remote controller will be started with a slightly modified configuration
1017 * (port numbers, unix domain sockets and service home values are changed as per
1018 * TESTING library on the remote host). The modified configuration replaces the
1019 * host's existing configuration before signalling success through the
1020 * GNUNET_TESTBED_ControllerStatusCallback()
1021 *
1022 * @param trusted_ip the ip address of the controller which will be set as TRUSTED
1023 * HOST(all connections form this ip are permitted by the testbed) when
1024 * starting testbed controller at host. This can either be a single ip
1025 * address or a network address in CIDR notation.
1026 * @param host the host where the controller has to be started. CANNOT be NULL.
1027 * @param cb function called when the controller is successfully started or
1028 * dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
1029 * called if cb is called with GNUNET_SYSERR as status. Will never be
1030 * called in the same task as 'GNUNET_TESTBED_controller_start'
1031 * (synchronous errors will be signalled by returning NULL). This
1032 * parameter cannot be NULL.
1033 * @param cls closure for above callbacks
1034 * @return the controller process handle, NULL on errors
1035 */
1036struct GNUNET_TESTBED_ControllerProc *
1037GNUNET_TESTBED_controller_start (const char *trusted_ip,
1038 struct GNUNET_TESTBED_Host *host,
1039 GNUNET_TESTBED_ControllerStatusCallback cb,
1040 void *cls)
1041{
1042 struct GNUNET_TESTBED_ControllerProc *cp;
1043 struct GNUNET_TESTBED_HelperInit *msg;
1044 const struct GNUNET_CONFIGURATION_Handle *cfg;
1045 const char *hostname;
1046 static char *const binary_argv[] = { HELPER_TESTBED_BINARY, NULL };
1047
1048 GNUNET_assert (NULL != host);
1049 GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
1050 hostname = NULL;
1051 API_VIOLATION (
1052 GNUNET_NO == host->locked,
1053 "Host is already locked by a previous call to GNUNET_TESTBED_controller_start()");
1054 host->locked = GNUNET_YES;
1055 API_VIOLATION (
1056 GNUNET_NO == host->controller_started,
1057 "Attempting to start a controller on a host which is already started a controller");
1058 cp = GNUNET_new (struct GNUNET_TESTBED_ControllerProc);
1059 if (0 == GNUNET_TESTBED_host_get_id_ (host))
1060 {
1061 cp->helper = GNUNET_HELPER_start (GNUNET_YES,
1062 HELPER_TESTBED_BINARY,
1063 binary_argv,
1064 &helper_mst,
1065 &helper_exp_cb,
1066 cp);
1067 }
1068 else
1069 {
1070 char *helper_binary_path_args[2];
1071 char **rsh_args;
1072 char **rsh_suffix_args;
1073 const char *username;
1074 char *port;
1075 char *argstr;
1076 char *aux;
1077 unsigned int cnt;
1078
1079 username = host->username;
1080 hostname = host->hostname;
1081 GNUNET_asprintf (&port, "%u", host->port);
1082 LOG_DEBUG ("Starting remote connection to destination %s\n", hostname);
1083 if (GNUNET_OK !=
1084 GNUNET_CONFIGURATION_get_value_filename (cfg,
1085 "testbed",
1086 "HELPER_BINARY_PATH",
1087 &helper_binary_path_args[0]))
1088 helper_binary_path_args[0] =
1089 GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
1090 helper_binary_path_args[1] = NULL;
1091 rsh_args = gen_rsh_args (port, hostname, username);
1092 rsh_suffix_args =
1093 gen_rsh_suffix_args ((const char **) helper_binary_path_args);
1094 cp->helper_argv =
1095 join_argv ((const char **) rsh_args, (const char **) rsh_suffix_args);
1096 free_argv (rsh_args);
1097 free_argv (rsh_suffix_args);
1098 GNUNET_free (port);
1099 argstr = GNUNET_strdup ("");
1100 for (cnt = 0; NULL != cp->helper_argv[cnt]; cnt++)
1101 {
1102 aux = argstr;
1103 GNUNET_assert (
1104 0 < GNUNET_asprintf (&argstr, "%s %s", aux, cp->helper_argv[cnt]));
1105 GNUNET_free (aux);
1106 }
1107 LOG_DEBUG ("Helper cmd str: %s\n", argstr);
1108 GNUNET_free (argstr);
1109 cp->helper = GNUNET_HELPER_start (GNUNET_NO,
1110 cp->helper_argv[0],
1111 cp->helper_argv,
1112 &helper_mst,
1113 &helper_exp_cb,
1114 cp);
1115 GNUNET_free (helper_binary_path_args[0]);
1116 }
1117 if (NULL == cp->helper)
1118 {
1119 if (NULL != cp->helper_argv)
1120 free_argv (cp->helper_argv);
1121 GNUNET_free (cp);
1122 return NULL;
1123 }
1124 cp->host = host;
1125 cp->cb = cb;
1126 cp->cls = cls;
1127 msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, hostname, cfg);
1128 cp->msg = &msg->header;
1129 cp->shandle =
1130 GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
1131 if (NULL == cp->shandle)
1132 {
1133 GNUNET_free (msg);
1134 GNUNET_TESTBED_controller_stop (cp);
1135 return NULL;
1136 }
1137 return cp;
1138}
1139
1140
1141/**
1142 * Sends termination signal to the controller's helper process
1143 *
1144 * @param cproc the handle to the controller's helper process
1145 */
1146void
1147GNUNET_TESTBED_controller_kill_ (struct GNUNET_TESTBED_ControllerProc *cproc)
1148{
1149 if (NULL != cproc->shandle)
1150 GNUNET_HELPER_send_cancel (cproc->shandle);
1151 if (NULL != cproc->helper)
1152 GNUNET_HELPER_kill (cproc->helper, GNUNET_YES);
1153}
1154
1155
1156/**
1157 * Cleans-up the controller's helper process handle
1158 *
1159 * @param cproc the handle to the controller's helper process
1160 */
1161void
1162GNUNET_TESTBED_controller_destroy_ (struct GNUNET_TESTBED_ControllerProc *cproc)
1163{
1164 if (NULL != cproc->helper)
1165 {
1166 GNUNET_break (GNUNET_OK == GNUNET_HELPER_wait (cproc->helper));
1167 GNUNET_HELPER_destroy (cproc->helper);
1168 }
1169 if (NULL != cproc->helper_argv)
1170 free_argv (cproc->helper_argv);
1171 cproc->host->controller_started = GNUNET_NO;
1172 cproc->host->locked = GNUNET_NO;
1173 GNUNET_free (cproc->msg);
1174 GNUNET_free (cproc);
1175}
1176
1177
1178/**
1179 * Stop the controller process (also will terminate all peers and controllers
1180 * dependent on this controller). This function blocks until the testbed has
1181 * been fully terminated (!). The controller status cb from
1182 * GNUNET_TESTBED_controller_start() will not be called.
1183 *
1184 * @param cproc the controller process handle
1185 */
1186void
1187GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
1188{
1189 GNUNET_TESTBED_controller_kill_ (cproc);
1190 GNUNET_TESTBED_controller_destroy_ (cproc);
1191}
1192
1193
1194/**
1195 * The handle for whether a host is habitable or not
1196 */
1197struct GNUNET_TESTBED_HostHabitableCheckHandle
1198{
1199 /**
1200 * The host to check
1201 */
1202 const struct GNUNET_TESTBED_Host *host;
1203
1204 /**
1205 * The callback to call once we have the status
1206 */
1207 GNUNET_TESTBED_HostHabitableCallback cb;
1208
1209 /**
1210 * The callback closure
1211 */
1212 void *cb_cls;
1213
1214 /**
1215 * The process handle for the SSH process
1216 */
1217 struct GNUNET_OS_Process *auxp;
1218
1219 /**
1220 * The arguments used to start the helper
1221 */
1222 char **helper_argv;
1223
1224 /**
1225 * Task id for the habitability check task
1226 */
1227 struct GNUNET_SCHEDULER_Task *habitability_check_task;
1228
1229 /**
1230 * How long we wait before checking the process status. Should grow
1231 * exponentially
1232 */
1233 struct GNUNET_TIME_Relative wait_time;
1234};
1235
1236
1237/**
1238 * Task for checking whether a host is habitable or not
1239 *
1240 * @param cls GNUNET_TESTBED_HostHabitableCheckHandle
1241 */
1242static void
1243habitability_check (void *cls)
1244{
1245 struct GNUNET_TESTBED_HostHabitableCheckHandle *h = cls;
1246 void *cb_cls;
1247 GNUNET_TESTBED_HostHabitableCallback cb;
1248 const struct GNUNET_TESTBED_Host *host;
1249 unsigned long code;
1250 enum GNUNET_OS_ProcessStatusType type;
1251 int ret;
1252
1253 h->habitability_check_task = NULL;
1254 ret = GNUNET_OS_process_status (h->auxp, &type, &code);
1255 if (GNUNET_SYSERR == ret)
1256 {
1257 GNUNET_break (0);
1258 ret = GNUNET_NO;
1259 goto call_cb;
1260 }
1261 if (GNUNET_NO == ret)
1262 {
1263 h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
1264 h->habitability_check_task =
1265 GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
1266 return;
1267 }
1268 GNUNET_OS_process_destroy (h->auxp);
1269 h->auxp = NULL;
1270 ret = (0 != code) ? GNUNET_NO : GNUNET_YES;
1271
1272 call_cb:
1273 if (NULL != h->auxp)
1274 GNUNET_OS_process_destroy (h->auxp);
1275 cb = h->cb;
1276 cb_cls = h->cb_cls;
1277 host = h->host;
1278 free_argv (h->helper_argv);
1279 GNUNET_free (h);
1280 if (NULL != cb)
1281 cb (cb_cls, host, ret);
1282}
1283
1284
1285/**
1286 * Checks whether a host can be used to start testbed service
1287 *
1288 * @param host the host to check
1289 * @param config the configuration handle to lookup the path of the testbed
1290 * helper
1291 * @param cb the callback to call to inform about habitability of the given host
1292 * @param cb_cls the closure for the callback
1293 * @return NULL upon any error or a handle which can be passed to
1294 * GNUNET_TESTBED_is_host_habitable_cancel()
1295 */
1296struct GNUNET_TESTBED_HostHabitableCheckHandle *
1297GNUNET_TESTBED_is_host_habitable (
1298 const struct GNUNET_TESTBED_Host *host,
1299 const struct GNUNET_CONFIGURATION_Handle *config,
1300 GNUNET_TESTBED_HostHabitableCallback cb,
1301 void *cb_cls)
1302{
1303 struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
1304 char **rsh_args;
1305 char **rsh_suffix_args;
1306 char *stat_args[3];
1307 const char *hostname;
1308 char *port;
1309
1310 h = GNUNET_new (struct GNUNET_TESTBED_HostHabitableCheckHandle);
1311 h->cb = cb;
1312 h->cb_cls = cb_cls;
1313 h->host = host;
1314 hostname = (NULL == host->hostname) ? "127.0.0.1" : host->hostname;
1315 if (GNUNET_OK !=
1316 GNUNET_CONFIGURATION_get_value_filename (config,
1317 "testbed",
1318 "HELPER_BINARY_PATH",
1319 &stat_args[1]))
1320 stat_args[1] = GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
1321 GNUNET_asprintf (&port, "%u", host->port);
1322 rsh_args = gen_rsh_args (port, hostname, host->username);
1323 GNUNET_free (port);
1324 port = NULL;
1325 stat_args[0] = "stat";
1326 stat_args[2] = NULL;
1327 rsh_suffix_args = gen_rsh_suffix_args ((const char **) stat_args);
1328 GNUNET_free (stat_args[1]);
1329 h->helper_argv =
1330 join_argv ((const char **) rsh_args, (const char **) rsh_suffix_args);
1331 free_argv (rsh_suffix_args);
1332 free_argv (rsh_args);
1333 h->auxp = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ERR,
1334 NULL,
1335 NULL,
1336 NULL,
1337 h->helper_argv[0],
1338 h->helper_argv);
1339 if (NULL == h->auxp)
1340 {
1341 GNUNET_break (0); /* Cannot exec SSH? */
1342 GNUNET_free (h);
1343 return NULL;
1344 }
1345 h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
1346 h->habitability_check_task =
1347 GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
1348 return h;
1349}
1350
1351
1352/**
1353 * Function to cancel a request started using GNUNET_TESTBED_is_host_habitable()
1354 *
1355 * @param handle the habitability check handle
1356 */
1357void
1358GNUNET_TESTBED_is_host_habitable_cancel (
1359 struct GNUNET_TESTBED_HostHabitableCheckHandle *handle)
1360{
1361 GNUNET_SCHEDULER_cancel (handle->habitability_check_task);
1362 (void) GNUNET_OS_process_kill (handle->auxp, GNUNET_TERM_SIG);
1363 (void) GNUNET_OS_process_wait (handle->auxp);
1364 GNUNET_OS_process_destroy (handle->auxp);
1365 free_argv (handle->helper_argv);
1366 GNUNET_free (handle);
1367}
1368
1369
1370/**
1371 * Register a host with the controller
1372 *
1373 * @param controller the controller handle
1374 * @param host the host to register
1375 * @param cc the completion callback to call to inform the status of
1376 * registration. After calling this callback the registration handle
1377 * will be invalid. Cannot be NULL.
1378 * @param cc_cls the closure for the cc
1379 * @return handle to the host registration which can be used to cancel the
1380 * registration
1381 */
1382struct GNUNET_TESTBED_HostRegistrationHandle *
1383GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
1384 struct GNUNET_TESTBED_Host *host,
1385 GNUNET_TESTBED_HostRegistrationCompletion cc,
1386 void *cc_cls)
1387{
1388 struct GNUNET_TESTBED_HostRegistrationHandle *rh;
1389 struct GNUNET_TESTBED_AddHostMessage *msg;
1390 const char *username;
1391 const char *hostname;
1392 char *config;
1393 char *cconfig;
1394 void *ptr;
1395 size_t cc_size;
1396 size_t config_size;
1397 uint16_t msg_size;
1398 uint16_t username_length;
1399 uint16_t hostname_length;
1400
1401 if (NULL != controller->rh)
1402 return NULL;
1403 hostname = GNUNET_TESTBED_host_get_hostname (host);
1404 if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
1405 {
1406 LOG (GNUNET_ERROR_TYPE_WARNING,
1407 "Host hostname: %s already registered\n",
1408 (NULL == hostname) ? "localhost" : hostname);
1409 return NULL;
1410 }
1411 rh = GNUNET_new (struct GNUNET_TESTBED_HostRegistrationHandle);
1412 rh->host = host;
1413 rh->c = controller;
1414 GNUNET_assert (NULL != cc);
1415 rh->cc = cc;
1416 rh->cc_cls = cc_cls;
1417 controller->rh = rh;
1418 username = GNUNET_TESTBED_host_get_username_ (host);
1419 username_length = 0;
1420 if (NULL != username)
1421 username_length = strlen (username);
1422 GNUNET_assert (NULL != hostname); /* Hostname must be present */
1423 hostname_length = strlen (hostname);
1424 GNUNET_assert (NULL != host->cfg);
1425 config = GNUNET_CONFIGURATION_serialize (host->cfg, &config_size);
1426 cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
1427 GNUNET_free (config);
1428 msg_size = (sizeof(struct GNUNET_TESTBED_AddHostMessage));
1429 msg_size += username_length;
1430 msg_size += hostname_length;
1431 msg_size += cc_size;
1432 msg = GNUNET_malloc (msg_size);
1433 msg->header.size = htons (msg_size);
1434 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST);
1435 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
1436 msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
1437 ptr = &msg[1];
1438 if (NULL != username)
1439 {
1440 msg->username_length = htons (username_length);
1441 GNUNET_memcpy (ptr, username, username_length);
1442 ptr += username_length;
1443 }
1444 msg->hostname_length = htons (hostname_length);
1445 GNUNET_memcpy (ptr, hostname, hostname_length);
1446 ptr += hostname_length;
1447 msg->config_size = htons (config_size);
1448 GNUNET_memcpy (ptr, cconfig, cc_size);
1449 ptr += cc_size;
1450 GNUNET_assert ((ptr - (void *) msg) == msg_size);
1451 GNUNET_free (cconfig);
1452 GNUNET_TESTBED_queue_message_ (controller,
1453 (struct GNUNET_MessageHeader *) msg);
1454 return rh;
1455}
1456
1457
1458/**
1459 * Cancel the pending registration. Note that if the registration message is
1460 * already sent to the service the cancellation has only the effect that the
1461 * registration completion callback for the registration is never called.
1462 *
1463 * @param handle the registration handle to cancel
1464 */
1465void
1466GNUNET_TESTBED_cancel_registration (
1467 struct GNUNET_TESTBED_HostRegistrationHandle *handle)
1468{
1469 if (handle != handle->c->rh)
1470 {
1471 GNUNET_break (0);
1472 return;
1473 }
1474 handle->c->rh = NULL;
1475 GNUNET_free (handle);
1476}
1477
1478
1479/**
1480 * Queues the given operation in the queue for parallel overlay connects of the
1481 * given host
1482 *
1483 * @param h the host handle
1484 * @param op the operation to queue in the given host's parally overlay connect
1485 * queue
1486 */
1487void
1488GNUNET_TESTBED_host_queue_oc_ (struct GNUNET_TESTBED_Host *h,
1489 struct GNUNET_TESTBED_Operation *op)
1490{
1491 GNUNET_TESTBED_operation_queue_insert_ (
1492 h->opq_parallel_overlay_connect_operations,
1493 op);
1494}
1495
1496
1497/**
1498 * Resolves the hostname of the host to an ip address
1499 *
1500 * @param host the host whose hostname is to be resolved
1501 */
1502void
1503GNUNET_TESTBED_host_resolve_ (struct GNUNET_TESTBED_Host *host)
1504{
1505 char *hostname;
1506
1507 hostname = (char *) host->hostname;
1508 host->hostname = simple_resolve (hostname);
1509 if (NULL == host->hostname)
1510 {
1511 GNUNET_break (0);
1512 host->hostname = hostname;
1513 return;
1514 }
1515 GNUNET_free (hostname);
1516 host->hostname = GNUNET_strdup (host->hostname);
1517}
1518
1519
1520/* end of testbed_api_hosts.c */
diff --git a/src/testbed/testbed_api_hosts.h b/src/testbed/testbed_api_hosts.h
deleted file mode 100644
index ab7dd8808..000000000
--- a/src/testbed/testbed_api_hosts.h
+++ /dev/null
@@ -1,227 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_hosts.h
23 * @brief internal API to access the 'hosts' subsystem
24 * @author Christian Grothoff
25 */
26
27#ifndef TESTBED_API_HOSTS_H
28#define TESTBED_API_HOSTS_H
29
30// #include "gnunet_testbed_service.h"
31// #include "testbed_helper.h"
32#include "testbed.h"
33
34
35/**
36 * handle for host registration
37 */
38struct GNUNET_TESTBED_HostRegistrationHandle
39{
40 /**
41 * The host being registered
42 */
43 struct GNUNET_TESTBED_Host *host;
44
45 /**
46 * The controller at which this host is being registered
47 */
48 struct GNUNET_TESTBED_Controller *c;
49
50 /**
51 * The Registration completion callback
52 */
53 GNUNET_TESTBED_HostRegistrationCompletion cc;
54
55 /**
56 * The closure for above callback
57 */
58 void *cc_cls;
59};
60
61
62/**
63 * Lookup a host by ID.
64 *
65 * @param id global host ID assigned to the host; 0 is
66 * reserved to always mean 'localhost'
67 * @return handle to the host, NULL on error
68 */
69struct GNUNET_TESTBED_Host *
70GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id);
71
72
73/**
74 * Create a host by ID; given this host handle, we could not
75 * run peers at the host, but we can talk about the host
76 * internally.
77 *
78 * @param id global host ID assigned to the host; 0 is
79 * reserved to always mean 'localhost'
80 * @param cfg the configuration to use as a template while starting a controller
81 * on this host. Operation queue sizes specific to a host are also
82 * read from this configuration handle
83 * @return handle to the host, NULL on error
84 */
85struct GNUNET_TESTBED_Host *
86GNUNET_TESTBED_host_create_by_id_ (uint32_t id,
87 const struct GNUNET_CONFIGURATION_Handle
88 *cfg);
89
90
91/**
92 * Obtain a host's unique global ID.
93 *
94 * @param host handle to the host, NULL means 'localhost'
95 * @return id global host ID assigned to the host (0 is
96 * 'localhost', but then obviously not globally unique)
97 */
98uint32_t
99GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host *host);
100
101
102/**
103 * Obtain the host's username
104 *
105 * @param host handle to the host, NULL means 'localhost'
106 * @return username to login to the host
107 */
108const char *
109GNUNET_TESTBED_host_get_username_ (const struct GNUNET_TESTBED_Host *host);
110
111
112/**
113 * Obtain the host's ssh port
114 *
115 * @param host handle to the host, NULL means 'localhost'
116 * @return username to login to the host
117 */
118uint16_t
119GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host *host);
120
121
122/**
123 * Obtain the host's configuration template
124 *
125 * @param host handle to the host
126 * @return the host's configuration template
127 */
128const struct GNUNET_CONFIGURATION_Handle *
129GNUNET_TESTBED_host_get_cfg_ (const struct GNUNET_TESTBED_Host *host);
130
131
132/**
133 * Function to replace host's configuration
134 *
135 * @param host the host handle
136 * @param new_cfg the new configuration to replace the old one
137 */
138void
139GNUNET_TESTBED_host_replace_cfg_ (struct GNUNET_TESTBED_Host *host,
140 const struct
141 GNUNET_CONFIGURATION_Handle *new_cfg);
142
143
144/**
145 * Marks a host as registered with a controller
146 *
147 * @param host the host to mark
148 * @param controller the controller at which this host is registered
149 */
150void
151GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
152 const struct GNUNET_TESTBED_Controller
153 *controller);
154
155
156/**
157 * Unmarks a host registered at a controller
158 *
159 * @param host the host to unmark
160 * @param controller the controller at which this host has to be unmarked
161 */
162void
163GNUNET_TESTBED_deregister_host_at_ (struct GNUNET_TESTBED_Host *host,
164 const struct GNUNET_TESTBED_Controller
165 *const controller);
166
167
168/**
169 * Checks whether a host has been registered with the given controller
170 *
171 * @param host the host to check
172 * @param controller the controller at which host's registration is checked
173 * @return GNUNET_YES if registered; GNUNET_NO if not
174 */
175int
176GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host,
177 const struct GNUNET_TESTBED_Controller
178 *controller);
179
180
181/**
182 * Queues the given operation in the queue for parallel overlay connects of the
183 * given host
184 *
185 * @param h the host handle
186 * @param op the operation to queue in the given host's parally overlay connect
187 * queue
188 */
189void
190GNUNET_TESTBED_host_queue_oc_ (struct GNUNET_TESTBED_Host *h,
191 struct GNUNET_TESTBED_Operation *op);
192
193
194/**
195 * Sends termination signal to the controller's helper process
196 *
197 * @param cproc the handle to the controller's helper process
198 */
199void
200GNUNET_TESTBED_controller_kill_ (struct GNUNET_TESTBED_ControllerProc *cproc);
201
202
203/**
204 * Cleans-up the controller's helper process handle
205 *
206 * @param cproc the handle to the controller's helper process
207 */
208void
209GNUNET_TESTBED_controller_destroy_ (struct GNUNET_TESTBED_ControllerProc
210 *cproc);
211
212
213/**
214 * Resolves the hostname of the host to an ip address
215 *
216 * @param host the host whose hostname is to be resolved
217 */
218void
219GNUNET_TESTBED_host_resolve_ (struct GNUNET_TESTBED_Host *host);
220
221void
222GNUNET_TESTBED_extract_cfg (struct GNUNET_TESTBED_Host *host, const struct
223 GNUNET_MessageHeader *message);
224
225
226#endif
227/* end of testbed_api_hosts.h */
diff --git a/src/testbed/testbed_api_operations.c b/src/testbed/testbed_api_operations.c
deleted file mode 100644
index ea7e71496..000000000
--- a/src/testbed/testbed_api_operations.c
+++ /dev/null
@@ -1,1379 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_operations.c
23 * @brief functions to manage operation queues
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
26 */
27
28#include "platform.h"
29#include "testbed_api_operations.h"
30#include "testbed_api_sd.h"
31
32/**
33 * The number of readings containing past operation's timing information that we
34 * keep track of for adaptive queues
35 */
36#define ADAPTIVE_QUEUE_DEFAULT_HISTORY 40
37
38/**
39 * The number of parallel operations we start with by default for adaptive
40 * queues
41 */
42#define ADAPTIVE_QUEUE_DEFAULT_MAX_ACTIVE 4
43
44/**
45 * An entry in the operation queue
46 */
47struct QueueEntry
48{
49 /**
50 * The next DLL pointer
51 */
52 struct QueueEntry *next;
53
54 /**
55 * The prev DLL pointer
56 */
57 struct QueueEntry *prev;
58
59 /**
60 * The operation this entry holds
61 */
62 struct GNUNET_TESTBED_Operation *op;
63
64 /**
65 * How many units of resources does the operation need
66 */
67 unsigned int nres;
68};
69
70
71/**
72 * Queue of operations where we can only support a certain
73 * number of concurrent operations of a particular type.
74 */
75struct OperationQueue;
76
77
78/**
79 * A slot to record time taken by an operation
80 */
81struct TimeSlot
82{
83 /**
84 * DLL next pointer
85 */
86 struct TimeSlot *next;
87
88 /**
89 * DLL prev pointer
90 */
91 struct TimeSlot *prev;
92
93 /**
94 * This operation queue to which this time slot belongs to
95 */
96 struct OperationQueue *queue;
97
98 /**
99 * The operation to which this timeslot is currently allocated to
100 */
101 struct GNUNET_TESTBED_Operation *op;
102
103 /**
104 * Accumulated time
105 */
106 struct GNUNET_TIME_Relative tsum;
107
108 /**
109 * Number of timing values accumulated
110 */
111 unsigned int nvals;
112};
113
114
115/**
116 * Context for operation queues of type OPERATION_QUEUE_TYPE_ADAPTIVE
117 */
118struct FeedbackCtx
119{
120 /**
121 * Handle for calculating standard deviation
122 */
123 struct SDHandle *sd;
124
125 /**
126 * Head for DLL of time slots which are free to be allocated to operations
127 */
128 struct TimeSlot *alloc_head;
129
130 /**
131 * Tail for DLL of time slots which are free to be allocated to operations
132 */
133 struct TimeSlot *alloc_tail;
134
135 /**
136 * Pointer to the chunk of time slots. Free all time slots at a time using
137 * this pointer.
138 */
139 struct TimeSlot *tslots_freeptr;
140
141 /**
142 * Number of time slots filled so far
143 */
144 unsigned int tslots_filled;
145
146 /**
147 * Bound on the maximum number of operations which can be active
148 */
149 unsigned int max_active_bound;
150
151 /**
152 * Number of operations that have failed
153 */
154 unsigned int nfailed;
155};
156
157
158/**
159 * Queue of operations where we can only support a certain
160 * number of concurrent operations of a particular type.
161 */
162struct OperationQueue
163{
164 /**
165 * DLL head for the wait queue. Operations which are waiting for this
166 * operation queue are put here
167 */
168 struct QueueEntry *wq_head;
169
170 /**
171 * DLL tail for the wait queue.
172 */
173 struct QueueEntry *wq_tail;
174
175 /**
176 * DLL head for the ready queue. Operations which are in this operation queue
177 * and are in ready state are put here
178 */
179 struct QueueEntry *rq_head;
180
181 /**
182 * DLL tail for the ready queue
183 */
184 struct QueueEntry *rq_tail;
185
186 /**
187 * DLL head for the active queue. Operations which are in this operation
188 * queue and are currently active are put here
189 */
190 struct QueueEntry *aq_head;
191
192 /**
193 * DLL tail for the active queue.
194 */
195 struct QueueEntry *aq_tail;
196
197 /**
198 * DLL head for the inactive queue. Operations which are inactive and can be
199 * evicted if the queues it holds are maxed out and another operation begins
200 * to wait on them.
201 */
202 struct QueueEntry *nq_head;
203
204 /**
205 * DLL tail for the inactive queue.
206 */
207 struct QueueEntry *nq_tail;
208
209 /**
210 * Feedback context; only relevant for adaptive operation queues. NULL for
211 * fixed operation queues
212 */
213 struct FeedbackCtx *fctx;
214
215 /**
216 * The type of this operation queue
217 */
218 enum OperationQueueType type;
219
220 /**
221 * Number of operations that are currently active in this queue.
222 */
223 unsigned int active;
224
225 /**
226 * Max number of operations which can be active at any time in this queue.
227 * This value can be changed either by calling
228 * GNUNET_TESTBED_operation_queue_reset_max_active_() or by the adaptive
229 * algorithm if this operation queue is of type #OPERATION_QUEUE_TYPE_ADAPTIVE
230 */
231 unsigned int max_active;
232
233 /**
234 * The number of resources occupied by failed operations in the current shot.
235 * This is only relevant if the operation queue is of type
236 * #OPERATION_QUEUE_TYPE_ADAPTIVE
237 */
238 unsigned int overload;
239
240 /**
241 * Is this queue marked for expiry?
242 */
243 unsigned int expired;
244};
245
246
247/**
248 * Operation state
249 */
250enum OperationState
251{
252 /**
253 * The operation is just created and is in initial state
254 */
255 OP_STATE_INIT,
256
257 /**
258 * The operation is currently waiting for resources
259 */
260 OP_STATE_WAITING,
261
262 /**
263 * The operation is ready to be started
264 */
265 OP_STATE_READY,
266
267 /**
268 * The operation has started and is active
269 */
270 OP_STATE_ACTIVE,
271
272 /**
273 * The operation is inactive. It still holds resources on the operation
274 * queues. However, this operation will be evicted when another operation
275 * requires resources from the maxed out queues this operation is holding
276 * resources from.
277 */
278 OP_STATE_INACTIVE
279};
280
281
282/**
283 * An entry in the ready queue (implemented as DLL)
284 */
285struct ReadyQueueEntry
286{
287 /**
288 * next ptr for DLL
289 */
290 struct ReadyQueueEntry *next;
291
292 /**
293 * prev ptr for DLL
294 */
295 struct ReadyQueueEntry *prev;
296
297 /**
298 * The operation associated with this entry
299 */
300 struct GNUNET_TESTBED_Operation *op;
301};
302
303
304/**
305 * Opaque handle to an abstract operation to be executed by the testing framework.
306 */
307struct GNUNET_TESTBED_Operation
308{
309 /**
310 * Function to call when we have the resources to begin the operation.
311 */
312 OperationStart start;
313
314 /**
315 * Function to call to clean up after the operation (which may or may
316 * not have been started yet).
317 */
318 OperationRelease release;
319
320 /**
321 * Closure for callbacks.
322 */
323 void *cb_cls;
324
325 /**
326 * Array of operation queues this Operation belongs to.
327 */
328 struct OperationQueue **queues;
329
330 /**
331 * Array of operation queue entries corresponding to this operation in
332 * operation queues for this operation
333 */
334 struct QueueEntry **qentries;
335
336 /**
337 * Array of number of resources an operation need from each queue. The numbers
338 * in this array should correspond to the queues array
339 */
340 unsigned int *nres;
341
342 /**
343 * Entry corresponding to this operation in ready queue. Will be NULL if the
344 * operation is not marked as READY
345 */
346 struct ReadyQueueEntry *rq_entry;
347
348 /**
349 * Head pointer for DLL of tslots allocated to this operation
350 */
351 struct TimeSlot *tslots_head;
352
353 /**
354 * Tail pointer for DLL of tslots allocated to this operation
355 */
356 struct TimeSlot *tslots_tail;
357
358 /**
359 * The time at which the operation is started
360 */
361 struct GNUNET_TIME_Absolute tstart;
362
363 /**
364 * Number of queues in the operation queues array
365 */
366 unsigned int nqueues;
367
368 /**
369 * The state of the operation
370 */
371 enum OperationState state;
372
373 /**
374 * Is this a failed operation?
375 */
376 int failed;
377};
378
379/**
380 * DLL head for the ready queue
381 */
382static struct ReadyQueueEntry *rq_head;
383
384/**
385 * DLL tail for the ready queue
386 */
387static struct ReadyQueueEntry *rq_tail;
388
389/**
390 * Array of operation queues which are to be destroyed
391 */
392static struct OperationQueue **expired_opqs;
393
394/**
395 * Number of expired operation queues in the above array
396 */
397static unsigned int n_expired_opqs;
398
399/**
400 * The id of the task to process the ready queue
401 */
402struct GNUNET_SCHEDULER_Task *process_rq_task_id;
403
404
405/**
406 * Assigns the given operation a time slot from the given operation queue
407 *
408 * @param op the operation
409 * @param queue the operation queue
410 * @return the timeslot
411 */
412static void
413assign_timeslot (struct GNUNET_TESTBED_Operation *op,
414 struct OperationQueue *queue)
415{
416 struct FeedbackCtx *fctx = queue->fctx;
417 struct TimeSlot *tslot;
418
419 GNUNET_assert (OPERATION_QUEUE_TYPE_ADAPTIVE == queue->type);
420 tslot = fctx->alloc_head;
421 GNUNET_assert (NULL != tslot);
422 GNUNET_CONTAINER_DLL_remove (fctx->alloc_head, fctx->alloc_tail, tslot);
423 GNUNET_CONTAINER_DLL_insert_tail (op->tslots_head, op->tslots_tail, tslot);
424 tslot->op = op;
425}
426
427
428/**
429 * Removes a queue entry of an operation from one of the operation queues' lists
430 * depending on the state of the operation
431 *
432 * @param op the operation whose entry has to be removed
433 * @param index the index of the entry in the operation's array of queue entries
434 */
435static void
436remove_queue_entry (struct GNUNET_TESTBED_Operation *op, unsigned int index)
437{
438 struct OperationQueue *opq;
439 struct QueueEntry *entry;
440
441 opq = op->queues[index];
442 entry = op->qentries[index];
443 switch (op->state)
444 {
445 case OP_STATE_INIT:
446 GNUNET_assert (0);
447 break;
448
449 case OP_STATE_WAITING:
450 GNUNET_CONTAINER_DLL_remove (opq->wq_head, opq->wq_tail, entry);
451 break;
452
453 case OP_STATE_READY:
454 GNUNET_CONTAINER_DLL_remove (opq->rq_head, opq->rq_tail, entry);
455 break;
456
457 case OP_STATE_ACTIVE:
458 GNUNET_CONTAINER_DLL_remove (opq->aq_head, opq->aq_tail, entry);
459 break;
460
461 case OP_STATE_INACTIVE:
462 GNUNET_CONTAINER_DLL_remove (opq->nq_head, opq->nq_tail, entry);
463 break;
464 }
465}
466
467
468/**
469 * Changes the state of the operation while moving its associated queue entries
470 * in the operation's operation queues
471 *
472 * @param op the operation whose state has to be changed
473 * @param state the state the operation should have. It cannot be OP_STATE_INIT
474 */
475static void
476change_state (struct GNUNET_TESTBED_Operation *op, enum OperationState state)
477{
478 struct QueueEntry *entry;
479 struct OperationQueue *opq;
480 unsigned int cnt;
481 unsigned int s;
482
483 GNUNET_assert (OP_STATE_INIT != state);
484 GNUNET_assert (NULL != op->queues);
485 GNUNET_assert (NULL != op->nres);
486 GNUNET_assert ((OP_STATE_INIT == op->state) || (NULL != op->qentries));
487 GNUNET_assert (op->state != state);
488 for (cnt = 0; cnt < op->nqueues; cnt++)
489 {
490 if (OP_STATE_INIT == op->state)
491 {
492 entry = GNUNET_new (struct QueueEntry);
493 entry->op = op;
494 entry->nres = op->nres[cnt];
495 s = cnt;
496 GNUNET_array_append (op->qentries, s, entry);
497 }
498 else
499 {
500 entry = op->qentries[cnt];
501 remove_queue_entry (op, cnt);
502 }
503 opq = op->queues[cnt];
504 switch (state)
505 {
506 case OP_STATE_INIT:
507 GNUNET_assert (0);
508 break;
509
510 case OP_STATE_WAITING:
511 GNUNET_CONTAINER_DLL_insert_tail (opq->wq_head, opq->wq_tail, entry);
512 break;
513
514 case OP_STATE_READY:
515 GNUNET_CONTAINER_DLL_insert_tail (opq->rq_head, opq->rq_tail, entry);
516 break;
517
518 case OP_STATE_ACTIVE:
519 GNUNET_CONTAINER_DLL_insert_tail (opq->aq_head, opq->aq_tail, entry);
520 break;
521
522 case OP_STATE_INACTIVE:
523 GNUNET_CONTAINER_DLL_insert_tail (opq->nq_head, opq->nq_tail, entry);
524 break;
525 }
526 }
527 op->state = state;
528}
529
530
531/**
532 * Removes an operation from the ready queue. Also stops the 'process_rq_task'
533 * if the given operation is the last one in the queue.
534 *
535 * @param op the operation to be removed
536 */
537static void
538rq_remove (struct GNUNET_TESTBED_Operation *op)
539{
540 GNUNET_assert (NULL != op->rq_entry);
541 GNUNET_CONTAINER_DLL_remove (rq_head, rq_tail, op->rq_entry);
542 GNUNET_free (op->rq_entry);
543 op->rq_entry = NULL;
544 if ((NULL == rq_head) && (NULL != process_rq_task_id))
545 {
546 GNUNET_SCHEDULER_cancel (process_rq_task_id);
547 process_rq_task_id = NULL;
548 }
549}
550
551
552/**
553 * Processes the ready queue by calling the operation start callback of the
554 * operation at the head. The operation is then removed from the queue. The
555 * task is scheduled to run again immediately until no more operations are in
556 * the ready queue.
557 *
558 * @param cls NULL
559 */
560static void
561process_rq_task (void *cls)
562{
563 struct GNUNET_TESTBED_Operation *op;
564 struct OperationQueue *queue;
565 unsigned int cnt;
566
567 process_rq_task_id = NULL;
568 GNUNET_assert (NULL != rq_head);
569 GNUNET_assert (NULL != (op = rq_head->op));
570 rq_remove (op);
571 if (NULL != rq_head)
572 process_rq_task_id = GNUNET_SCHEDULER_add_now (&process_rq_task, NULL);
573 change_state (op, OP_STATE_ACTIVE);
574 for (cnt = 0; cnt < op->nqueues; cnt++)
575 {
576 queue = op->queues[cnt];
577 if (OPERATION_QUEUE_TYPE_ADAPTIVE == queue->type)
578 assign_timeslot (op, queue);
579 }
580 op->tstart = GNUNET_TIME_absolute_get ();
581 if (NULL != op->start)
582 op->start (op->cb_cls);
583}
584
585
586/**
587 * Adds the operation to the ready queue and starts the 'process_rq_task'
588 *
589 * @param op the operation to be queued
590 */
591static void
592rq_add (struct GNUNET_TESTBED_Operation *op)
593{
594 struct ReadyQueueEntry *rq_entry;
595
596 GNUNET_assert (NULL == op->rq_entry);
597 rq_entry = GNUNET_new (struct ReadyQueueEntry);
598 rq_entry->op = op;
599 GNUNET_CONTAINER_DLL_insert_tail (rq_head, rq_tail, rq_entry);
600 op->rq_entry = rq_entry;
601 if (NULL == process_rq_task_id)
602 process_rq_task_id = GNUNET_SCHEDULER_add_now (&process_rq_task, NULL);
603}
604
605
606/**
607 * Checks if the given operation queue is empty or not
608 *
609 * @param opq the operation queue
610 * @return GNUNET_YES if the given operation queue has no operations; GNUNET_NO
611 * otherwise
612 */
613static int
614is_queue_empty (struct OperationQueue *opq)
615{
616 if ((NULL != opq->wq_head)
617 || (NULL != opq->rq_head)
618 || (NULL != opq->aq_head)
619 || (NULL != opq->nq_head))
620 return GNUNET_NO;
621 return GNUNET_YES;
622}
623
624
625/**
626 * Checks if the given operation queue has enough resources to provide for the
627 * operation of the given queue entry. It also checks if any inactive
628 * operations are to be released in order to accommodate the needed resources
629 * and returns them as an array.
630 *
631 * @param opq the operation queue to check for resource accommodation
632 * @param entry the operation queue entry whose operation's resources are to be
633 * accommodated
634 * @param ops_ pointer to return the array of operations which are to be released
635 * in order to accommodate the new operation. Can be NULL
636 * @param n_ops_ the number of operations in ops_
637 * @return GNUNET_YES if the given entry's operation can be accommodated in this
638 * queue. GNUNET_NO if it cannot be accommodated; ops_ and n_ops_ will
639 * be set to NULL and 0 respectively.
640 */
641static int
642decide_capacity (struct OperationQueue *opq,
643 struct QueueEntry *entry,
644 struct GNUNET_TESTBED_Operation ***ops_,
645 unsigned int *n_ops_)
646{
647 struct QueueEntry **evict_entries;
648 struct GNUNET_TESTBED_Operation **ops;
649 struct GNUNET_TESTBED_Operation *op;
650 unsigned int n_ops;
651 unsigned int n_evict_entries;
652 unsigned int need;
653 unsigned int max;
654 int deficit;
655 int rval;
656
657 GNUNET_assert (NULL != (op = entry->op));
658 GNUNET_assert (0 < (need = entry->nres));
659 ops = NULL;
660 n_ops = 0;
661 evict_entries = NULL;
662 n_evict_entries = 0;
663 rval = GNUNET_YES;
664 if (OPERATION_QUEUE_TYPE_ADAPTIVE == opq->type)
665 {
666 GNUNET_assert (NULL != opq->fctx);
667 GNUNET_assert (opq->max_active >= opq->overload);
668 max = opq->max_active - opq->overload;
669 }
670 else
671 max = opq->max_active;
672 if (opq->active > max)
673 {
674 rval = GNUNET_NO;
675 goto ret;
676 }
677 if ((opq->active + need) <= max)
678 goto ret;
679 deficit = need - (max - opq->active);
680 for (entry = opq->nq_head;
681 (0 < deficit) && (NULL != entry);
682 entry = entry->next)
683 {
684 GNUNET_array_append (evict_entries, n_evict_entries, entry);
685 deficit -= entry->nres;
686 }
687 if (0 < deficit)
688 {
689 rval = GNUNET_NO;
690 goto ret;
691 }
692 for (n_ops = 0; n_ops < n_evict_entries;)
693 {
694 op = evict_entries[n_ops]->op;
695 GNUNET_array_append (ops, n_ops, op); /* increments n-ops */
696 }
697
698ret:
699 GNUNET_free (evict_entries);
700 if (NULL != ops_)
701 *ops_ = ops;
702 else
703 GNUNET_free (ops);
704 if (NULL != n_ops_)
705 *n_ops_ = n_ops;
706 return rval;
707}
708
709
710/**
711 * Merges an array of operations into another, eliminating duplicates. No
712 * ordering is guaranteed.
713 *
714 * @param old the array into which the merging is done.
715 * @param n_old the number of operations in old array
716 * @param new the array from which operations are to be merged
717 * @param n_new the number of operations in new array
718 */
719static void
720merge_ops (struct GNUNET_TESTBED_Operation ***old,
721 unsigned int *n_old,
722 struct GNUNET_TESTBED_Operation **new,
723 unsigned int n_new)
724{
725 struct GNUNET_TESTBED_Operation **cur;
726 unsigned int i;
727 unsigned int j;
728 unsigned int n_cur;
729
730 GNUNET_assert (NULL != old);
731 n_cur = *n_old;
732 cur = *old;
733 for (i = 0; i < n_new; i++)
734 {
735 for (j = 0; j < *n_old; j++)
736 {
737 if (new[i] == cur[j])
738 break;
739 }
740 if (j < *n_old)
741 continue;
742 GNUNET_array_append (cur, n_cur, new[j]);
743 }
744 *old = cur;
745 *n_old = n_cur;
746}
747
748
749/**
750 * Checks for the readiness of an operation and schedules a operation start task
751 *
752 * @param op the operation
753 */
754static int
755check_readiness (struct GNUNET_TESTBED_Operation *op)
756{
757 struct GNUNET_TESTBED_Operation **evict_ops;
758 struct GNUNET_TESTBED_Operation **ops;
759 unsigned int n_ops;
760 unsigned int n_evict_ops;
761 unsigned int i;
762
763 GNUNET_assert (NULL == op->rq_entry);
764 GNUNET_assert (OP_STATE_WAITING == op->state);
765 evict_ops = NULL;
766 n_evict_ops = 0;
767 for (i = 0; i < op->nqueues; i++)
768 {
769 ops = NULL;
770 n_ops = 0;
771 if (GNUNET_NO == decide_capacity (op->queues[i], op->qentries[i],
772 &ops, &n_ops))
773 {
774 GNUNET_free (evict_ops);
775 return GNUNET_NO;
776 }
777 if (NULL == ops)
778 continue;
779 merge_ops (&evict_ops, &n_evict_ops, ops, n_ops);
780 GNUNET_free (ops);
781 }
782 if (NULL != evict_ops)
783 {
784 for (i = 0; i < n_evict_ops; i++)
785 GNUNET_TESTBED_operation_release_ (evict_ops[i]);
786 GNUNET_free (evict_ops);
787 evict_ops = NULL;
788 /* Evicting the operations should schedule this operation */
789 GNUNET_assert (OP_STATE_READY == op->state);
790 return GNUNET_YES;
791 }
792 for (i = 0; i < op->nqueues; i++)
793 op->queues[i]->active += op->nres[i];
794 change_state (op, OP_STATE_READY);
795 rq_add (op);
796 return GNUNET_YES;
797}
798
799
800/**
801 * Defers a ready to be executed operation back to waiting
802 *
803 * @param op the operation to defer
804 */
805static void
806defer (struct GNUNET_TESTBED_Operation *op)
807{
808 unsigned int i;
809
810 GNUNET_assert (OP_STATE_READY == op->state);
811 rq_remove (op);
812 for (i = 0; i < op->nqueues; i++)
813 {
814 GNUNET_assert (op->queues[i]->active >= op->nres[i]);
815 op->queues[i]->active -= op->nres[i];
816 }
817 change_state (op, OP_STATE_WAITING);
818}
819
820
821/**
822 * Cleanups the array of timeslots of an operation queue. For each time slot in
823 * the array, if it is allocated to an operation, it will be deallocated from
824 * the operation
825 *
826 * @param queue the operation queue
827 */
828static void
829cleanup_tslots (struct OperationQueue *queue)
830{
831 struct FeedbackCtx *fctx = queue->fctx;
832 struct TimeSlot *tslot;
833 struct GNUNET_TESTBED_Operation *op;
834 unsigned int cnt;
835
836 GNUNET_assert (NULL != fctx);
837 for (cnt = 0; cnt < queue->max_active; cnt++)
838 {
839 tslot = &fctx->tslots_freeptr[cnt];
840 op = tslot->op;
841 if (NULL == op)
842 continue;
843 GNUNET_CONTAINER_DLL_remove (op->tslots_head, op->tslots_tail, tslot);
844 }
845 GNUNET_free (fctx->tslots_freeptr);
846 fctx->tslots_freeptr = NULL;
847 fctx->alloc_head = NULL;
848 fctx->alloc_tail = NULL;
849 fctx->tslots_filled = 0;
850}
851
852
853/**
854 * Cleansup the existing timing slots and sets new timing slots in the given
855 * queue to accommodate given number of max active operations.
856 *
857 * @param queue the queue
858 * @param n the number of maximum active operations. If n is greater than the
859 * maximum limit set while creating the queue, then the minimum of these two
860 * will be selected as n
861 */
862static void
863adaptive_queue_set_max_active (struct OperationQueue *queue, unsigned int n)
864{
865 struct FeedbackCtx *fctx = queue->fctx;
866 struct TimeSlot *tslot;
867 unsigned int cnt;
868
869 cleanup_tslots (queue);
870 n = GNUNET_MIN (n, fctx->max_active_bound);
871 fctx->tslots_freeptr = GNUNET_malloc (n * sizeof(struct TimeSlot));
872 fctx->nfailed = 0;
873 for (cnt = 0; cnt < n; cnt++)
874 {
875 tslot = &fctx->tslots_freeptr[cnt];
876 tslot->queue = queue;
877 GNUNET_CONTAINER_DLL_insert_tail (fctx->alloc_head, fctx->alloc_tail,
878 tslot);
879 }
880 GNUNET_TESTBED_operation_queue_reset_max_active_ (queue, n);
881}
882
883
884/**
885 * Adapts parallelism in an adaptive queue by using the statistical data from
886 * the feedback context.
887 *
888 * @param queue the queue
889 */
890static void
891adapt_parallelism (struct OperationQueue *queue)
892{
893 struct GNUNET_TIME_Relative avg;
894 struct FeedbackCtx *fctx;
895 struct TimeSlot *tslot;
896 int sd;
897 unsigned int nvals;
898 unsigned int cnt;
899 unsigned int parallelism;
900
901 avg = GNUNET_TIME_UNIT_ZERO;
902 nvals = 0;
903 fctx = queue->fctx;
904 for (cnt = 0; cnt < queue->max_active; cnt++)
905 {
906 tslot = &fctx->tslots_freeptr[cnt];
907 avg = GNUNET_TIME_relative_add (avg, tslot->tsum);
908 nvals += tslot->nvals;
909 }
910 GNUNET_assert (nvals >= queue->max_active);
911 GNUNET_assert (fctx->nfailed <= nvals);
912 nvals -= fctx->nfailed;
913 if (0 == nvals)
914 {
915 if (1 == queue->max_active)
916 adaptive_queue_set_max_active (queue, 1);
917 else
918 adaptive_queue_set_max_active (queue, queue->max_active / 2);
919 return;
920 }
921 avg = GNUNET_TIME_relative_divide (avg, nvals);
922 GNUNET_TESTBED_SD_add_data_ (fctx->sd, (unsigned int) avg.rel_value_us);
923 if (GNUNET_SYSERR ==
924 GNUNET_TESTBED_SD_deviation_factor_ (fctx->sd,
925 (unsigned int) avg.rel_value_us,
926 &sd))
927 {
928 adaptive_queue_set_max_active (queue, queue->max_active); /* no change */
929 return;
930 }
931
932 parallelism = 0;
933 if (-1 == sd)
934 parallelism = queue->max_active + 1;
935 if (sd <= -2)
936 parallelism = queue->max_active * 2;
937 if (1 == sd)
938 parallelism = queue->max_active - 1;
939 if (2 <= sd)
940 parallelism = queue->max_active / 2;
941 parallelism = GNUNET_MAX (parallelism, ADAPTIVE_QUEUE_DEFAULT_MAX_ACTIVE);
942 adaptive_queue_set_max_active (queue, parallelism);
943
944#if 0
945 /* old algorithm */
946 if (sd < 0)
947 sd = 0;
948 GNUNET_assert (0 <= sd);
949 // GNUNET_TESTBED_SD_add_data_ (fctx->sd, (unsigned int) avg.rel_value_us);
950 if (0 == sd)
951 {
952 adaptive_queue_set_max_active (queue, queue->max_active * 2);
953 return;
954 }
955 if (1 == sd)
956 {
957 adaptive_queue_set_max_active (queue, queue->max_active + 1);
958 return;
959 }
960 if (1 == queue->max_active)
961 {
962 adaptive_queue_set_max_active (queue, 1);
963 return;
964 }
965 if (2 == sd)
966 {
967 adaptive_queue_set_max_active (queue, queue->max_active - 1);
968 return;
969 }
970 adaptive_queue_set_max_active (queue, queue->max_active / 2);
971#endif
972}
973
974
975/**
976 * update tslots with the operation's completion time. Additionally, if
977 * updating a timeslot makes all timeslots filled in an adaptive operation
978 * queue, call adapt_parallelism() for that queue.
979 *
980 * @param op the operation
981 */
982static void
983update_tslots (struct GNUNET_TESTBED_Operation *op)
984{
985 struct OperationQueue *queue;
986 struct GNUNET_TIME_Relative t;
987 struct TimeSlot *tslot;
988 struct FeedbackCtx *fctx;
989 unsigned int i;
990
991 t = GNUNET_TIME_absolute_get_duration (op->tstart);
992 while (NULL != (tslot = op->tslots_head)) /* update time slots */
993 {
994 queue = tslot->queue;
995 fctx = queue->fctx;
996 GNUNET_CONTAINER_DLL_remove (op->tslots_head, op->tslots_tail, tslot);
997 tslot->op = NULL;
998 GNUNET_CONTAINER_DLL_insert_tail (fctx->alloc_head, fctx->alloc_tail,
999 tslot);
1000 if (op->failed)
1001 {
1002 fctx->nfailed++;
1003 for (i = 0; i < op->nqueues; i++)
1004 if (queue == op->queues[i])
1005 break;
1006 GNUNET_assert (i != op->nqueues);
1007 op->queues[i]->overload += op->nres[i];
1008 }
1009 tslot->tsum = GNUNET_TIME_relative_add (tslot->tsum, t);
1010 if (0 != tslot->nvals++)
1011 continue;
1012 fctx->tslots_filled++;
1013 if (queue->max_active == fctx->tslots_filled)
1014 adapt_parallelism (queue);
1015 }
1016}
1017
1018
1019/**
1020 * Create an 'operation' to be performed.
1021 *
1022 * @param cls closure for the callbacks
1023 * @param start function to call to start the operation
1024 * @param release function to call to close down the operation
1025 * @return handle to the operation
1026 */
1027struct GNUNET_TESTBED_Operation *
1028GNUNET_TESTBED_operation_create_ (void *cls, OperationStart start,
1029 OperationRelease release)
1030{
1031 struct GNUNET_TESTBED_Operation *op;
1032
1033 op = GNUNET_new (struct GNUNET_TESTBED_Operation);
1034 op->start = start;
1035 op->state = OP_STATE_INIT;
1036 op->release = release;
1037 op->cb_cls = cls;
1038 return op;
1039}
1040
1041
1042struct OperationQueue *
1043GNUNET_TESTBED_operation_queue_create_ (enum OperationQueueType type,
1044 unsigned int max_active)
1045{
1046 struct OperationQueue *queue;
1047 struct FeedbackCtx *fctx;
1048
1049 queue = GNUNET_new (struct OperationQueue);
1050 queue->type = type;
1051 if (OPERATION_QUEUE_TYPE_FIXED == type)
1052 {
1053 queue->max_active = max_active;
1054 }
1055 else
1056 {
1057 fctx = GNUNET_new (struct FeedbackCtx);
1058 fctx->max_active_bound = max_active;
1059 fctx->sd = GNUNET_TESTBED_SD_init_ (ADAPTIVE_QUEUE_DEFAULT_HISTORY);
1060 queue->fctx = fctx;
1061 adaptive_queue_set_max_active (queue, ADAPTIVE_QUEUE_DEFAULT_MAX_ACTIVE);
1062 }
1063 return queue;
1064}
1065
1066
1067/**
1068 * Cleanup the given operation queue.
1069 *
1070 * @param queue the operation queue to destroy
1071 */
1072static void
1073queue_destroy (struct OperationQueue *queue)
1074{
1075 struct FeedbackCtx *fctx;
1076
1077 if (OPERATION_QUEUE_TYPE_ADAPTIVE == queue->type)
1078 {
1079 cleanup_tslots (queue);
1080 fctx = queue->fctx;
1081 GNUNET_TESTBED_SD_destroy_ (fctx->sd);
1082 GNUNET_free (fctx);
1083 }
1084 GNUNET_free (queue);
1085}
1086
1087
1088/**
1089 * Destroys an operation queue. If the queue is still in use by operations it
1090 * is marked as expired and its resources are released in the destructor
1091 * GNUNET_TESTBED_operations_fini().
1092 *
1093 * @param queue queue to destroy
1094 */
1095void
1096GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue)
1097{
1098 if (GNUNET_YES != is_queue_empty (queue))
1099 {
1100 GNUNET_assert (0 == queue->expired); /* Are you calling twice on same queue? */
1101 queue->expired = 1;
1102 GNUNET_array_append (expired_opqs, n_expired_opqs, queue);
1103 return;
1104 }
1105 queue_destroy (queue);
1106}
1107
1108
1109/**
1110 * Destroys the operation queue if it is empty. If not empty return GNUNET_NO.
1111 *
1112 * @param queue the queue to destroy if empty
1113 * @return GNUNET_YES if the queue is destroyed. GNUNET_NO if not (because it
1114 * is not empty)
1115 */
1116int
1117GNUNET_TESTBED_operation_queue_destroy_empty_ (struct OperationQueue *queue)
1118{
1119 if (GNUNET_NO == is_queue_empty (queue))
1120 return GNUNET_NO;
1121 GNUNET_TESTBED_operation_queue_destroy_ (queue);
1122 return GNUNET_YES;
1123}
1124
1125
1126/**
1127 * Rechecks if any of the operations in the given operation queue's waiting list
1128 * can be made active
1129 *
1130 * @param opq the operation queue
1131 */
1132static void
1133recheck_waiting (struct OperationQueue *opq)
1134{
1135 struct QueueEntry *entry;
1136 struct QueueEntry *entry2;
1137
1138 entry = opq->wq_head;
1139 while (NULL != entry)
1140 {
1141 entry2 = entry->next;
1142 if (GNUNET_NO == check_readiness (entry->op))
1143 break;
1144 entry = entry2;
1145 }
1146}
1147
1148
1149/**
1150 * Function to reset the maximum number of operations in the given queue. If
1151 * max_active is lesser than the number of currently active operations, the
1152 * active operations are not stopped immediately.
1153 *
1154 * @param queue the operation queue which has to be modified
1155 * @param max_active the new maximum number of active operations
1156 */
1157void
1158GNUNET_TESTBED_operation_queue_reset_max_active_ (struct OperationQueue *queue,
1159 unsigned int max_active)
1160{
1161 struct QueueEntry *entry;
1162
1163 queue->max_active = max_active;
1164 queue->overload = 0;
1165 while ((queue->active > queue->max_active)
1166 && (NULL != (entry = queue->rq_head)))
1167 defer (entry->op);
1168 recheck_waiting (queue);
1169}
1170
1171
1172/**
1173 * Add an operation to a queue. An operation can be in multiple queues at
1174 * once. Once the operation is inserted into all the queues
1175 * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
1176 * waiting for the operation to become active.
1177 *
1178 * @param queue queue to add the operation to
1179 * @param op operation to add to the queue
1180 * @param nres the number of units of the resources of queue needed by the
1181 * operation. Should be greater than 0.
1182 */
1183void
1184GNUNET_TESTBED_operation_queue_insert2_ (struct OperationQueue *queue,
1185 struct GNUNET_TESTBED_Operation *op,
1186 unsigned int nres)
1187{
1188 unsigned int qsize;
1189
1190 GNUNET_assert (0 < nres);
1191 qsize = op->nqueues;
1192 GNUNET_array_append (op->queues, op->nqueues, queue);
1193 GNUNET_array_append (op->nres, qsize, nres);
1194 GNUNET_assert (qsize == op->nqueues);
1195}
1196
1197
1198/**
1199 * Add an operation to a queue. An operation can be in multiple queues at
1200 * once. Once the operation is inserted into all the queues
1201 * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
1202 * waiting for the operation to become active. The operation is assumed to take
1203 * 1 queue resource. Use GNUNET_TESTBED_operation_queue_insert2_() if it
1204 * requires more than 1
1205 *
1206 * @param queue queue to add the operation to
1207 * @param op operation to add to the queue
1208 */
1209void
1210GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue,
1211 struct GNUNET_TESTBED_Operation *op)
1212{
1213 return GNUNET_TESTBED_operation_queue_insert2_ (queue, op, 1);
1214}
1215
1216
1217/**
1218 * Marks the given operation as waiting on the queues. Once all queues permit
1219 * the operation to become active, the operation will be activated. The actual
1220 * activation will occur in a separate task (thus allowing multiple queue
1221 * insertions to be made without having the first one instantly trigger the
1222 * operation if the first queue has sufficient resources).
1223 *
1224 * @param op the operation to marks as waiting
1225 */
1226void
1227GNUNET_TESTBED_operation_begin_wait_ (struct GNUNET_TESTBED_Operation *op)
1228{
1229 GNUNET_assert (NULL == op->rq_entry);
1230 change_state (op, OP_STATE_WAITING);
1231 (void) check_readiness (op);
1232}
1233
1234
1235/**
1236 * Marks an active operation as inactive - the operation will be kept in a
1237 * ready-to-be-released state and continues to hold resources until another
1238 * operation contents for them.
1239 *
1240 * @param op the operation to be marked as inactive. The operation start
1241 * callback should have been called before for this operation to mark
1242 * it as inactive.
1243 */
1244void
1245GNUNET_TESTBED_operation_inactivate_ (struct GNUNET_TESTBED_Operation *op)
1246{
1247 struct OperationQueue **queues;
1248 size_t ms;
1249 unsigned int nqueues;
1250 unsigned int i;
1251
1252 GNUNET_assert (OP_STATE_ACTIVE == op->state);
1253 change_state (op, OP_STATE_INACTIVE);
1254 nqueues = op->nqueues;
1255 ms = sizeof(struct OperationQueue *) * nqueues;
1256 queues = GNUNET_malloc (ms);
1257 /* Cloning is needed as the operation be released by waiting operations and
1258 hence its nqueues memory ptr will be freed */
1259 GNUNET_memcpy (queues, op->queues, ms);
1260 for (i = 0; i < nqueues; i++)
1261 recheck_waiting (queues[i]);
1262 GNUNET_free (queues);
1263}
1264
1265
1266/**
1267 * Marks and inactive operation as active. This function should be called to
1268 * ensure that the oprelease callback will not be called until it is either
1269 * marked as inactive or released.
1270 *
1271 * @param op the operation to be marked as active
1272 */
1273void
1274GNUNET_TESTBED_operation_activate_ (struct GNUNET_TESTBED_Operation *op)
1275{
1276 GNUNET_assert (OP_STATE_INACTIVE == op->state);
1277 change_state (op, OP_STATE_ACTIVE);
1278}
1279
1280
1281/**
1282 * An operation is 'done' (was cancelled or finished); remove
1283 * it from the queues and release associated resources.
1284 *
1285 * @param op operation that finished
1286 */
1287void
1288GNUNET_TESTBED_operation_release_ (struct GNUNET_TESTBED_Operation *op)
1289{
1290 struct QueueEntry *entry;
1291 struct OperationQueue *opq;
1292 unsigned int i;
1293
1294 if (OP_STATE_INIT == op->state)
1295 {
1296 GNUNET_free (op);
1297 return;
1298 }
1299 if (OP_STATE_READY == op->state)
1300 rq_remove (op);
1301 if (OP_STATE_INACTIVE == op->state) /* Activate the operation if inactive */
1302 GNUNET_TESTBED_operation_activate_ (op);
1303 if (OP_STATE_ACTIVE == op->state)
1304 update_tslots (op);
1305 GNUNET_assert (NULL != op->queues);
1306 GNUNET_assert (NULL != op->qentries);
1307 for (i = 0; i < op->nqueues; i++)
1308 {
1309 entry = op->qentries[i];
1310 remove_queue_entry (op, i);
1311 opq = op->queues[i];
1312 switch (op->state)
1313 {
1314 case OP_STATE_INIT:
1315 case OP_STATE_INACTIVE:
1316 GNUNET_assert (0);
1317 break;
1318
1319 case OP_STATE_WAITING:
1320 break;
1321
1322 case OP_STATE_ACTIVE:
1323 case OP_STATE_READY:
1324 GNUNET_assert (0 != opq->active);
1325 GNUNET_assert (opq->active >= entry->nres);
1326 opq->active -= entry->nres;
1327 recheck_waiting (opq);
1328 break;
1329 }
1330 GNUNET_free (entry);
1331 }
1332 GNUNET_free (op->qentries);
1333 GNUNET_free (op->queues);
1334 GNUNET_free (op->nres);
1335 if (NULL != op->release)
1336 op->release (op->cb_cls);
1337 GNUNET_free (op);
1338}
1339
1340
1341/**
1342 * Marks an operation as failed
1343 *
1344 * @param op the operation to be marked as failed
1345 */
1346void
1347GNUNET_TESTBED_operation_mark_failed (struct GNUNET_TESTBED_Operation *op)
1348{
1349 op->failed = GNUNET_YES;
1350}
1351
1352
1353/**
1354 * Cleanup expired operation queues. While doing so, also check for any
1355 * operations which are not completed and warn about them.
1356 */
1357void __attribute__ ((destructor))
1358GNUNET_TESTBED_operations_fini ()
1359{
1360 struct OperationQueue *queue;
1361 unsigned int i;
1362 int warn = 0;
1363
1364 for (i = 0; i < n_expired_opqs; i++)
1365 {
1366 queue = expired_opqs[i];
1367 if (GNUNET_NO == is_queue_empty (queue))
1368 warn = 1;
1369 queue_destroy (queue);
1370 }
1371 GNUNET_free (expired_opqs);
1372 n_expired_opqs = 0;
1373 if (warn)
1374 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1375 "Be disciplined. Some operations were not marked as done.\n");
1376}
1377
1378
1379/* end of testbed_api_operations.c */
diff --git a/src/testbed/testbed_api_operations.h b/src/testbed/testbed_api_operations.h
deleted file mode 100644
index 7d6659837..000000000
--- a/src/testbed/testbed_api_operations.h
+++ /dev/null
@@ -1,233 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_operations.h
23 * @brief internal API to access the 'operations' subsystem
24 * @author Christian Grothoff
25 */
26#ifndef NEW_TESTING_API_OPERATIONS_H
27#define NEW_TESTING_API_OPERATIONS_H
28
29#include "gnunet_testbed_service.h"
30#include "gnunet_util_lib.h"
31
32
33/**
34 * Queue of operations where we can only support a certain
35 * number of concurrent operations of a particular type.
36 */
37struct OperationQueue;
38
39
40/**
41 * The type of operation queue
42 */
43enum OperationQueueType
44{
45 /**
46 * Operation queue which permits a fixed maximum number of operations to be
47 * active at any time
48 */
49 OPERATION_QUEUE_TYPE_FIXED,
50
51 /**
52 * Operation queue which adapts the number of operations to be active based on
53 * the operation completion times of previously executed operation in it
54 */
55 OPERATION_QUEUE_TYPE_ADAPTIVE
56};
57
58
59/**
60 * Create an operation queue.
61 *
62 * @param type the type of operation queue
63 * @param max_active maximum number of operations in this
64 * queue that can be active in parallel at the same time.
65 * @return handle to the queue
66 */
67struct OperationQueue *
68GNUNET_TESTBED_operation_queue_create_ (enum OperationQueueType type,
69 unsigned int max_active);
70
71
72/**
73 * Destroy an operation queue. The queue MUST be empty
74 * at this time.
75 *
76 * @param queue queue to destroy
77 */
78void
79GNUNET_TESTBED_operation_queue_destroy_ (struct OperationQueue *queue);
80
81
82/**
83 * Destroys the operation queue if it is empty. If not empty return GNUNET_NO.
84 *
85 * @param queue the queue to destroy if empty
86 * @return GNUNET_YES if the queue is destroyed. GNUNET_NO if not (because it
87 * is not empty)
88 */
89int
90GNUNET_TESTBED_operation_queue_destroy_empty_ (struct OperationQueue *queue);
91
92
93/**
94 * Function to reset the maximum number of operations in the given queue. If
95 * max_active is lesser than the number of currently active operations, the
96 * active operations are not stopped immediately.
97 *
98 * @param queue the operation queue which has to be modified
99 * @param max_active the new maximum number of active operations
100 */
101void
102GNUNET_TESTBED_operation_queue_reset_max_active_ (struct OperationQueue *queue,
103 unsigned int max_active);
104
105
106/**
107 * Add an operation to a queue. An operation can be in multiple queues at
108 * once. Once the operation is inserted into all the queues
109 * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
110 * waiting for the operation to become active.
111 *
112 * @param queue queue to add the operation to
113 * @param op operation to add to the queue
114 * @param nres the number of units of the resources of queue needed by the
115 * operation. Should be greater than 0.
116 */
117void
118GNUNET_TESTBED_operation_queue_insert2_ (struct OperationQueue *queue,
119 struct GNUNET_TESTBED_Operation *op,
120 unsigned int nres);
121
122
123/**
124 * Add an operation to a queue. An operation can be in multiple queues at
125 * once. Once the operation is inserted into all the queues
126 * GNUNET_TESTBED_operation_begin_wait_() has to be called to actually start
127 * waiting for the operation to become active.
128 *
129 * @param queue queue to add the operation to
130 * @param op operation to add to the queue
131 */
132void
133GNUNET_TESTBED_operation_queue_insert_ (struct OperationQueue *queue,
134 struct GNUNET_TESTBED_Operation *op);
135
136
137/**
138 * Marks the given operation as waiting on the queues. Once all queues permit
139 * the operation to become active, the operation will be activated. The actual
140 * activation will occur in a separate task (thus allowing multiple queue
141 * insertions to be made without having the first one instantly trigger the
142 * operation if the first queue has sufficient resources).
143 *
144 * @param op the operation to marks as waiting
145 */
146void
147GNUNET_TESTBED_operation_begin_wait_ (struct GNUNET_TESTBED_Operation *op);
148
149
150/**
151 * Function to call to start an operation once all
152 * queues the operation is part of declare that the
153 * operation can be activated.
154 *
155 * @param cls the closure from GNUNET_TESTBED_operation_create_()
156 */
157typedef void (*OperationStart) (void *cls);
158
159
160/**
161 * Function to call to cancel an operation (release all associated
162 * resources). This can be because of a call to
163 * "GNUNET_TESTBED_operation_cancel" (before the operation generated
164 * an event) or AFTER the operation generated an event due to a call
165 * to "GNUNET_TESTBED_operation_done". Thus it is not guaranteed that
166 * a callback to the 'OperationStart' precedes the call to
167 * 'OperationRelease'. Implementations of this function are expected
168 * to clean up whatever state is in 'cls' and release all resources
169 * associated with the operation.
170 *
171 * @param cls the closure from GNUNET_TESTBED_operation_create_()
172 */
173typedef void (*OperationRelease) (void *cls);
174
175
176/**
177 * Create an 'operation' to be performed.
178 *
179 * @param cls closure for the callbacks
180 * @param start function to call to start the operation
181 * @param release function to call to close down the operation
182 * @return handle to the operation
183 */
184struct GNUNET_TESTBED_Operation *
185GNUNET_TESTBED_operation_create_ (void *cls, OperationStart start,
186 OperationRelease release);
187
188
189/**
190 * An operation is 'done' (was cancelled or finished); remove
191 * it from the queues and release associated resources.
192 *
193 * @param op operation that finished
194 */
195void
196GNUNET_TESTBED_operation_release_ (struct GNUNET_TESTBED_Operation *op);
197
198
199/**
200 * Marks an active operation as inactive - the operation will be kept in a
201 * ready-to-be-released state and continues to hold resources until another
202 * operation contents for them.
203 *
204 * @param op the operation to be marked as inactive. The operation start
205 * callback should have been called before for this operation to mark
206 * it as inactive.
207 */
208void
209GNUNET_TESTBED_operation_inactivate_ (struct GNUNET_TESTBED_Operation *op);
210
211
212/**
213 * Marks and inactive operation as active. This function should be called to
214 * ensure that the oprelease callback will not be called until it is either
215 * marked as inactive or released.
216 *
217 * @param op the operation to be marked as active
218 */
219void
220GNUNET_TESTBED_operation_activate_ (struct GNUNET_TESTBED_Operation *op);
221
222
223/**
224 * Marks an operation as failed
225 *
226 * @param op the operation to be marked as failed
227 */
228void
229GNUNET_TESTBED_operation_mark_failed (struct GNUNET_TESTBED_Operation *op);
230
231
232#endif
233/* end of testbed_api_operations.h */
diff --git a/src/testbed/testbed_api_peers.c b/src/testbed/testbed_api_peers.c
deleted file mode 100644
index b8e428441..000000000
--- a/src/testbed/testbed_api_peers.c
+++ /dev/null
@@ -1,961 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_peers.c
23 * @brief management of the knowledge about peers in this library
24 * (we know the peer ID, its host, pending operations, etc.)
25 * @author Christian Grothoff
26 * @author Sree Harsha Totakura
27 */
28
29#include "platform.h"
30#include "testbed_api_peers.h"
31#include "testbed_api.h"
32#include "testbed.h"
33#include "testbed_api_hosts.h"
34#include "testbed_api_operations.h"
35
36
37/**
38 * Peer list DLL head
39 */
40static struct GNUNET_TESTBED_Peer *peer_list_head;
41
42/**
43 * Peer list DLL tail
44 */
45static struct GNUNET_TESTBED_Peer *peer_list_tail;
46
47
48/**
49 * Adds a peer to the peer list
50 *
51 * @param peer the peer to add to the peer list
52 */
53void
54GNUNET_TESTBED_peer_register_ (struct GNUNET_TESTBED_Peer *peer)
55{
56 GNUNET_CONTAINER_DLL_insert_tail (peer_list_head, peer_list_tail, peer);
57}
58
59
60/**
61 * Removes a peer from the peer list
62 *
63 * @param peer the peer to remove
64 */
65void
66GNUNET_TESTBED_peer_deregister_ (struct GNUNET_TESTBED_Peer *peer)
67{
68 GNUNET_CONTAINER_DLL_remove (peer_list_head, peer_list_tail, peer);
69}
70
71
72/**
73 * Frees all peers
74 */
75void
76GNUNET_TESTBED_cleanup_peers_ (void)
77{
78 struct GNUNET_TESTBED_Peer *peer;
79
80 while (NULL != (peer = peer_list_head))
81 {
82 GNUNET_TESTBED_peer_deregister_ (peer);
83 GNUNET_free (peer);
84 }
85}
86
87
88/**
89 * Function to call to start a peer_create type operation once all
90 * queues the operation is part of declare that the
91 * operation can be activated.
92 *
93 * @param cls the closure from GNUNET_TESTBED_operation_create_()
94 */
95static void
96opstart_peer_create (void *cls)
97{
98 struct OperationContext *opc = cls;
99 struct PeerCreateData *data = opc->data;
100 struct GNUNET_TESTBED_PeerCreateMessage *msg;
101 struct GNUNET_MQ_Envelope *env;
102 char *config;
103 char *xconfig;
104 size_t c_size;
105 size_t xc_size;
106
107 GNUNET_assert (OP_PEER_CREATE == opc->type);
108 GNUNET_assert (NULL != data);
109 GNUNET_assert (NULL != data->peer);
110 opc->state = OPC_STATE_STARTED;
111 config = GNUNET_CONFIGURATION_serialize (data->cfg,
112 &c_size);
113 xc_size = GNUNET_TESTBED_compress_config_ (config,
114 c_size,
115 &xconfig);
116 GNUNET_free (config);
117 env = GNUNET_MQ_msg_extra (msg,
118 xc_size,
119 GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER);
120 msg->operation_id = GNUNET_htonll (opc->id);
121 msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->peer->host));
122 msg->peer_id = htonl (data->peer->unique_id);
123 msg->config_size = htons ((uint16_t) c_size);
124 GNUNET_memcpy (&msg[1],
125 xconfig,
126 xc_size);
127 GNUNET_MQ_send (opc->c->mq,
128 env);
129 GNUNET_free (xconfig);
130 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
131}
132
133
134/**
135 * Callback which will be called when peer_create type operation is released
136 *
137 * @param cls the closure from GNUNET_TESTBED_operation_create_()
138 */
139static void
140oprelease_peer_create (void *cls)
141{
142 struct OperationContext *opc = cls;
143
144 switch (opc->state)
145 {
146 case OPC_STATE_STARTED:
147 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
148
149 /* No break we continue flow */
150 case OPC_STATE_INIT:
151 GNUNET_free (((struct PeerCreateData *) opc->data)->peer);
152 GNUNET_free (opc->data);
153 break;
154
155 case OPC_STATE_FINISHED:
156 break;
157 }
158 GNUNET_free (opc);
159}
160
161
162/**
163 * Function called when a peer destroy operation is ready
164 *
165 * @param cls the closure from GNUNET_TESTBED_operation_create_()
166 */
167static void
168opstart_peer_destroy (void *cls)
169{
170 struct OperationContext *opc = cls;
171 struct GNUNET_TESTBED_Peer *peer = opc->data;
172 struct GNUNET_TESTBED_PeerDestroyMessage *msg;
173 struct GNUNET_MQ_Envelope *env;
174
175 GNUNET_assert (OP_PEER_DESTROY == opc->type);
176 GNUNET_assert (NULL != peer);
177 opc->state = OPC_STATE_STARTED;
178 env = GNUNET_MQ_msg (msg,
179 GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER);
180 msg->peer_id = htonl (peer->unique_id);
181 msg->operation_id = GNUNET_htonll (opc->id);
182 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
183 GNUNET_MQ_send (peer->controller->mq,
184 env);
185}
186
187
188/**
189 * Callback which will be called when peer_create type operation is released
190 *
191 * @param cls the closure from GNUNET_TESTBED_operation_create_()
192 */
193static void
194oprelease_peer_destroy (void *cls)
195{
196 struct OperationContext *opc = cls;
197
198 switch (opc->state)
199 {
200 case OPC_STATE_STARTED:
201 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
202
203 /* no break; continue */
204 case OPC_STATE_INIT:
205 break;
206
207 case OPC_STATE_FINISHED:
208 break;
209 }
210 GNUNET_free (opc);
211}
212
213
214/**
215 * Function called when a peer start operation is ready
216 *
217 * @param cls the closure from GNUNET_TESTBED_operation_create_()
218 */
219static void
220opstart_peer_start (void *cls)
221{
222 struct OperationContext *opc = cls;
223 struct GNUNET_TESTBED_PeerStartMessage *msg;
224 struct GNUNET_MQ_Envelope *env;
225 struct PeerEventData *data;
226 struct GNUNET_TESTBED_Peer *peer;
227
228 GNUNET_assert (OP_PEER_START == opc->type);
229 GNUNET_assert (NULL != (data = opc->data));
230 GNUNET_assert (NULL != (peer = data->peer));
231 GNUNET_assert ((TESTBED_PS_CREATED == peer->state) || (TESTBED_PS_STOPPED ==
232 peer->state));
233 opc->state = OPC_STATE_STARTED;
234 env = GNUNET_MQ_msg (msg,
235 GNUNET_MESSAGE_TYPE_TESTBED_START_PEER);
236 msg->peer_id = htonl (peer->unique_id);
237 msg->operation_id = GNUNET_htonll (opc->id);
238 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
239 GNUNET_MQ_send (peer->controller->mq,
240 env);
241}
242
243
244/**
245 * Callback which will be called when peer start type operation is released
246 *
247 * @param cls the closure from GNUNET_TESTBED_operation_create_()
248 */
249static void
250oprelease_peer_start (void *cls)
251{
252 struct OperationContext *opc = cls;
253
254 switch (opc->state)
255 {
256 case OPC_STATE_STARTED:
257 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
258
259 /* no break; continue */
260 case OPC_STATE_INIT:
261 GNUNET_free (opc->data);
262 break;
263
264 case OPC_STATE_FINISHED:
265 break;
266 }
267 GNUNET_free (opc);
268}
269
270
271/**
272 * Function called when a peer stop operation is ready
273 *
274 * @param cls the closure from GNUNET_TESTBED_operation_create_()
275 */
276static void
277opstart_peer_stop (void *cls)
278{
279 struct OperationContext *opc = cls;
280 struct GNUNET_TESTBED_PeerStopMessage *msg;
281 struct PeerEventData *data;
282 struct GNUNET_TESTBED_Peer *peer;
283 struct GNUNET_MQ_Envelope *env;
284
285 GNUNET_assert (NULL != (data = opc->data));
286 GNUNET_assert (NULL != (peer = data->peer));
287 GNUNET_assert (TESTBED_PS_STARTED == peer->state);
288 opc->state = OPC_STATE_STARTED;
289 env = GNUNET_MQ_msg (msg,
290 GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER);
291 msg->peer_id = htonl (peer->unique_id);
292 msg->operation_id = GNUNET_htonll (opc->id);
293 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
294 GNUNET_MQ_send (peer->controller->mq,
295 env);
296}
297
298
299/**
300 * Callback which will be called when peer stop type operation is released
301 *
302 * @param cls the closure from GNUNET_TESTBED_operation_create_()
303 */
304static void
305oprelease_peer_stop (void *cls)
306{
307 struct OperationContext *opc = cls;
308
309 switch (opc->state)
310 {
311 case OPC_STATE_STARTED:
312 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
313
314 /* no break; continue */
315 case OPC_STATE_INIT:
316 GNUNET_free (opc->data);
317 break;
318
319 case OPC_STATE_FINISHED:
320 break;
321 }
322 GNUNET_free (opc);
323}
324
325
326/**
327 * Generate PeerGetConfigurationMessage
328 *
329 * @param peer_id the id of the peer whose information we have to get
330 * @param operation_id the ip of the operation that should be represented in the
331 * message
332 * @return the PeerGetConfigurationMessage
333 */
334struct GNUNET_TESTBED_PeerGetConfigurationMessage *
335GNUNET_TESTBED_generate_peergetconfig_msg_ (uint32_t peer_id,
336 uint64_t operation_id)
337{
338 struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
339
340 msg =
341 GNUNET_malloc (sizeof
342 (struct GNUNET_TESTBED_PeerGetConfigurationMessage));
343 msg->header.size =
344 htons (sizeof(struct GNUNET_TESTBED_PeerGetConfigurationMessage));
345 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION);
346 msg->peer_id = htonl (peer_id);
347 msg->operation_id = GNUNET_htonll (operation_id);
348 return msg;
349}
350
351
352/**
353 * Function called when a peer get information operation is ready
354 *
355 * @param cls the closure from GNUNET_TESTBED_operation_create_()
356 */
357static void
358opstart_peer_getinfo (void *cls)
359{
360 struct OperationContext *opc = cls;
361 struct PeerInfoData *data = opc->data;
362 struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
363
364 GNUNET_assert (NULL != data);
365 opc->state = OPC_STATE_STARTED;
366 msg =
367 GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id,
368 opc->id);
369 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
370 GNUNET_TESTBED_queue_message_ (opc->c, &msg->header);
371}
372
373
374/**
375 * Callback which will be called when peer stop type operation is released
376 *
377 * @param cls the closure from GNUNET_TESTBED_operation_create_()
378 */
379static void
380oprelease_peer_getinfo (void *cls)
381{
382 struct OperationContext *opc = cls;
383 struct GNUNET_TESTBED_PeerInformation *data;
384
385 switch (opc->state)
386 {
387 case OPC_STATE_STARTED:
388 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
389
390 /* no break; continue */
391 case OPC_STATE_INIT:
392 GNUNET_free (opc->data);
393 break;
394
395 case OPC_STATE_FINISHED:
396 data = opc->data;
397 GNUNET_assert (NULL != data);
398 switch (data->pit)
399 {
400 case GNUNET_TESTBED_PIT_CONFIGURATION:
401 if (NULL != data->result.cfg)
402 GNUNET_CONFIGURATION_destroy (data->result.cfg);
403 break;
404
405 case GNUNET_TESTBED_PIT_IDENTITY:
406 GNUNET_free (data->result.id);
407 break;
408
409 default:
410 GNUNET_assert (0); /* We should never reach here */
411 }
412 GNUNET_free (data);
413 break;
414 }
415 GNUNET_free (opc);
416}
417
418
419/**
420 * Function called when a overlay connect operation is ready
421 *
422 * @param cls the closure from GNUNET_TESTBED_operation_create_()
423 */
424static void
425opstart_overlay_connect (void *cls)
426{
427 struct OperationContext *opc = cls;
428 struct GNUNET_MQ_Envelope *env;
429 struct GNUNET_TESTBED_OverlayConnectMessage *msg;
430 struct OverlayConnectData *data;
431
432 opc->state = OPC_STATE_STARTED;
433 data = opc->data;
434 GNUNET_assert (NULL != data);
435 env = GNUNET_MQ_msg (msg,
436 GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT);
437 msg->peer1 = htonl (data->p1->unique_id);
438 msg->peer2 = htonl (data->p2->unique_id);
439 msg->operation_id = GNUNET_htonll (opc->id);
440 msg->peer2_host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->p2->host));
441 GNUNET_TESTBED_insert_opc_ (opc->c,
442 opc);
443 GNUNET_MQ_send (opc->c->mq,
444 env);
445}
446
447
448/**
449 * Callback which will be called when overlay connect operation is released
450 *
451 * @param cls the closure from GNUNET_TESTBED_operation_create_()
452 */
453static void
454oprelease_overlay_connect (void *cls)
455{
456 struct OperationContext *opc = cls;
457 struct OverlayConnectData *data;
458
459 data = opc->data;
460 switch (opc->state)
461 {
462 case OPC_STATE_INIT:
463 break;
464
465 case OPC_STATE_STARTED:
466 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
467 break;
468
469 case OPC_STATE_FINISHED:
470 break;
471 }
472 GNUNET_free (data);
473 GNUNET_free (opc);
474}
475
476
477/**
478 * Function called when a peer reconfigure operation is ready
479 *
480 * @param cls the closure from GNUNET_TESTBED_operation_create_()
481 */
482static void
483opstart_peer_reconfigure (void *cls)
484{
485 struct OperationContext *opc = cls;
486 struct PeerReconfigureData *data = opc->data;
487 struct GNUNET_MQ_Envelope *env;
488 struct GNUNET_TESTBED_PeerReconfigureMessage *msg;
489 char *xconfig;
490 size_t xc_size;
491
492 opc->state = OPC_STATE_STARTED;
493 GNUNET_assert (NULL != data);
494 xc_size = GNUNET_TESTBED_compress_config_ (data->config,
495 data->cfg_size,
496 &xconfig);
497 GNUNET_free (data->config);
498 data->config = NULL;
499 GNUNET_assert (xc_size < UINT16_MAX - sizeof(*msg));
500 env = GNUNET_MQ_msg_extra (msg,
501 xc_size,
502 GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER);
503 msg->peer_id = htonl (data->peer->unique_id);
504 msg->operation_id = GNUNET_htonll (opc->id);
505 msg->config_size = htons (data->cfg_size);
506 GNUNET_memcpy (&msg[1],
507 xconfig,
508 xc_size);
509 GNUNET_free (xconfig);
510 GNUNET_free (data);
511 opc->data = NULL;
512 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
513 GNUNET_MQ_send (opc->c->mq,
514 env);
515}
516
517
518/**
519 * Callback which will be called when a peer reconfigure operation is released
520 *
521 * @param cls the closure from GNUNET_TESTBED_operation_create_()
522 */
523static void
524oprelease_peer_reconfigure (void *cls)
525{
526 struct OperationContext *opc = cls;
527 struct PeerReconfigureData *data = opc->data;
528
529 switch (opc->state)
530 {
531 case OPC_STATE_INIT:
532 GNUNET_free (data->config);
533 GNUNET_free (data);
534 break;
535
536 case OPC_STATE_STARTED:
537 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
538 break;
539
540 case OPC_STATE_FINISHED:
541 break;
542 }
543 GNUNET_free (opc);
544}
545
546
547/**
548 * Lookup a peer by ID.
549 *
550 * @param id global peer ID assigned to the peer
551 * @return handle to the host, NULL on error
552 */
553struct GNUNET_TESTBED_Peer *
554GNUNET_TESTBED_peer_lookup_by_id_ (uint32_t id)
555{
556 GNUNET_break (0);
557 return NULL;
558}
559
560
561/**
562 * Create the given peer at the specified host using the given
563 * controller. If the given controller is not running on the target
564 * host, it should find or create a controller at the target host and
565 * delegate creating the peer. Explicit delegation paths can be setup
566 * using 'GNUNET_TESTBED_controller_link'. If no explicit delegation
567 * path exists, a direct link with a subordinate controller is setup
568 * for the first delegated peer to a particular host; the subordinate
569 * controller is then destroyed once the last peer that was delegated
570 * to the remote host is stopped.
571 *
572 * Creating the peer only creates the handle to manipulate and further
573 * configure the peer; use "GNUNET_TESTBED_peer_start" and
574 * "GNUNET_TESTBED_peer_stop" to actually start/stop the peer's
575 * processes.
576 *
577 * Note that the given configuration will be adjusted by the
578 * controller to avoid port/path conflicts with other peers.
579 * The "final" configuration can be obtained using
580 * 'GNUNET_TESTBED_peer_get_information'.
581 *
582 * @param controller controller process to use
583 * @param host host to run the peer on; cannot be NULL
584 * @param cfg Template configuration to use for the peer. Should exist until
585 * operation is cancelled or GNUNET_TESTBED_operation_done() is called
586 * @param cb the callback to call when the peer has been created
587 * @param cls the closure to the above callback
588 * @return the operation handle
589 */
590struct GNUNET_TESTBED_Operation *
591GNUNET_TESTBED_peer_create (struct GNUNET_TESTBED_Controller *controller,
592 struct GNUNET_TESTBED_Host *host,
593 const struct GNUNET_CONFIGURATION_Handle *cfg,
594 GNUNET_TESTBED_PeerCreateCallback cb, void *cls)
595{
596 struct GNUNET_TESTBED_Peer *peer;
597 struct PeerCreateData *data;
598 struct OperationContext *opc;
599 static uint32_t id_gen;
600
601 peer = GNUNET_new (struct GNUNET_TESTBED_Peer);
602 peer->controller = controller;
603 peer->host = host;
604 peer->unique_id = id_gen++;
605 peer->state = TESTBED_PS_INVALID;
606 data = GNUNET_new (struct PeerCreateData);
607 data->host = host;
608 data->cfg = cfg;
609 data->cb = cb;
610 data->cls = cls;
611 data->peer = peer;
612 opc = GNUNET_new (struct OperationContext);
613 opc->c = controller;
614 opc->data = data;
615 opc->id = GNUNET_TESTBED_get_next_op_id (controller);
616 opc->type = OP_PEER_CREATE;
617 opc->op =
618 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_create,
619 &oprelease_peer_create);
620 GNUNET_TESTBED_operation_queue_insert_ (controller->opq_parallel_operations,
621 opc->op);
622 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
623 return opc->op;
624}
625
626
627/**
628 * Start the given peer.
629 *
630 * @param op_cls the closure for this operation; will be set in
631 * event->details.operation_finished.op_cls when this operation fails.
632 * @param peer peer to start
633 * @param pcc function to call upon completion
634 * @param pcc_cls closure for 'pcc'
635 * @return handle to the operation
636 */
637struct GNUNET_TESTBED_Operation *
638GNUNET_TESTBED_peer_start (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
639 GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
640{
641 struct OperationContext *opc;
642 struct PeerEventData *data;
643
644 data = GNUNET_new (struct PeerEventData);
645 data->peer = peer;
646 data->pcc = pcc;
647 data->pcc_cls = pcc_cls;
648 opc = GNUNET_new (struct OperationContext);
649 opc->c = peer->controller;
650 opc->data = data;
651 opc->op_cls = op_cls;
652 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
653 opc->type = OP_PEER_START;
654 opc->op =
655 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_start,
656 &oprelease_peer_start);
657 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
658 opc->op);
659 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
660 return opc->op;
661}
662
663
664struct GNUNET_TESTBED_Operation *
665GNUNET_TESTBED_peer_stop (void *op_cls,
666 struct GNUNET_TESTBED_Peer *peer,
667 GNUNET_TESTBED_PeerChurnCallback pcc, void *pcc_cls)
668{
669 struct OperationContext *opc;
670 struct PeerEventData *data;
671
672 data = GNUNET_new (struct PeerEventData);
673 data->peer = peer;
674 data->pcc = pcc;
675 data->pcc_cls = pcc_cls;
676 opc = GNUNET_new (struct OperationContext);
677 opc->c = peer->controller;
678 opc->data = data;
679 opc->op_cls = op_cls;
680 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
681 opc->type = OP_PEER_STOP;
682 opc->op =
683 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_stop,
684 &oprelease_peer_stop);
685 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
686 opc->op);
687 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
688 return opc->op;
689}
690
691
692struct GNUNET_TESTBED_Operation *
693GNUNET_TESTBED_peer_get_information (struct GNUNET_TESTBED_Peer *peer,
694 enum GNUNET_TESTBED_PeerInformationType
695 pit, GNUNET_TESTBED_PeerInfoCallback cb,
696 void *cb_cls)
697{
698 struct OperationContext *opc;
699 struct PeerInfoData *data;
700
701 GNUNET_assert (GNUNET_TESTBED_PIT_GENERIC != pit);
702 GNUNET_assert (NULL != cb);
703 data = GNUNET_new (struct PeerInfoData);
704 data->peer = peer;
705 data->pit = pit;
706 data->cb = cb;
707 data->cb_cls = cb_cls;
708 opc = GNUNET_new (struct OperationContext);
709 opc->c = peer->controller;
710 opc->data = data;
711 opc->type = OP_PEER_INFO;
712 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
713 opc->op =
714 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_getinfo,
715 &oprelease_peer_getinfo);
716 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
717 opc->op);
718 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
719 return opc->op;
720}
721
722
723/**
724 * Change peer configuration. Must only be called while the
725 * peer is stopped. Ports and paths cannot be changed this
726 * way.
727 *
728 * @param peer peer to change configuration for
729 * @param cfg new configuration (differences to existing
730 * configuration only)
731 * @return handle to the operation
732 */
733struct GNUNET_TESTBED_Operation *
734GNUNET_TESTBED_peer_update_configuration (struct GNUNET_TESTBED_Peer *peer,
735 const struct
736 GNUNET_CONFIGURATION_Handle *cfg)
737{
738 struct OperationContext *opc;
739 struct PeerReconfigureData *data;
740 size_t csize;
741
742 data = GNUNET_new (struct PeerReconfigureData);
743 data->peer = peer;
744 data->config = GNUNET_CONFIGURATION_serialize (cfg, &csize);
745 if (NULL == data->config)
746 {
747 GNUNET_free (data);
748 return NULL;
749 }
750 if (csize > UINT16_MAX)
751 {
752 GNUNET_break (0);
753 GNUNET_free (data->config);
754 GNUNET_free (data);
755 return NULL;
756 }
757 data->cfg_size = (uint16_t) csize;
758 opc = GNUNET_new (struct OperationContext);
759 opc->c = peer->controller;
760 opc->data = data;
761 opc->type = OP_PEER_RECONFIGURE;
762 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
763 opc->op =
764 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_reconfigure,
765 &oprelease_peer_reconfigure);
766 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
767 opc->op);
768 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
769 return opc->op;
770}
771
772
773/**
774 * Destroy the given peer; the peer should have been
775 * stopped first (if it was started).
776 *
777 * @param peer peer to stop
778 * @return handle to the operation
779 */
780struct GNUNET_TESTBED_Operation *
781GNUNET_TESTBED_peer_destroy (struct GNUNET_TESTBED_Peer *peer)
782{
783 struct OperationContext *opc;
784
785 opc = GNUNET_new (struct OperationContext);
786 opc->data = peer;
787 opc->c = peer->controller;
788 opc->id = GNUNET_TESTBED_get_next_op_id (peer->controller);
789 opc->type = OP_PEER_DESTROY;
790 opc->op =
791 GNUNET_TESTBED_operation_create_ (opc, &opstart_peer_destroy,
792 &oprelease_peer_destroy);
793 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
794 opc->op);
795 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
796 return opc->op;
797}
798
799
800/**
801 * Manipulate the P2P underlay topology by configuring a link
802 * between two peers.
803 *
804 * @param op_cls closure argument to give with the operation event
805 * @param p1 first peer
806 * @param p2 second peer
807 * @param co option to change
808 * @param ... option-specific values
809 * @return handle to the operation, NULL if configuring the link at this
810 * time is not allowed
811 */
812struct GNUNET_TESTBED_Operation *
813GNUNET_TESTBED_underlay_configure_link (void *op_cls,
814 struct GNUNET_TESTBED_Peer *p1,
815 struct GNUNET_TESTBED_Peer *p2,
816 enum GNUNET_TESTBED_ConnectOption co,
817 ...)
818{
819 GNUNET_break (0);
820 return NULL;
821}
822
823
824struct GNUNET_TESTBED_Operation *
825GNUNET_TESTBED_overlay_connect (void *op_cls,
826 GNUNET_TESTBED_OperationCompletionCallback cb,
827 void *cb_cls, struct GNUNET_TESTBED_Peer *p1,
828 struct GNUNET_TESTBED_Peer *p2)
829{
830 struct OperationContext *opc;
831 struct OverlayConnectData *data;
832
833 GNUNET_assert ((TESTBED_PS_STARTED == p1->state) && (TESTBED_PS_STARTED ==
834 p2->state));
835 data = GNUNET_new (struct OverlayConnectData);
836 data->p1 = p1;
837 data->p2 = p2;
838 data->cb = cb;
839 data->cb_cls = cb_cls;
840 opc = GNUNET_new (struct OperationContext);
841 opc->data = data;
842 opc->c = p1->controller;
843 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
844 opc->type = OP_OVERLAY_CONNECT;
845 opc->op_cls = op_cls;
846 opc->op =
847 GNUNET_TESTBED_operation_create_ (opc, &opstart_overlay_connect,
848 &oprelease_overlay_connect);
849 GNUNET_TESTBED_host_queue_oc_ (p1->host, opc->op);
850 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
851 return opc->op;
852}
853
854
855/**
856 * Function called when a peer manage service operation is ready
857 *
858 * @param cls the closure from GNUNET_TESTBED_operation_create_()
859 */
860static void
861opstart_manage_service (void *cls)
862{
863 struct OperationContext *opc = cls;
864 struct ManageServiceData *data = opc->data;
865 struct GNUNET_MQ_Envelope *env;
866 struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
867 size_t xlen;
868
869 GNUNET_assert (NULL != data);
870 xlen = data->msize - sizeof(struct GNUNET_TESTBED_ManagePeerServiceMessage);
871 env = GNUNET_MQ_msg_extra (msg,
872 xlen,
873 GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE);
874 msg->peer_id = htonl (data->peer->unique_id);
875 msg->operation_id = GNUNET_htonll (opc->id);
876 msg->start = (uint8_t) data->start;
877 GNUNET_memcpy (&msg[1],
878 data->service_name,
879 xlen);
880 GNUNET_free (data->service_name);
881 data->service_name = NULL;
882 opc->state = OPC_STATE_STARTED;
883 GNUNET_TESTBED_insert_opc_ (opc->c, opc);
884 GNUNET_MQ_send (opc->c->mq,
885 env);
886}
887
888
889/**
890 * Callback which will be called when peer manage server operation is released
891 *
892 * @param cls the closure from GNUNET_TESTBED_operation_create_()
893 */
894static void
895oprelease_manage_service (void *cls)
896{
897 struct OperationContext *opc = cls;
898 struct ManageServiceData *data;
899
900 data = opc->data;
901 switch (opc->state)
902 {
903 case OPC_STATE_STARTED:
904 GNUNET_TESTBED_remove_opc_ (opc->c, opc);
905 break;
906
907 case OPC_STATE_INIT:
908 GNUNET_assert (NULL != data);
909 GNUNET_free (data->service_name);
910 break;
911
912 case OPC_STATE_FINISHED:
913 break;
914 }
915 GNUNET_free (data);
916 GNUNET_free (opc);
917}
918
919
920struct GNUNET_TESTBED_Operation *
921GNUNET_TESTBED_peer_manage_service (void *op_cls,
922 struct GNUNET_TESTBED_Peer *peer,
923 const char *service_name,
924 GNUNET_TESTBED_OperationCompletionCallback
925 cb,
926 void *cb_cls,
927 unsigned int start)
928{
929 struct ManageServiceData *data;
930 struct OperationContext *opc;
931 size_t msize;
932
933 GNUNET_assert (TESTBED_PS_STARTED == peer->state); /* peer is not running? */
934 msize = strlen (service_name) + 1;
935 msize += sizeof(struct GNUNET_TESTBED_ManagePeerServiceMessage);
936 if (GNUNET_MAX_MESSAGE_SIZE < msize)
937 return NULL;
938 data = GNUNET_new (struct ManageServiceData);
939 data->cb = cb;
940 data->cb_cls = cb_cls;
941 data->peer = peer;
942 data->service_name = GNUNET_strdup (service_name);
943 data->start = start;
944 data->msize = (uint16_t) msize;
945 opc = GNUNET_new (struct OperationContext);
946 opc->data = data;
947 opc->c = peer->controller;
948 opc->id = GNUNET_TESTBED_get_next_op_id (opc->c);
949 opc->type = OP_MANAGE_SERVICE;
950 opc->op_cls = op_cls;
951 opc->op =
952 GNUNET_TESTBED_operation_create_ (opc, &opstart_manage_service,
953 &oprelease_manage_service);
954 GNUNET_TESTBED_operation_queue_insert_ (opc->c->opq_parallel_operations,
955 opc->op);
956 GNUNET_TESTBED_operation_begin_wait_ (opc->op);
957 return opc->op;
958}
959
960
961/* end of testbed_api_peers.c */
diff --git a/src/testbed/testbed_api_peers.h b/src/testbed/testbed_api_peers.h
deleted file mode 100644
index 10129d961..000000000
--- a/src/testbed/testbed_api_peers.h
+++ /dev/null
@@ -1,311 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_peers.h
23 * @brief internal API to access the 'peers' subsystem
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
26 */
27
28#ifndef NEW_TESTING_API_PEERS_H
29#define NEW_TESTING_API_PEERS_H
30
31#include "gnunet_testbed_service.h"
32#include "gnunet_util_lib.h"
33
34
35/**
36 * Enumeration of possible states a peer could be in
37 */
38enum PeerState
39{
40 /**
41 * State to signify that this peer is invalid
42 */
43 TESTBED_PS_INVALID,
44
45 /**
46 * The peer has been created
47 */
48 TESTBED_PS_CREATED,
49
50 /**
51 * The peer is running
52 */
53 TESTBED_PS_STARTED,
54
55 /**
56 * The peer is stopped
57 */
58 TESTBED_PS_STOPPED,
59};
60
61
62/**
63 * A peer controlled by the testing framework. A peer runs
64 * at a particular host.
65 */
66struct GNUNET_TESTBED_Peer
67{
68 /**
69 * peer list DLL
70 */
71 struct GNUNET_TESTBED_Peer *next;
72
73 /**
74 * peer list DLL
75 */
76 struct GNUNET_TESTBED_Peer *prev;
77
78 /**
79 * Our controller context (not necessarily the controller
80 * that is responsible for starting/running the peer!).
81 */
82 struct GNUNET_TESTBED_Controller *controller;
83
84 /**
85 * Which host does this peer run on?
86 */
87 struct GNUNET_TESTBED_Host *host;
88
89 /**
90 * Globally unique ID of the peer.
91 */
92 uint32_t unique_id;
93
94 /**
95 * Peer's state
96 */
97 enum PeerState state;
98
99 /**
100 * Has an underlay model already set for this peer?
101 */
102 uint8_t underlay_model_exists;
103};
104
105
106/**
107 * Data for the OperationType OP_PEER_CREATE
108 */
109struct PeerCreateData
110{
111 /**
112 * The host where the peer has to be created
113 */
114 struct GNUNET_TESTBED_Host *host;
115
116 /**
117 * The template configuration of the peer
118 */
119 const struct GNUNET_CONFIGURATION_Handle *cfg;
120
121 /**
122 * The call back to call when we receive peer create success message
123 */
124 GNUNET_TESTBED_PeerCreateCallback cb;
125
126 /**
127 * The closure for the above callback
128 */
129 void *cls;
130
131 /**
132 * The peer structure to return when we get success message
133 */
134 struct GNUNET_TESTBED_Peer *peer;
135};
136
137
138/**
139 * Data for OperationType OP_PEER_START and OP_PEER_STOP
140 */
141struct PeerEventData
142{
143 /**
144 * The handle of the peer to start
145 */
146 struct GNUNET_TESTBED_Peer *peer;
147
148 /**
149 * The Peer churn callback to call when this operation is completed
150 */
151 GNUNET_TESTBED_PeerChurnCallback pcc;
152
153 /**
154 * Closure for the above callback
155 */
156 void *pcc_cls;
157};
158
159
160/**
161 * Data for the OperationType OP_PEER_DESTROY;
162 */
163struct PeerDestroyData
164{
165 /**
166 * The peer structure
167 */
168 struct GNUNET_TESTBED_Peer *peer;
169
170 // PEERDESTROYDATA
171};
172
173
174/**
175 * Data for the OperationType OP_PEER_INFO
176 */
177struct PeerInfoData
178{
179 /**
180 * The peer whose information has been requested
181 */
182 struct GNUNET_TESTBED_Peer *peer;
183
184 /**
185 * The Peer info callback to call when this operation has completed
186 */
187 GNUNET_TESTBED_PeerInfoCallback cb;
188
189 /**
190 * The closure for peer info callback
191 */
192 void *cb_cls;
193
194 /**
195 * The type of peer information requested
196 */
197 enum GNUNET_TESTBED_PeerInformationType pit;
198};
199
200
201/**
202 * Data for the operations of type OP_PEER_RECONFIGURE
203 */
204struct PeerReconfigureData
205{
206 /**
207 * The peer whose information has been requested
208 */
209 struct GNUNET_TESTBED_Peer *peer;
210
211 /**
212 * The serialized new configuration template
213 */
214 char *config;
215
216 /**
217 * the size of the serialized configuration
218 */
219 uint16_t cfg_size;
220};
221
222
223/**
224 * Data structure for OperationType OP_OVERLAY_CONNECT
225 */
226struct OverlayConnectData
227{
228 /**
229 * Peer A to connect to peer B
230 */
231 struct GNUNET_TESTBED_Peer *p1;
232
233 /**
234 * Peer B
235 */
236 struct GNUNET_TESTBED_Peer *p2;
237
238 /**
239 * The operation completion callback to call once this operation is done
240 */
241 GNUNET_TESTBED_OperationCompletionCallback cb;
242
243 /**
244 * The closure for the above callback
245 */
246 void *cb_cls;
247
248 /**
249 * OperationContext for forwarded operations generated when peer1's controller doesn't have the
250 * configuration of peer2's controller for linking laterally to attempt an
251 * overlay connection between peer 1 and peer 2.
252 */
253 struct OperationContext *sub_opc;
254};
255
256
257struct ManageServiceData
258{
259 GNUNET_TESTBED_OperationCompletionCallback cb;
260
261 void *cb_cls;
262
263 struct GNUNET_TESTBED_Peer *peer;
264
265 char *service_name;
266
267 unsigned int start;
268
269 uint16_t msize;
270};
271
272
273/**
274 * Generate PeerGetConfigurationMessage
275 *
276 * @param peer_id the id of the peer whose information we have to get
277 * @param operation_id the ip of the operation that should be represented in
278 * the message
279 * @return the PeerGetConfigurationMessage
280 */
281struct GNUNET_TESTBED_PeerGetConfigurationMessage *
282GNUNET_TESTBED_generate_peergetconfig_msg_ (uint32_t peer_id,
283 uint64_t operation_id);
284
285
286/**
287 * Adds a peer to the peer list
288 *
289 * @param peer the peer to add to the peer list
290 */
291void
292GNUNET_TESTBED_peer_register_ (struct GNUNET_TESTBED_Peer *peer);
293
294
295/**
296 * Removes a peer from the peer list
297 *
298 * @param peer the peer to remove
299 */
300void
301GNUNET_TESTBED_peer_deregister_ (struct GNUNET_TESTBED_Peer *peer);
302
303
304/**
305 * Frees all peers
306 */
307void
308GNUNET_TESTBED_cleanup_peers_ (void);
309
310#endif
311/* end of testbed_api_peers.h */
diff --git a/src/testbed/testbed_api_sd.c b/src/testbed/testbed_api_sd.c
deleted file mode 100644
index 59c7a3ebd..000000000
--- a/src/testbed/testbed_api_sd.c
+++ /dev/null
@@ -1,213 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_sd.c
23 * @brief functions to calculate standard deviation
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "testbed_api_sd.h"
30
31/**
32 * An entry to hold data which will be used to calculate SD
33 */
34struct SDEntry
35{
36 /**
37 * DLL next pointer
38 */
39 struct SDEntry *next;
40
41 /**
42 * DLL prev pointer
43 */
44 struct SDEntry *prev;
45
46 /**
47 * The value to store
48 */
49 unsigned int amount;
50};
51
52
53/**
54 * Opaque handle for calculating SD
55 */
56struct SDHandle
57{
58 /**
59 * DLL head for storing entries
60 */
61 struct SDEntry *head;
62
63 /**
64 * DLL tail for storing entries
65 */
66 struct SDEntry *tail;
67
68 /**
69 * Squared sum of data values
70 */
71 unsigned long long sqsum;
72
73 /**
74 * Sum of the data values
75 */
76 unsigned long sum;
77
78 /**
79 * The average of data amounts
80 */
81 float avg;
82
83 /**
84 * The variance
85 */
86 double vr;
87
88 /**
89 * Number of data values; also the length of DLL containing SDEntries
90 */
91 unsigned int cnt;
92
93 /**
94 * max number of entries we can have in the DLL
95 */
96 unsigned int max_cnt;
97};
98
99
100/**
101 * Initialize standard deviation calculation handle
102 *
103 * @param max_cnt the maximum number of readings to keep
104 * @return the initialized handle
105 */
106struct SDHandle *
107GNUNET_TESTBED_SD_init_ (unsigned int max_cnt)
108{
109 struct SDHandle *h;
110
111 GNUNET_assert (1 < max_cnt);
112 h = GNUNET_new (struct SDHandle);
113 h->max_cnt = max_cnt;
114 return h;
115}
116
117
118/**
119 * Frees the memory allocated to the SD handle
120 *
121 * @param h the SD handle
122 */
123void
124GNUNET_TESTBED_SD_destroy_ (struct SDHandle *h)
125{
126 struct SDEntry *entry;
127
128 while (NULL != (entry = h->head))
129 {
130 GNUNET_CONTAINER_DLL_remove (h->head, h->tail, entry);
131 GNUNET_free (entry);
132 }
133 GNUNET_free (h);
134}
135
136
137/**
138 * Add a reading to SD
139 *
140 * @param h the SD handle
141 * @param amount the reading value
142 */
143void
144GNUNET_TESTBED_SD_add_data_ (struct SDHandle *h, unsigned int amount)
145{
146 struct SDEntry *entry;
147 double sqavg;
148 double sqsum_avg;
149
150 entry = NULL;
151 if (h->cnt == h->max_cnt)
152 {
153 entry = h->head;
154 GNUNET_CONTAINER_DLL_remove (h->head, h->tail, entry);
155 h->sum -= entry->amount;
156 h->sqsum -=
157 ((unsigned long) entry->amount) * ((unsigned long) entry->amount);
158 h->cnt--;
159 }
160 GNUNET_assert (h->cnt < h->max_cnt);
161 if (NULL == entry)
162 entry = GNUNET_new (struct SDEntry);
163 entry->amount = amount;
164 GNUNET_CONTAINER_DLL_insert_tail (h->head, h->tail, entry);
165 h->sum += amount;
166 h->cnt++;
167 h->avg = ((float) h->sum) / ((float) h->cnt);
168 h->sqsum += ((unsigned long) amount) * ((unsigned long) amount);
169 sqsum_avg = ((double) h->sqsum) / ((double) h->cnt);
170 sqavg = ((double) h->avg) * ((double) h->avg);
171 h->vr = sqsum_avg - sqavg;
172}
173
174
175/**
176 * Calculates the factor by which the given amount differs
177 *
178 * @param h the SDhandle
179 * @param amount the value for which the deviation is returned
180 * @param factor the factor by which the given amont differs
181 * @return GNUNET_SYSERR if the deviation cannot
182 * be calculated; GNUNET_OK if the deviation is returned through factor
183 */
184int
185GNUNET_TESTBED_SD_deviation_factor_ (struct SDHandle *h, unsigned int amount,
186 int *factor)
187{
188 double diff;
189 int f;
190 int n;
191
192 if (h->cnt < 2)
193 return GNUNET_SYSERR;
194 if (((float) amount) > h->avg)
195 {
196 diff = ((float) amount) - h->avg;
197 f = 1;
198 }
199 else
200 {
201 diff = h->avg - ((float) amount);
202 f = -1;
203 }
204 diff *= diff;
205 for (n = 1; n < 4; n++)
206 if (diff < (((double) (n * n)) * h->vr))
207 break;
208 *factor = f * n;
209 return GNUNET_OK;
210}
211
212
213/* end of testbed_api_sd.c */
diff --git a/src/testbed/testbed_api_sd.h b/src/testbed/testbed_api_sd.h
deleted file mode 100644
index 2872051e0..000000000
--- a/src/testbed/testbed_api_sd.h
+++ /dev/null
@@ -1,81 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_sd.h
23 * @brief functions to calculate standard deviation
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#ifndef TESTBED_API_SD_H
28#define TESTBED_API_SD_H
29
30
31/**
32 * Opaque handle for calculating SD
33 */
34struct SDHandle;
35
36
37/**
38 * Initialize standard deviation calculation handle
39 *
40 * @param max_cnt the maximum number of readings to keep
41 * @return the initialized handle
42 */
43struct SDHandle *
44GNUNET_TESTBED_SD_init_ (unsigned int max_cnt);
45
46
47/**
48 * Frees the memory allocated to the SD handle
49 *
50 * @param h the SD handle
51 */
52void
53GNUNET_TESTBED_SD_destroy_ (struct SDHandle *h);
54
55
56/**
57 * Add a reading to SD
58 *
59 * @param h the SD handle
60 * @param amount the reading value
61 */
62void
63GNUNET_TESTBED_SD_add_data_ (struct SDHandle *h, unsigned int amount);
64
65
66/**
67 * Returns the factor by which the given amount differs from the standard deviation
68 *
69 * @param h the SDhandle
70 * @param amount the value for which the deviation is returned
71 * @param factor the factor by which the given amont differs
72 * @return the deviation from the average; GNUNET_SYSERR if the deviation cannot
73 * be calculated OR 0 if the deviation is less than the average; a
74 * maximum of 4 is returned for deviations equal to or larger than 4
75 */
76int
77GNUNET_TESTBED_SD_deviation_factor_ (struct SDHandle *h, unsigned int amount,
78 int *factor);
79
80#endif
81/* end of testbed_api.h */
diff --git a/src/testbed/testbed_api_services.c b/src/testbed/testbed_api_services.c
deleted file mode 100644
index 2c9a90fd4..000000000
--- a/src/testbed/testbed_api_services.c
+++ /dev/null
@@ -1,291 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_services.c
23 * @brief convenience functions for accessing services
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "testbed_api.h"
28#include "testbed_api_peers.h"
29#include "testbed_api_operations.h"
30
31
32/**
33 * States for Service connect operations
34 */
35enum State
36{
37 /**
38 * Initial state
39 */
40 INIT,
41
42 /**
43 * The configuration request has been sent
44 */
45 CFG_REQUEST_QUEUED,
46
47 /**
48 * connected to service
49 */
50 SERVICE_CONNECTED
51};
52
53
54/**
55 * Data accessed during service connections
56 */
57struct ServiceConnectData
58{
59 /**
60 * helper function callback to establish the connection
61 */
62 GNUNET_TESTBED_ConnectAdapter ca;
63
64 /**
65 * helper function callback to close the connection
66 */
67 GNUNET_TESTBED_DisconnectAdapter da;
68
69 /**
70 * Closure to the above callbacks
71 */
72 void *cada_cls;
73
74 /**
75 * Service name
76 */
77 char *service_name;
78
79 /**
80 * Closure for operation event
81 */
82 void *op_cls;
83
84 /**
85 * The operation which created this structure
86 */
87 struct GNUNET_TESTBED_Operation *operation;
88
89 /**
90 * The operation context from GNUNET_TESTBED_forward_operation_msg_()
91 */
92 struct OperationContext *opc;
93
94 /**
95 * The peer handle
96 */
97 struct GNUNET_TESTBED_Peer *peer;
98
99 /**
100 * The acquired configuration of the peer
101 */
102 struct GNUNET_CONFIGURATION_Handle *cfg;
103
104 /**
105 * The op_result pointer from ConnectAdapter
106 */
107 void *op_result;
108
109 /**
110 * The operation completion callback
111 */
112 GNUNET_TESTBED_ServiceConnectCompletionCallback cb;
113
114 /**
115 * The closure for operation completion callback
116 */
117 void *cb_cls;
118
119 /**
120 * State information
121 */
122 enum State state;
123};
124
125
126/**
127 * Type of a function to call when we receive a message
128 * from the service.
129 *
130 * @param cls ServiceConnectData
131 * @param msg message received, NULL on timeout or fatal error
132 */
133static void
134configuration_receiver (void *cls, const struct GNUNET_MessageHeader *msg)
135{
136 struct ServiceConnectData *data = cls;
137 struct GNUNET_TESTBED_Controller *c;
138 const char *emsg;
139 struct GNUNET_TESTBED_EventInformation info;
140 uint16_t mtype;
141
142 c = data->peer->controller;
143 mtype = ntohs (msg->type);
144 emsg = NULL;
145 info.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
146 info.op = data->operation;
147 info.op_cls = data->op_cls;
148 if (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT == mtype)
149 {
150 emsg =
151 GNUNET_TESTBED_parse_error_string_ ((const struct
152 GNUNET_TESTBED_OperationFailureEventMessage
153 *) msg);
154 if (NULL == emsg)
155 emsg = "Unknown error";
156 info.details.operation_finished.emsg = emsg;
157 info.details.operation_finished.generic = NULL;
158 goto call_cb;
159 }
160 data->cfg = GNUNET_TESTBED_extract_config_ (msg);
161 GNUNET_assert (NULL == data->op_result);
162 data->op_result = data->ca (data->cada_cls, data->cfg);
163 info.details.operation_finished.emsg = NULL;
164 info.details.operation_finished.generic = data->op_result;
165 data->state = SERVICE_CONNECTED;
166
167call_cb:
168 if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
169 (NULL != c->cc))
170 c->cc (c->cc_cls, &info);
171 if (NULL != data->cb)
172 data->cb (data->cb_cls, data->operation, data->op_result, emsg);
173}
174
175
176/**
177 * Function called when a service connect operation is ready
178 *
179 * @param cls the closure from GNUNET_TESTBED_operation_create_()
180 */
181static void
182opstart_service_connect (void *cls)
183{
184 struct ServiceConnectData *data = cls;
185 struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
186 struct GNUNET_TESTBED_Controller *c;
187 uint64_t op_id;
188
189 GNUNET_assert (NULL != data);
190 GNUNET_assert (NULL != data->peer);
191 c = data->peer->controller;
192 op_id = GNUNET_TESTBED_get_next_op_id (c);
193 msg =
194 GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id, op_id);
195 data->opc =
196 GNUNET_TESTBED_forward_operation_msg_ (c, op_id, &msg->header,
197 &configuration_receiver, data);
198 GNUNET_free (msg);
199 data->state = CFG_REQUEST_QUEUED;
200}
201
202
203/**
204 * Callback which will be called when service connect type operation is
205 * released
206 *
207 * @param cls the closure from GNUNET_TESTBED_operation_create_()
208 */
209static void
210oprelease_service_connect (void *cls)
211{
212 struct ServiceConnectData *data = cls;
213
214 switch (data->state)
215 {
216 case INIT:
217 break;
218
219 case CFG_REQUEST_QUEUED:
220 GNUNET_assert (NULL != data->opc);
221 GNUNET_TESTBED_forward_operation_msg_cancel_ (data->opc);
222 break;
223
224 case SERVICE_CONNECTED:
225 GNUNET_assert (NULL != data->cfg);
226 GNUNET_CONFIGURATION_destroy (data->cfg);
227 if (NULL != data->da)
228 data->da (data->cada_cls, data->op_result);
229 break;
230 }
231 GNUNET_free (data);
232}
233
234
235/**
236 * Connect to a service offered by the given peer. Will ensure that
237 * the request is queued to not overwhelm our ability to create and
238 * maintain connections with other systems. The actual service
239 * handle is then returned via the 'op_result' member in the event
240 * callback. The 'ca' callback is used to create the connection
241 * when the time is right; the 'da' callback will be used to
242 * destroy the connection (upon 'GNUNET_TESTBED_operation_done').
243 * 'GNUNET_TESTBED_operation_done' can be used to abort this
244 * operation until the event callback has been called.
245 *
246 * @param op_cls closure to pass in operation event
247 * @param peer peer that runs the service
248 * @param service_name name of the service to connect to
249 * @param cb the callback to call when this operation finishes
250 * @param cb_cls closure for the above callback
251 * @param ca helper function to establish the connection
252 * @param da helper function to close the connection
253 * @param cada_cls closure for ca and da
254 * @return handle for the operation
255 */
256struct GNUNET_TESTBED_Operation *
257GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
258 const char *service_name,
259 GNUNET_TESTBED_ServiceConnectCompletionCallback
260 cb, void *cb_cls,
261 GNUNET_TESTBED_ConnectAdapter ca,
262 GNUNET_TESTBED_DisconnectAdapter da,
263 void *cada_cls)
264{
265 struct ServiceConnectData *data;
266
267 data = GNUNET_new (struct ServiceConnectData);
268 data->ca = ca;
269 data->da = da;
270 data->cada_cls = cada_cls;
271 data->op_cls = op_cls;
272 data->peer = peer;
273 data->state = INIT;
274 data->cb = cb;
275 data->cb_cls = cb_cls;
276 data->operation =
277 GNUNET_TESTBED_operation_create_ (data, &opstart_service_connect,
278 &oprelease_service_connect);
279 GNUNET_TESTBED_operation_queue_insert_ (peer->
280 controller->
281 opq_parallel_service_connections,
282 data->operation);
283 GNUNET_TESTBED_operation_queue_insert_ (peer->
284 controller->opq_parallel_operations,
285 data->operation);
286 GNUNET_TESTBED_operation_begin_wait_ (data->operation);
287 return data->operation;
288}
289
290
291/* end of testbed_api_services.c */
diff --git a/src/testbed/testbed_api_statistics.c b/src/testbed/testbed_api_statistics.c
deleted file mode 100644
index e800baa73..000000000
--- a/src/testbed/testbed_api_statistics.c
+++ /dev/null
@@ -1,435 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_statistics.c
23 * @brief high-level statistics function
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testbed_service.h"
30
31#include "testbed_api_operations.h"
32
33
34/**
35 * Generic logging shorthand
36 */
37#define LOG(kind, ...) \
38 GNUNET_log_from (kind, "testbed-api-statistics", __VA_ARGS__)
39
40/**
41 * Debug logging shorthand
42 */
43#define LOG_DEBUG(...) \
44 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
45
46
47/**
48 * Context information for use in GNUNET_TESTBED_get_statistics()
49 */
50struct GetStatsContext
51{
52 /**
53 * The main operation we generate while creating this context
54 */
55 struct GNUNET_TESTBED_Operation *main_op;
56
57 /**
58 * The service connect operations we create to open connection to the
59 * statistics service of each given peer
60 */
61 struct GNUNET_TESTBED_Operation **ops;
62
63 /**
64 * The array of peers whose statistics services are to be accessed
65 */
66 struct GNUNET_TESTBED_Peer **peers;
67
68 /**
69 * The subsystem of peers for which statistics are requested
70 */
71 char *subsystem;
72
73 /**
74 * The particular statistics value of interest
75 */
76 char *name;
77
78 /**
79 * The iterator to call with statistics information
80 */
81 GNUNET_TESTBED_StatisticsIterator proc;
82
83 /**
84 * The callback to call when we are done iterating through all peers'
85 * statistics services
86 */
87 GNUNET_TESTBED_OperationCompletionCallback cont;
88
89 /**
90 * The closure for the above callbacks
91 */
92 void *cb_cls;
93
94 /**
95 * The task for calling the continuation callback
96 */
97 struct GNUNET_SCHEDULER_Task *call_completion_task_id;
98
99 /**
100 * The number of peers present in the peers array. This number also
101 * represents the number of service connect operations in the ops array
102 */
103 unsigned int num_peers;
104
105 /**
106 * How many peers' statistics have we iterated through
107 */
108 unsigned int num_completed;
109};
110
111
112/**
113 * Context information with respect to a particular peer
114 */
115struct PeerGetStatsContext
116{
117 /**
118 * The GetStatsContext which is associated with this context
119 */
120 struct GetStatsContext *sc;
121
122 /**
123 * The handle from GNUNET_STATISTICS_get()
124 */
125 struct GNUNET_STATISTICS_GetHandle *get_handle;
126
127 /**
128 * Task to mark the statistics service connect operation as done
129 */
130 struct GNUNET_SCHEDULER_Task *op_done_task_id;
131
132 /**
133 * The index of this peer in the peers array of GetStatsContext
134 */
135 unsigned int peer_index;
136};
137
138
139/**
140 * A no-wait operation queue
141 */
142static struct OperationQueue *no_wait_queue;
143
144
145/**
146 * Call statistics operation completion. We call it in a separate task because
147 * the iteration_completion_cb() cannot destroy statistics handle which will be
148 * the case if the user calls GNUNET_TESTBED_operation_done() on the
149 * get_statistics operation.
150 *
151 * @param cls the GetStatsContext
152 */
153static void
154call_completion_task (void *cls)
155{
156 struct GetStatsContext *sc = cls;
157
158 GNUNET_assert (sc->call_completion_task_id != NULL);
159 sc->call_completion_task_id = NULL;
160 LOG_DEBUG ("Calling get_statistics() continuation callback\n");
161 sc->cont (sc->cb_cls, sc->main_op, NULL);
162}
163
164
165/**
166 * Task to mark statistics service connect operation as done. We call it here
167 * as we cannot destroy the statistics handle in iteration_completion_cb()
168 *
169 * @param cls the PeerGetStatsContext
170 */
171static void
172op_done_task (void *cls)
173{
174 struct PeerGetStatsContext *peer_sc = cls;
175 struct GetStatsContext *sc;
176 struct GNUNET_TESTBED_Operation **op;
177
178 sc = peer_sc->sc;
179 peer_sc->op_done_task_id = NULL;
180 op = &sc->ops[peer_sc->peer_index];
181 GNUNET_assert (NULL != *op);
182 GNUNET_TESTBED_operation_done (*op);
183 *op = NULL;
184}
185
186
187/**
188 * Continuation called by the "get_all" and "get" functions.
189 *
190 * @param cls the PeerGetStatsContext
191 * @param success GNUNET_OK if statistics were
192 * successfully obtained, GNUNET_SYSERR if not.
193 */
194static void
195iteration_completion_cb (void *cls, int success)
196{
197 struct PeerGetStatsContext *peer_sc = cls;
198 struct GetStatsContext *sc;
199
200 GNUNET_break (GNUNET_OK == success);
201 sc = peer_sc->sc;
202 peer_sc->get_handle = NULL;
203 sc->num_completed++;
204 peer_sc->op_done_task_id = GNUNET_SCHEDULER_add_now (&op_done_task, peer_sc);
205 if (sc->num_completed == sc->num_peers)
206 {
207 LOG_DEBUG ("Scheduling to call iteration completion callback\n");
208 sc->call_completion_task_id =
209 GNUNET_SCHEDULER_add_now (&call_completion_task, sc);
210 }
211}
212
213
214/**
215 * Callback function to process statistic values.
216 *
217 * @param cls the PeerGetStatsContext
218 * @param subsystem name of subsystem that created the statistic
219 * @param name the name of the datum
220 * @param value the current value
221 * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
222 * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
223 */
224static int
225iterator_cb (void *cls, const char *subsystem,
226 const char *name, uint64_t value,
227 int is_persistent)
228{
229 struct PeerGetStatsContext *peer_sc = cls;
230 struct GetStatsContext *sc;
231 struct GNUNET_TESTBED_Peer *peer;
232 int ret;
233
234 sc = peer_sc->sc;
235 peer = sc->peers[peer_sc->peer_index];
236 LOG_DEBUG ("Peer %u: [%s,%s] -> %lu\n", peer_sc->peer_index,
237 subsystem, name, (unsigned long) value);
238 ret = sc->proc (sc->cb_cls, peer,
239 subsystem, name, value, is_persistent);
240 if (GNUNET_SYSERR == ret)
241 LOG_DEBUG ("Aborting iteration for peer %u\n", peer_sc->peer_index);
242 return ret;
243}
244
245
246/**
247 * Called after opening a connection to the statistics service of a peer
248 *
249 * @param cls the PeerGetStatsContext
250 * @param op the operation that has been finished
251 * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
252 * @param emsg error message in case the operation has failed; will be NULL if
253 * operation has executed successfully.
254 */
255static void
256service_connect_comp (void *cls,
257 struct GNUNET_TESTBED_Operation *op,
258 void *ca_result,
259 const char *emsg)
260{
261 struct PeerGetStatsContext *peer_sc = cls;
262 struct GNUNET_STATISTICS_Handle *h = ca_result;
263
264 LOG_DEBUG ("Retrieving statistics of peer %u\n",
265 peer_sc->peer_index);
266 peer_sc->get_handle =
267 GNUNET_STATISTICS_get (h, peer_sc->sc->subsystem,
268 peer_sc->sc->name,
269 &iteration_completion_cb,
270 iterator_cb, peer_sc);
271}
272
273
274/**
275 * Adapter function called to establish a connection to the statistics service
276 * of a peer.
277 *
278 * @param cls the PeerGetStatsContext
279 * @param cfg configuration of the peer to connect to; will be available until
280 * GNUNET_TESTBED_operation_done() is called on the operation returned
281 * from GNUNET_TESTBED_service_connect()
282 * @return service handle to return in 'op_result', NULL on error
283 */
284static void *
285statistics_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
286{
287 struct PeerGetStatsContext *peer_sc = cls;
288
289 LOG_DEBUG ("Connecting to statistics service of peer %u\n",
290 peer_sc->peer_index);
291 return GNUNET_STATISTICS_create ("<testbed-api>", cfg);
292}
293
294
295/**
296 * Adapter function called to destroy statistics connection
297 *
298 * @param cls the PeerGetStatsContext
299 * @param op_result service handle returned from the connect adapter
300 */
301static void
302statistics_da (void *cls, void *op_result)
303{
304 struct PeerGetStatsContext *peer_sc = cls;
305 struct GNUNET_STATISTICS_Handle *sh = op_result;
306
307 if (NULL != peer_sc->get_handle)
308 {
309 GNUNET_STATISTICS_get_cancel (peer_sc->get_handle);
310 peer_sc->get_handle = NULL;
311 }
312 GNUNET_STATISTICS_destroy (sh, GNUNET_NO);
313 if (NULL != peer_sc->op_done_task_id)
314 GNUNET_SCHEDULER_cancel (peer_sc->op_done_task_id);
315 GNUNET_free (peer_sc);
316}
317
318
319/**
320 * Function called when get_statistics operation is ready
321 *
322 * @param cls the GetStatsContext
323 */
324static void
325opstart_get_stats (void *cls)
326{
327 struct GetStatsContext *sc = cls;
328 struct PeerGetStatsContext *peer_sc;
329 unsigned int peer;
330
331 LOG_DEBUG ("Starting get_statistics operation\n");
332 sc->ops = GNUNET_malloc (sc->num_peers
333 * sizeof(struct GNUNET_TESTBED_Operation *));
334 for (peer = 0; peer < sc->num_peers; peer++)
335 {
336 if (NULL == sc->peers[peer])
337 {
338 GNUNET_break (0);
339 continue;
340 }
341 peer_sc = GNUNET_new (struct PeerGetStatsContext);
342 peer_sc->sc = sc;
343 peer_sc->peer_index = peer;
344 sc->ops[peer] =
345 GNUNET_TESTBED_service_connect (sc, sc->peers[peer], "statistics",
346 &service_connect_comp,
347 peer_sc,
348 &statistics_ca,
349 &statistics_da,
350 peer_sc);
351 }
352}
353
354
355/**
356 * Function called when get_statistics operation is cancelled or marked as done
357 *
358 * @param cls the GetStatsContext
359 */
360static void
361oprelease_get_stats (void *cls)
362{
363 struct GetStatsContext *sc = cls;
364 unsigned int peer;
365
366 LOG_DEBUG ("Cleaning up get_statistics operation\n");
367 if (NULL != sc->call_completion_task_id)
368 GNUNET_SCHEDULER_cancel (sc->call_completion_task_id);
369 if (NULL != sc->ops)
370 {
371 for (peer = 0; peer < sc->num_peers; peer++)
372 {
373 if (NULL != sc->ops[peer])
374 {
375 GNUNET_TESTBED_operation_done (sc->ops[peer]);
376 sc->ops[peer] = NULL;
377 }
378 }
379 GNUNET_free (sc->ops);
380 }
381 GNUNET_free (sc->subsystem);
382 GNUNET_free (sc->name);
383 GNUNET_free (sc);
384 if (GNUNET_YES ==
385 GNUNET_TESTBED_operation_queue_destroy_empty_ (no_wait_queue))
386 no_wait_queue = NULL;
387}
388
389
390/**
391 * Convenience method that iterates over all (running) peers
392 * and retrieves all statistics from each peer.
393 *
394 * @param num_peers number of peers to iterate over
395 * @param peers array of peers to iterate over
396 * @param subsystem limit to the specified subsystem, NULL for all subsystems
397 * @param name name of the statistic value, NULL for all values
398 * @param proc processing function for each statistic retrieved
399 * @param cont continuation to call once call is completed(?)
400 * @param cls closure to pass to proc and cont
401 * @return operation handle to cancel the operation
402 */
403struct GNUNET_TESTBED_Operation *
404GNUNET_TESTBED_get_statistics (unsigned int num_peers,
405 struct GNUNET_TESTBED_Peer **peers,
406 const char *subsystem, const char *name,
407 GNUNET_TESTBED_StatisticsIterator proc,
408 GNUNET_TESTBED_OperationCompletionCallback cont,
409 void *cls)
410{
411 struct GetStatsContext *sc;
412
413 GNUNET_assert (NULL != proc);
414 GNUNET_assert (NULL != cont);
415 if (NULL == no_wait_queue)
416 no_wait_queue = GNUNET_TESTBED_operation_queue_create_
417 (OPERATION_QUEUE_TYPE_FIXED, UINT_MAX);
418 sc = GNUNET_new (struct GetStatsContext);
419 sc->peers = peers;
420 sc->subsystem = (NULL == subsystem) ? NULL : GNUNET_strdup (subsystem);
421 sc->name = (NULL == name) ? NULL : GNUNET_strdup (name);
422 sc->proc = proc;
423 sc->cont = cont;
424 sc->cb_cls = cls;
425 sc->num_peers = num_peers;
426 sc->main_op =
427 GNUNET_TESTBED_operation_create_ (sc, &opstart_get_stats,
428 &oprelease_get_stats);
429 GNUNET_TESTBED_operation_queue_insert_ (no_wait_queue, sc->main_op);
430 GNUNET_TESTBED_operation_begin_wait_ (sc->main_op);
431 return sc->main_op;
432}
433
434
435/* end of testbed_api_statistics.c */
diff --git a/src/testbed/testbed_api_test.c b/src/testbed/testbed_api_test.c
deleted file mode 100644
index d9eb384ba..000000000
--- a/src/testbed/testbed_api_test.c
+++ /dev/null
@@ -1,175 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_test.c
23 * @brief high-level test function
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
26 * @author Tobias Frisch
27 */
28#include "platform.h"
29#include "gnunet_testbed_service.h"
30#include "testbed.h"
31
32
33/**
34 * Context information for test run
35 */
36struct TestRunContext
37{
38 /**
39 * Test master callback
40 */
41 GNUNET_TESTBED_TestMaster test_master;
42
43 /**
44 * Closure for test master
45 */
46 void *test_master_cls;
47
48 /**
49 * The controller event callback
50 */
51 GNUNET_TESTBED_ControllerCallback cc;
52
53 /**
54 * Closure for the above callback
55 */
56 void *cc_cls;
57
58 /**
59 * event mask for the controller callback
60 */
61 uint64_t event_mask;
62
63 /**
64 * Number of peers to start
65 */
66 unsigned int num_peers;
67};
68
69
70/**
71 * Main run function.
72 *
73 * @param cls NULL
74 * @param args arguments passed to GNUNET_PROGRAM_run
75 * @param cfgfile the path to configuration file
76 * @param config the configuration file handle
77 */
78static void
79run (void *cls, char *const *args, const char *cfgfile,
80 const struct GNUNET_CONFIGURATION_Handle *config)
81{
82 struct TestRunContext *rc = cls;
83
84 GNUNET_TESTBED_run (NULL, config, rc->num_peers, rc->event_mask, rc->cc,
85 rc->cc_cls, rc->test_master, rc->test_master_cls);
86}
87
88
89/**
90 * Convenience method for running a "simple" test on the local system
91 * with a single call from 'main'. Underlay and overlay topology are
92 * configured using the "UNDERLAY" and "OVERLAY" options in the
93 * "[testbed]" section of the configuration (with possible options
94 * given in "UNDERLAY_XXX" and/or "OVERLAY_XXX").
95 *
96 * The test is to be terminated using a call to
97 * "GNUNET_SCHEDULER_shutdown". If starting the test fails,
98 * the program is stopped without 'master' ever being run.
99 *
100 * NOTE: this function should be called from 'main', NOT from
101 * within a GNUNET_SCHEDULER-loop. This function will initialize
102 * the scheduler loop, the testbed and then pass control to
103 * 'master'.
104 *
105 * @param testname name of the testcase (to configure logging, etc.)
106 * @param cfg_filename configuration filename to use
107 * (for testbed, controller and peers)
108 * @param num_peers number of peers to start
109 * @param event_mask bit mask with set of events to call 'cc' for;
110 * or-ed values of "1LL" shifted by the
111 * respective 'enum GNUNET_TESTBED_EventType'
112 * (e.g. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
113 * @param cc controller callback to invoke on events; This callback is called
114 * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
115 * set in the event_mask as this is the only way get access to the
116 * handle of each peer
117 * @param cc_cls closure for cc
118 * @param test_master task to run once the test is ready
119 * @param test_master_cls closure for @a test_master
120 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
121 */
122int
123GNUNET_TESTBED_test_run (const char *testname,
124 const char *cfg_filename,
125 unsigned int num_peers,
126 uint64_t event_mask,
127 GNUNET_TESTBED_ControllerCallback cc,
128 void *cc_cls,
129 GNUNET_TESTBED_TestMaster test_master,
130 void *test_master_cls)
131{
132 char *argv2[] = {
133 NULL,
134 "-c",
135 NULL,
136 NULL
137 };
138 struct GNUNET_GETOPT_CommandLineOption options[] = {
139 GNUNET_GETOPT_OPTION_END
140 };
141 struct TestRunContext *rc;
142 int ret;
143
144 argv2[0] = GNUNET_strdup (testname);
145 argv2[2] = GNUNET_strdup (cfg_filename);
146 GNUNET_assert (NULL != test_master);
147 GNUNET_assert (num_peers > 0);
148
149 char* envcfg = getenv(ENV_TESTBED_CONFIG);
150 setenv(ENV_TESTBED_CONFIG, cfg_filename, 1);
151
152 rc = GNUNET_malloc (sizeof(struct TestRunContext)
153 + (num_peers * sizeof(struct GNUNET_TESTBED_Peer *)));
154 rc->test_master = test_master;
155 rc->test_master_cls = test_master_cls;
156 rc->num_peers = num_peers;
157 rc->event_mask = event_mask;
158 rc->cc = cc;
159 rc->cc_cls = cc_cls;
160 ret = GNUNET_PROGRAM_run ((sizeof(argv2) / sizeof(char *)) - 1, argv2,
161 testname, "nohelp", options, &run, rc);
162
163 if (envcfg)
164 setenv(ENV_TESTBED_CONFIG, envcfg, 1);
165 else
166 unsetenv(ENV_TESTBED_CONFIG);
167
168 GNUNET_free (rc);
169 GNUNET_free (argv2[0]);
170 GNUNET_free (argv2[2]);
171 return ret;
172}
173
174
175/* end of testbed_api_test.c */
diff --git a/src/testbed/testbed_api_testbed.c b/src/testbed/testbed_api_testbed.c
deleted file mode 100644
index 8e75daae3..000000000
--- a/src/testbed/testbed_api_testbed.c
+++ /dev/null
@@ -1,1467 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_testbed.c
23 * @brief high-level testbed management
24 * @author Christian Grothoff
25 * @author Sree Harsha Totakura
26 */
27
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_testbed_service.h"
31#include "testbed_api.h"
32#include "testbed_api_peers.h"
33#include "testbed_api_hosts.h"
34#include "testbed_api_topology.h"
35
36/**
37 * Generic loggins shorthand
38 */
39#define LOG(kind, ...) \
40 GNUNET_log_from (kind, "testbed-api-testbed", __VA_ARGS__)
41
42/**
43 * Debug logging shortcut
44 */
45#define DEBUG(...) \
46 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
47
48/**
49 * The default setup timeout in seconds
50 */
51#define DEFAULT_SETUP_TIMEOUT 300
52
53
54/**
55 * Configuration section for testbed
56 */
57#define TESTBED_CONFIG_SECTION "testbed"
58
59/**
60 * Option string for the maximum number of edges a peer is permitted to have
61 * while generating scale free topology
62 */
63#define SCALE_FREE_CAP "SCALE_FREE_TOPOLOGY_CAP"
64
65/**
66 * Option string for the number of edges to be established when adding a new
67 * node to the scale free network
68 */
69#define SCALE_FREE_M "SCALE_FREE_TOPOLOGY_M"
70
71/**
72 * Context information for the operation we start
73 */
74struct RunContextOperation
75{
76 /**
77 * The testbed operation handle
78 */
79 struct GNUNET_TESTBED_Operation *op;
80
81 /**
82 * Context information for GNUNET_TESTBED_run()
83 */
84 struct GNUNET_TESTBED_RunHandle *rc;
85
86 /**
87 * Closure
88 */
89 void *cls;
90};
91
92
93/**
94 * States of RunContext
95 */
96enum State
97{
98 /**
99 * Initial state
100 */
101 RC_INIT = 0,
102
103 /**
104 * Controllers on given hosts started and linked
105 */
106 RC_LINKED,
107
108 /**
109 * Peers are created
110 */
111 RC_PEERS_CREATED,
112
113 /**
114 * The testbed run is ready and the master callback can be called now. At this
115 * time the peers are all started and if a topology is provided in the
116 * configuration the topology would have been attempted
117 */
118 RC_READY,
119
120 /* /\** */
121 /* * Peers are stopped */
122 /* *\/ */
123 /* RC_PEERS_STOPPED, */
124
125 /* /\** */
126 /* * Peers are destroyed */
127 /* *\/ */
128 /* RC_PEERS_DESTROYED */
129
130 /**
131 * All peers shutdown (stopped and destroyed)
132 */
133 RC_PEERS_SHUTDOWN
134};
135
136
137/**
138 * Context for host compatibility checks
139 */
140struct CompatibilityCheckContext
141{
142 /**
143 * The run context
144 */
145 struct GNUNET_TESTBED_RunHandle *rc;
146
147 /**
148 * Handle for the compatibility check
149 */
150 struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
151
152 /**
153 * Index of the host in the run context's hosts array
154 */
155 unsigned int index;
156};
157
158
159/**
160 * Testbed Run Handle
161 */
162struct GNUNET_TESTBED_RunHandle
163{
164 /**
165 * The controller handle
166 */
167 struct GNUNET_TESTBED_Controller *c;
168
169 /**
170 * The configuration of the controller. This is based on the cfg given to the
171 * function GNUNET_TESTBED_run(). We also use this config as a template while
172 * for peers
173 */
174 struct GNUNET_CONFIGURATION_Handle *cfg;
175
176 /**
177 * Handle to the host on which the controller runs
178 */
179 struct GNUNET_TESTBED_Host *h;
180
181 /**
182 * The handle to the controller process
183 */
184 struct GNUNET_TESTBED_ControllerProc *cproc;
185
186 /**
187 * The callback to use as controller callback
188 */
189 GNUNET_TESTBED_ControllerCallback cc;
190
191 /**
192 * The pointer to the controller callback
193 */
194 void *cc_cls;
195
196 /**
197 * The trusted IP string
198 */
199 char *trusted_ip;
200
201 /**
202 * TestMaster callback to call when testbed initialization is done
203 */
204 GNUNET_TESTBED_TestMaster test_master;
205
206 /**
207 * The closure for the TestMaster callback
208 */
209 void *test_master_cls;
210
211 /**
212 * A hashmap for operations started by us
213 */
214 struct GNUNET_CONTAINER_MultiHashMap32 *rcop_map;
215
216 /**
217 * An array of hosts loaded from the hostkeys file
218 */
219 struct GNUNET_TESTBED_Host **hosts;
220
221 /**
222 * Array of compatibility check contexts
223 */
224 struct CompatibilityCheckContext *hclist;
225
226 /**
227 * Array of peers which we create
228 */
229 struct GNUNET_TESTBED_Peer **peers;
230
231 /**
232 * The topology generation operation. Will be null if no topology is set in
233 * the configuration
234 */
235 struct GNUNET_TESTBED_Operation *topology_operation;
236
237 /**
238 * The file containing topology data. Only used if the topology is set to 'FROM_FILE'
239 */
240 char *topo_file;
241
242 /**
243 * Host registration handle
244 */
245 struct GNUNET_TESTBED_HostRegistrationHandle *reg_handle;
246
247 /**
248 * Profiling start time
249 */
250 struct GNUNET_TIME_Absolute pstart_time;
251
252 /**
253 * Host registration task
254 */
255 struct GNUNET_SCHEDULER_Task *register_hosts_task;
256
257 /**
258 * Task to be run of a timeout
259 */
260 struct GNUNET_SCHEDULER_Task *timeout_task;
261
262 /**
263 * Task run upon shutdown interrupts
264 */
265 struct GNUNET_SCHEDULER_Task *interrupt_task;
266
267 /**
268 * The event mask for the controller
269 */
270 uint64_t event_mask;
271
272 /**
273 * State of this context
274 */
275 enum State state;
276
277 /**
278 * The topology which has to be achieved with the peers started in this context
279 */
280 enum GNUNET_TESTBED_TopologyOption topology;
281
282 /**
283 * Have we already shutdown
284 */
285 int shutdown;
286
287 /**
288 * Number of hosts in the given host file
289 */
290 unsigned int num_hosts;
291
292 /**
293 * Number of registered hosts. Also used as a counter while checking
294 * habitabillity of hosts
295 */
296 unsigned int reg_hosts;
297
298 /**
299 * Current peer count for an operation; Set this to 0 and increment for each
300 * successful operation on a peer
301 */
302 unsigned int peer_count;
303
304 /**
305 * number of peers to start
306 */
307 unsigned int num_peers;
308
309 /**
310 * Expected overlay connects. Should be zero if no topology is relevant
311 */
312 unsigned int num_oc;
313
314 /**
315 * Number of random links to established
316 */
317 unsigned int random_links;
318
319 /**
320 * the number of overlay link connection attempts that succeeded
321 */
322 unsigned int links_succeeded;
323
324 /**
325 * the number of overlay link connection attempts that failed
326 */
327 unsigned int links_failed;
328};
329
330
331/**
332 * Return a 32-bit key from a pointer
333 *
334 * @param rcop the pointer
335 * @return 32-bit key
336 */
337static uint32_t
338rcop_key (void *rcop)
339{
340 return *((uint32_t *) &rcop);
341}
342
343
344/**
345 * Context information used for finding a pointer in the rcop_map
346 */
347struct SearchContext
348{
349 /**
350 * The operation pointer to look for
351 */
352 struct GNUNET_TESTBED_Operation *query;
353
354 /**
355 * The Run context operation which has the operation being queried
356 */
357 struct RunContextOperation *result;
358};
359
360
361/**
362 * Iterator for searching over the elements matching a given query
363 *
364 * @param cls the SearchContext
365 * @param key the 32-bit key
366 * @param value the RunContextOperation element
367 * @return GNUNET_YES to continue iteration; GNUNET_NO to cancel it
368 */
369static int
370search_iterator (void *cls, uint32_t key, void *value)
371{
372 struct RunContextOperation *rcop = value;
373 struct SearchContext *sc = cls;
374
375 GNUNET_assert (NULL != rcop);
376 if (sc->query == rcop->op)
377 {
378 GNUNET_assert (NULL == sc->result);
379 sc->result = rcop;
380 return GNUNET_NO;
381 }
382 return GNUNET_YES;
383}
384
385
386/**
387 * Initiate a search for the given operation in the rcop_map
388 *
389 * @param rc the RunContext whose rcop_map will be searched for the given
390 * operation
391 * @param op the given operation to search for
392 * @return the matching RunContextOperation if found; NULL if not
393 */
394static struct RunContextOperation *
395search_rcop (struct GNUNET_TESTBED_RunHandle *rc, struct
396 GNUNET_TESTBED_Operation *op)
397{
398 struct SearchContext sc;
399
400 sc.query = op;
401 sc.result = NULL;
402 if (GNUNET_SYSERR ==
403 GNUNET_CONTAINER_multihashmap32_get_multiple (rc->rcop_map,
404 rcop_key (op),
405 &search_iterator,
406 &sc))
407 {
408 GNUNET_assert (NULL != sc.result);
409 return sc.result;
410 }
411 return NULL;
412}
413
414
415/**
416 * Insert an RunContextOperation into the rcop_map of the given RunContext
417 *
418 * @param rc the RunContext into whose map is to be used for insertion
419 * @param rcop the RunContextOperation to insert
420 */
421static void
422insert_rcop (struct GNUNET_TESTBED_RunHandle *rc, struct
423 RunContextOperation *rcop)
424{
425 GNUNET_assert (GNUNET_OK ==
426 GNUNET_CONTAINER_multihashmap32_put (rc->rcop_map,
427 rcop_key (rcop->op), rcop,
428 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
429}
430
431
432/**
433 * Remove a RunContextOperation from the rcop_map of the given RunContext
434 *
435 * @param rc the RunContext from whose map the given RunContextOperaton has to
436 * be removed
437 * @param rcop the RunContextOperation
438 */
439static void
440remove_rcop (struct GNUNET_TESTBED_RunHandle *rc, struct
441 RunContextOperation *rcop)
442{
443 GNUNET_assert (GNUNET_YES ==
444 GNUNET_CONTAINER_multihashmap32_remove (rc->rcop_map,
445 rcop_key (rcop->op),
446 rcop));
447}
448
449
450/**
451 * Assuming all peers have been destroyed cleanup run handle
452 *
453 * @param rc the run context
454 */
455static void
456cleanup (struct GNUNET_TESTBED_RunHandle *rc)
457{
458 unsigned int hid;
459
460 GNUNET_assert (NULL == rc->register_hosts_task);
461 GNUNET_assert (NULL == rc->reg_handle);
462 GNUNET_assert (NULL == rc->peers);
463 GNUNET_assert (NULL == rc->hclist);
464 GNUNET_assert (RC_PEERS_SHUTDOWN == rc->state);
465 GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (rc->rcop_map));
466 GNUNET_CONTAINER_multihashmap32_destroy (rc->rcop_map);
467 if (NULL != rc->c)
468 GNUNET_TESTBED_controller_disconnect (rc->c);
469 if (NULL != rc->cproc)
470 GNUNET_TESTBED_controller_stop (rc->cproc);
471 if (NULL != rc->h)
472 GNUNET_TESTBED_host_destroy (rc->h);
473 for (hid = 0; hid < rc->num_hosts; hid++)
474 GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
475 GNUNET_free (rc->hosts);
476 if (NULL != rc->cfg)
477 GNUNET_CONFIGURATION_destroy (rc->cfg);
478 GNUNET_free (rc->topo_file);
479 GNUNET_free (rc->trusted_ip);
480 GNUNET_free (rc);
481}
482
483
484/**
485 * Iterator for cleaning up elements from rcop_map
486 *
487 * @param cls the RunContext
488 * @param key the 32-bit key
489 * @param value the RunContextOperation element
490 * @return always GNUNET_YES
491 */
492static int
493rcop_cleanup_iterator (void *cls, uint32_t key, void *value)
494{
495 struct GNUNET_TESTBED_RunHandle *rc = cls;
496 struct RunContextOperation *rcop = value;
497
498 GNUNET_assert (rc == rcop->rc);
499 remove_rcop (rc, rcop);
500 GNUNET_TESTBED_operation_done (rcop->op);
501 GNUNET_free (rcop);
502 return GNUNET_YES;
503}
504
505
506/**
507 * Cancels operations and tasks which are assigned to the given run context
508 *
509 * @param rc the RunContext
510 */
511static void
512rc_cleanup_operations (struct GNUNET_TESTBED_RunHandle *rc)
513{
514 struct CompatibilityCheckContext *hc;
515 unsigned int nhost;
516
517 if (NULL != rc->hclist)
518 {
519 for (nhost = 0; nhost < rc->num_hosts; nhost++)
520 {
521 hc = &rc->hclist[nhost];
522 if (NULL != hc->h)
523 GNUNET_TESTBED_is_host_habitable_cancel (hc->h);
524 }
525 GNUNET_free (rc->hclist);
526 rc->hclist = NULL;
527 }
528 /* Stop register hosts task if it is running */
529 if (NULL != rc->register_hosts_task)
530 {
531 GNUNET_SCHEDULER_cancel (rc->register_hosts_task);
532 rc->register_hosts_task = NULL;
533 }
534 if (NULL != rc->timeout_task)
535 {
536 GNUNET_SCHEDULER_cancel (rc->timeout_task);
537 rc->timeout_task = NULL;
538 }
539 if (NULL != rc->reg_handle)
540 {
541 GNUNET_TESTBED_cancel_registration (rc->reg_handle);
542 rc->reg_handle = NULL;
543 }
544 if (NULL != rc->topology_operation)
545 {
546 GNUNET_TESTBED_operation_done (rc->topology_operation);
547 rc->topology_operation = NULL;
548 }
549 /* cancel any exiting operations */
550 GNUNET_assert (GNUNET_SYSERR !=
551 GNUNET_CONTAINER_multihashmap32_iterate (rc->rcop_map,
552 &rcop_cleanup_iterator,
553 rc));
554}
555
556
557/**
558 * Cancels the scheduled interrupt task
559 *
560 * @param rc the run context
561 */
562static void
563cancel_interrupt_task (struct GNUNET_TESTBED_RunHandle *rc)
564{
565 GNUNET_SCHEDULER_cancel (rc->interrupt_task);
566 rc->interrupt_task = NULL;
567}
568
569
570/**
571 * This callback will be called when all the operations are completed
572 * (done/cancelled)
573 *
574 * @param cls run context
575 */
576static void
577wait_op_completion (void *cls)
578{
579 struct GNUNET_TESTBED_RunHandle *rc = cls;
580 struct RunContextOperation *rcop;
581
582 if ((NULL == rc->cproc)
583 || (NULL == rc->c)
584 || (GNUNET_YES == rc->shutdown))
585 {
586 if (NULL != rc->peers)
587 {
588 GNUNET_free (rc->peers);
589 rc->peers = NULL;
590 }
591 goto cleanup_;
592 }
593 if (NULL == rc->peers)
594 goto cleanup_;
595 rc->shutdown = GNUNET_YES;
596 rcop = GNUNET_new (struct RunContextOperation);
597 rcop->rc = rc;
598 rcop->op = GNUNET_TESTBED_shutdown_peers (rc->c, rcop, NULL, NULL);
599 GNUNET_assert (NULL != rcop->op);
600 DEBUG ("Shutting down peers\n");
601 rc->pstart_time = GNUNET_TIME_absolute_get ();
602 insert_rcop (rc, rcop);
603 return;
604
605cleanup_:
606 rc->state = RC_PEERS_SHUTDOWN;
607 cancel_interrupt_task (rc);
608 cleanup (rc);
609}
610
611
612/**
613 * Task run upon interrupts (SIGINT, SIGTERM) and upon scheduler shutdown.
614 *
615 * @param cls the RunContext which has to be acted upon
616 */
617static void
618interrupt (void *cls)
619{
620 struct GNUNET_TESTBED_RunHandle *rc = cls;
621 struct GNUNET_TESTBED_Controller *c = rc->c;
622 unsigned int size;
623
624 /* reschedule */
625 rc->interrupt_task = GNUNET_SCHEDULER_add_shutdown (&interrupt, rc);
626 rc_cleanup_operations (rc);
627 if ((GNUNET_NO == rc->shutdown) &&
628 (NULL != c) &&
629 (NULL != c->opc_map) &&
630 (0 != (size = GNUNET_CONTAINER_multihashmap32_size (c->opc_map))))
631 {
632 LOG (GNUNET_ERROR_TYPE_WARNING,
633 "Shutdown postponed as there are %u operations currently active\n",
634 size);
635 c->opcq_empty_cb = &wait_op_completion;
636 c->opcq_empty_cls = rc;
637 return;
638 }
639 wait_op_completion (rc);
640}
641
642
643/**
644 * Function to return the string representation of the duration between current
645 * time and `pstart_time' in `RunContext'
646 *
647 * @param rc the RunContext
648 * @return the representation string; this is NOT reentrant
649 */
650static const char *
651prof_time (struct GNUNET_TESTBED_RunHandle *rc)
652{
653 struct GNUNET_TIME_Relative ptime;
654
655 ptime = GNUNET_TIME_absolute_get_duration (rc->pstart_time);
656 return GNUNET_STRINGS_relative_time_to_string (ptime, GNUNET_YES);
657}
658
659
660/**
661 * Task for starting peers
662 *
663 * @param cls the RunHandle
664 */
665static void
666start_peers_task (void *cls)
667{
668 struct GNUNET_TESTBED_RunHandle *rc = cls;
669 struct RunContextOperation *rcop;
670 unsigned int peer;
671
672 DEBUG ("Starting Peers\n");
673 rc->pstart_time = GNUNET_TIME_absolute_get ();
674 for (peer = 0; peer < rc->num_peers; peer++)
675 {
676 rcop = GNUNET_new (struct RunContextOperation);
677 rcop->rc = rc;
678 rcop->op = GNUNET_TESTBED_peer_start (NULL, rc->peers[peer], NULL, NULL);
679 GNUNET_assert (NULL != rcop->op);
680 rcop->cls = rc->peers[peer];
681 insert_rcop (rc, rcop);
682 }
683 rc->peer_count = 0;
684}
685
686
687/**
688 * Functions of this signature are called when a peer has been successfully
689 * created
690 *
691 * @param cls the closure from GNUNET_TESTBED_peer_create()
692 * @param peer the handle for the created peer; NULL on any error during
693 * creation
694 * @param emsg NULL if peer is not NULL; else MAY contain the error description
695 */
696static void
697peer_create_cb (void *cls, struct GNUNET_TESTBED_Peer *peer, const char *emsg)
698{
699 struct RunContextOperation *rcop = cls;
700 struct GNUNET_TESTBED_RunHandle *rc;
701
702 GNUNET_assert (NULL != rcop);
703 GNUNET_assert (NULL != (rc = rcop->rc));
704 remove_rcop (rc, rcop);
705 GNUNET_TESTBED_operation_done (rcop->op);
706 GNUNET_free (rcop);
707 if (NULL == peer)
708 {
709 if (NULL != emsg)
710 LOG (GNUNET_ERROR_TYPE_ERROR, "Error while creating a peer: %s\n",
711 emsg);
712 GNUNET_SCHEDULER_shutdown ();
713 return;
714 }
715 rc->peers[rc->peer_count] = peer;
716 rc->peer_count++;
717 if (rc->peer_count < rc->num_peers)
718 return;
719 DEBUG ("%u peers created in %s\n", rc->num_peers, prof_time (rc));
720 rc->state = RC_PEERS_CREATED;
721 GNUNET_SCHEDULER_add_now (&start_peers_task, rc);
722}
723
724
725/**
726 * call test master callback
727 *
728 * @param rc the RunContext
729 */
730static void
731call_master (struct GNUNET_TESTBED_RunHandle *rc)
732{
733 GNUNET_SCHEDULER_cancel (rc->timeout_task);
734 rc->timeout_task = NULL;
735 if (NULL != rc->test_master)
736 rc->test_master (rc->test_master_cls, rc, rc->num_peers, rc->peers,
737 rc->links_succeeded, rc->links_failed);
738}
739
740
741/**
742 * Callbacks of this type are called when topology configuration is completed
743 *
744 * @param cls the operation closure given to
745 * GNUNET_TESTBED_overlay_configure_topology_va() and
746 * GNUNET_TESTBED_overlay_configure() calls
747 * @param nsuccess the number of successful overlay connects
748 * @param nfailures the number of overlay connects which failed
749 */
750static void
751topology_completion_callback (void *cls, unsigned int nsuccess,
752 unsigned int nfailures)
753{
754 struct GNUNET_TESTBED_RunHandle *rc = cls;
755
756 DEBUG ("Overlay topology generated in %s\n", prof_time (rc));
757 GNUNET_TESTBED_operation_done (rc->topology_operation);
758 rc->topology_operation = NULL;
759 rc->links_succeeded = nsuccess;
760 rc->links_failed = nfailures;
761 rc->state = RC_READY;
762 call_master (rc);
763}
764
765
766/**
767 * Function to create peers
768 *
769 * @param rc the RunContext
770 */
771static void
772create_peers (struct GNUNET_TESTBED_RunHandle *rc)
773{
774 struct RunContextOperation *rcop;
775 unsigned int peer;
776
777 DEBUG ("Creating peers\n");
778 rc->pstart_time = GNUNET_TIME_absolute_get ();
779 rc->peers =
780 GNUNET_malloc (sizeof(struct GNUNET_TESTBED_Peer *) * rc->num_peers);
781 GNUNET_assert (NULL != rc->c);
782 rc->peer_count = 0;
783 for (peer = 0; peer < rc->num_peers; peer++)
784 {
785 rcop = GNUNET_new (struct RunContextOperation);
786 rcop->rc = rc;
787 rcop->op =
788 GNUNET_TESTBED_peer_create (rc->c,
789 (0 ==
790 rc->num_hosts) ? rc->h : rc->hosts[peer
791 % rc->
792 num_hosts],
793 rc->cfg, &peer_create_cb, rcop);
794 GNUNET_assert (NULL != rcop->op);
795 insert_rcop (rc, rcop);
796 }
797}
798
799
800/**
801 * Signature of the event handler function called by the
802 * respective event controller.
803 *
804 * @param cls closure
805 * @param event information about the event
806 */
807static void
808event_cb (void *cls, const struct GNUNET_TESTBED_EventInformation *event)
809{
810 struct GNUNET_TESTBED_RunHandle *rc = cls;
811 struct RunContextOperation *rcop;
812
813 if (RC_INIT == rc->state)
814 {
815 switch (event->type)
816 {
817 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
818 rcop = event->op_cls;
819 if (NULL != event->details.operation_finished.emsg)
820 {
821 LOG (GNUNET_ERROR_TYPE_ERROR, _ (
822 "Linking controllers failed. Exiting"));
823 GNUNET_SCHEDULER_shutdown ();
824 }
825 else
826 rc->reg_hosts++;
827 GNUNET_assert (event->op == rcop->op);
828 remove_rcop (rc, rcop);
829 GNUNET_TESTBED_operation_done (rcop->op);
830 GNUNET_free (rcop);
831 if (rc->reg_hosts == rc->num_hosts)
832 {
833 rc->state = RC_LINKED;
834 create_peers (rc);
835 }
836 return;
837
838 default:
839 GNUNET_break (0);
840 GNUNET_SCHEDULER_shutdown ();
841 return;
842 }
843 }
844 if (GNUNET_TESTBED_ET_OPERATION_FINISHED != event->type)
845 goto call_cc;
846 if (NULL == (rcop = search_rcop (rc, event->op)))
847 goto call_cc;
848 remove_rcop (rc, rcop);
849 GNUNET_TESTBED_operation_done (rcop->op);
850 GNUNET_free (rcop);
851 if ((GNUNET_NO == rc->shutdown)
852 && (NULL != event->details.operation_finished.emsg))
853 {
854 LOG (GNUNET_ERROR_TYPE_ERROR, "A operation has failed with error: %s\n",
855 event->details.operation_finished.emsg);
856 GNUNET_SCHEDULER_shutdown ();
857 return;
858 }
859 GNUNET_assert (GNUNET_YES == rc->shutdown);
860 switch (rc->state)
861 {
862 case RC_LINKED:
863 case RC_PEERS_CREATED:
864 case RC_READY:
865 rc->state = RC_PEERS_SHUTDOWN;
866 GNUNET_free (rc->peers);
867 rc->peers = NULL;
868 DEBUG ("Peers shut down in %s\n", prof_time (rc));
869 GNUNET_SCHEDULER_shutdown ();
870 break;
871
872 default:
873 GNUNET_assert (0);
874 }
875 return;
876
877call_cc:
878 if ((0 != (rc->event_mask & (1LL << event->type))) && (NULL != rc->cc))
879 rc->cc (rc->cc_cls, event);
880 if (GNUNET_TESTBED_ET_PEER_START != event->type)
881 return;
882 if (NULL == (rcop = search_rcop (rc, event->op))) /* Not our operation */
883 return;
884 remove_rcop (rc, rcop);
885 GNUNET_TESTBED_operation_done (rcop->op);
886 GNUNET_free (rcop);
887 rc->peer_count++;
888 if (rc->peer_count < rc->num_peers)
889 return;
890 DEBUG ("%u peers started in %s\n", rc->num_peers, prof_time (rc));
891 if (GNUNET_TESTBED_TOPOLOGY_NONE != rc->topology)
892 {
893 switch (rc->topology)
894 {
895 case GNUNET_TESTBED_TOPOLOGY_NONE:
896 GNUNET_assert (0);
897
898 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
899 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
900 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
901 rc->topology_operation =
902 GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
903 rc->peers, &rc->num_oc,
904 &topology_completion_callback,
905 rc,
906 rc->topology,
907 rc->random_links,
908 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
909 break;
910
911 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
912 GNUNET_assert (NULL != rc->topo_file);
913 rc->topology_operation =
914 GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
915 rc->peers, &rc->num_oc,
916 &topology_completion_callback,
917 rc,
918 rc->topology,
919 rc->topo_file,
920 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
921 break;
922
923 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
924 {
925 unsigned long long number;
926 unsigned int cap;
927 GNUNET_assert (GNUNET_OK ==
928 GNUNET_CONFIGURATION_get_value_number (rc->cfg,
929 TESTBED_CONFIG_SECTION,
930 SCALE_FREE_CAP,
931 &number));
932 cap = (unsigned int) number;
933 GNUNET_assert (GNUNET_OK ==
934 GNUNET_CONFIGURATION_get_value_number (rc->cfg,
935 TESTBED_CONFIG_SECTION,
936 SCALE_FREE_M,
937 &number));
938 rc->topology_operation =
939 GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
940 rc->peers, &rc->num_oc,
941 &
942 topology_completion_callback,
943 rc,
944 rc->topology,
945 cap, /* uint16_t */
946 (unsigned int) number, /* uint8_t */
947 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
948 }
949 break;
950
951 default:
952 rc->topology_operation =
953 GNUNET_TESTBED_overlay_configure_topology (NULL, rc->num_peers,
954 rc->peers, &rc->num_oc,
955 &topology_completion_callback,
956 rc,
957 rc->topology,
958 GNUNET_TESTBED_TOPOLOGY_OPTION_END);
959 }
960 if (NULL == rc->topology_operation)
961 LOG (GNUNET_ERROR_TYPE_WARNING,
962 "Not generating a topology. Check number of peers\n");
963 else
964 {
965 DEBUG ("Creating overlay topology\n");
966 rc->pstart_time = GNUNET_TIME_absolute_get ();
967 return;
968 }
969 }
970 rc->state = RC_READY;
971 call_master (rc);
972}
973
974
975/**
976 * Task to register all hosts available in the global host list
977 *
978 * @param cls the RunContext
979 */
980static void
981register_hosts (void *cls);
982
983
984/**
985 * Callback which will be called to after a host registration succeeded or failed
986 *
987 * @param cls the closure
988 * @param emsg the error message; NULL if host registration is successful
989 */
990static void
991host_registration_completion (void *cls, const char *emsg)
992{
993 struct GNUNET_TESTBED_RunHandle *rc = cls;
994
995 rc->reg_handle = NULL;
996 if (NULL != emsg)
997 {
998 LOG (GNUNET_ERROR_TYPE_WARNING,
999 _ ("Host registration failed for a host. Error: %s\n"), emsg);
1000 GNUNET_SCHEDULER_shutdown ();
1001 return;
1002 }
1003 rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts,
1004 rc);
1005}
1006
1007
1008static void
1009register_hosts (void *cls)
1010{
1011 struct GNUNET_TESTBED_RunHandle *rc = cls;
1012 struct RunContextOperation *rcop;
1013 unsigned int slave;
1014
1015 rc->register_hosts_task = NULL;
1016 if (rc->reg_hosts == rc->num_hosts)
1017 {
1018 DEBUG ("All hosts successfully registered\n");
1019 /* Start slaves */
1020 for (slave = 0; slave < rc->num_hosts; slave++)
1021 {
1022 rcop = GNUNET_new (struct RunContextOperation);
1023 rcop->rc = rc;
1024 rcop->op =
1025 GNUNET_TESTBED_controller_link (rcop, rc->c, rc->hosts[slave],
1026 rc->h, GNUNET_YES);
1027 GNUNET_assert (NULL != rcop->op);
1028 insert_rcop (rc, rcop);
1029 }
1030 rc->reg_hosts = 0;
1031 return;
1032 }
1033 rc->reg_handle =
1034 GNUNET_TESTBED_register_host (rc->c, rc->hosts[rc->reg_hosts],
1035 host_registration_completion, rc);
1036 rc->reg_hosts++;
1037}
1038
1039
1040/**
1041 * Callback to signal successful startup of the controller process
1042 *
1043 * @param cls the closure from GNUNET_TESTBED_controller_start()
1044 * @param cfg the configuration with which the controller has been started;
1045 * NULL if status is not GNUNET_OK
1046 * @param status GNUNET_OK if the startup is successful; GNUNET_SYSERR if not,
1047 * GNUNET_TESTBED_controller_stop() shouldn't be called in this case
1048 */
1049static void
1050controller_status_cb (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
1051 int status)
1052{
1053 struct GNUNET_TESTBED_RunHandle *rc = cls;
1054 uint64_t event_mask;
1055
1056 if (status != GNUNET_OK)
1057 {
1058 rc->cproc = NULL;
1059 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1060 _ ("Controller crash detected. Shutting down.\n"));
1061 GNUNET_SCHEDULER_shutdown ();
1062 return;
1063 }
1064 GNUNET_CONFIGURATION_destroy (rc->cfg);
1065 rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1066 event_mask = rc->event_mask;
1067 event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1068 event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
1069 if (rc->topology < GNUNET_TESTBED_TOPOLOGY_NONE)
1070 event_mask |= GNUNET_TESTBED_ET_CONNECT;
1071 rc->c =
1072 GNUNET_TESTBED_controller_connect (rc->h, event_mask, &event_cb, rc);
1073 if (0 < rc->num_hosts)
1074 {
1075 rc->reg_hosts = 0;
1076 rc->register_hosts_task = GNUNET_SCHEDULER_add_now (&register_hosts, rc);
1077 return;
1078 }
1079 rc->state = RC_LINKED;
1080 create_peers (rc);
1081}
1082
1083
1084/**
1085 * Callback function invoked for each interface found.
1086 *
1087 * @param cls closure
1088 * @param name name of the interface (can be NULL for unknown)
1089 * @param isDefault is this presumably the default interface
1090 * @param addr address of this interface (can be NULL for unknown or unassigned)
1091 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
1092 * @param netmask the network mask (can be NULL for unknown or unassigned))
1093 * @param addrlen length of the address
1094 * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
1095 */
1096static int
1097netint_proc (void *cls, const char *name, int isDefault,
1098 const struct sockaddr *addr, const struct sockaddr *broadcast_addr,
1099 const struct sockaddr *netmask, socklen_t addrlen)
1100{
1101 struct GNUNET_TESTBED_RunHandle *rc = cls;
1102 char hostip[NI_MAXHOST];
1103 char *buf;
1104
1105 if (sizeof(struct sockaddr_in) != addrlen)
1106 return GNUNET_OK; /* Only consider IPv4 for now */
1107 if (0 !=
1108 getnameinfo (addr, addrlen, hostip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))
1109 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getnameinfo");
1110 if (NULL == rc->trusted_ip)
1111 {
1112 rc->trusted_ip = GNUNET_strdup (hostip);
1113 return GNUNET_YES;
1114 }
1115 (void) GNUNET_asprintf (&buf, "%s; %s", rc->trusted_ip, hostip);
1116 GNUNET_free (rc->trusted_ip);
1117 rc->trusted_ip = buf;
1118 return GNUNET_YES;
1119}
1120
1121
1122/**
1123 * Callbacks of this type are called by GNUNET_TESTBED_is_host_habitable to
1124 * inform whether the given host is habitable or not. The Handle returned by
1125 * GNUNET_TESTBED_is_host_habitable() is invalid after this callback is called
1126 *
1127 * @param cls NULL
1128 * @param host the host whose status is being reported; will be NULL if the host
1129 * given to GNUNET_TESTBED_is_host_habitable() is NULL
1130 * @param status GNUNET_YES if it is habitable; GNUNET_NO if not
1131 */
1132static void
1133host_habitable_cb (void *cls, const struct GNUNET_TESTBED_Host *host,
1134 int status)
1135{
1136 struct CompatibilityCheckContext *hc = cls;
1137 struct GNUNET_TESTBED_RunHandle *rc;
1138 struct GNUNET_TESTBED_Host **old_hosts;
1139 unsigned int nhost;
1140
1141 GNUNET_assert (NULL != (rc = hc->rc));
1142 nhost = hc->index;
1143 GNUNET_assert (nhost <= rc->num_hosts);
1144 GNUNET_assert (host == rc->hosts[nhost]);
1145 hc->h = NULL;
1146 if (GNUNET_NO == status)
1147 {
1148 if ((NULL != host) && (NULL != GNUNET_TESTBED_host_get_hostname (host)))
1149 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Host %s cannot start testbed\n"),
1150 GNUNET_TESTBED_host_get_hostname (host));
1151 else
1152 LOG (GNUNET_ERROR_TYPE_ERROR,
1153 _ ("Testbed cannot be started on localhost\n"));
1154 GNUNET_SCHEDULER_shutdown ();
1155 return;
1156 }
1157 rc->reg_hosts++;
1158 if (rc->reg_hosts < rc->num_hosts)
1159 return;
1160 GNUNET_free (rc->hclist);
1161 rc->hclist = NULL;
1162 rc->h = rc->hosts[0];
1163 rc->num_hosts--;
1164 if (0 < rc->num_hosts)
1165 {
1166 old_hosts = rc->hosts;
1167 rc->hosts =
1168 GNUNET_malloc (sizeof(struct GNUNET_TESTBED_Host *) * rc->num_hosts);
1169 GNUNET_memcpy (rc->hosts, &old_hosts[1],
1170 (sizeof(struct GNUNET_TESTBED_Host *) * rc->num_hosts));
1171 GNUNET_free (old_hosts);
1172 }
1173 else
1174 {
1175 GNUNET_free (rc->hosts);
1176 rc->hosts = NULL;
1177 }
1178 GNUNET_TESTBED_host_resolve_ (rc->h);
1179 for (nhost = 0; nhost < rc->num_hosts; nhost++)
1180 GNUNET_TESTBED_host_resolve_ (rc->hosts[nhost]);
1181 GNUNET_OS_network_interfaces_list (netint_proc, rc);
1182 if (NULL == rc->trusted_ip)
1183 rc->trusted_ip = GNUNET_strdup ("127.0.0.1");
1184 rc->cproc =
1185 GNUNET_TESTBED_controller_start (rc->trusted_ip, rc->h,
1186 &controller_status_cb, rc);
1187 GNUNET_free (rc->trusted_ip);
1188 rc->trusted_ip = NULL;
1189 if (NULL == rc->cproc)
1190 {
1191 LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Cannot start the master controller"));
1192 GNUNET_SCHEDULER_shutdown ();
1193 }
1194}
1195
1196
1197/**
1198 * Task run upon timeout while setting up the testbed
1199 *
1200 * @param cls the RunContext
1201 */
1202static void
1203timeout_task (void *cls)
1204{
1205 struct GNUNET_TESTBED_RunHandle *rc = cls;
1206
1207 rc->timeout_task = NULL;
1208 LOG (GNUNET_ERROR_TYPE_ERROR,
1209 _ ("Shutting down testbed due to timeout while setup.\n"));
1210 GNUNET_SCHEDULER_shutdown ();
1211 if (NULL != rc->test_master)
1212 rc->test_master (rc->test_master_cls, rc, 0, NULL, 0, 0);
1213 rc->test_master = NULL;
1214}
1215
1216
1217/**
1218 * Convenience method for running a testbed with
1219 * a single call. Underlay and overlay topology
1220 * are configured using the "UNDERLAY" and "OVERLAY"
1221 * options in the "[testbed]" section of the configuration\
1222 * (with possible options given in "UNDERLAY_XXX" and/or
1223 * "OVERLAY_XXX").
1224 *
1225 * The testbed is to be terminated using a call to
1226 * "GNUNET_SCHEDULER_shutdown".
1227 *
1228 * @param host_filename name of the file with the 'hosts', NULL
1229 * to run everything on 'localhost'
1230 * @param cfg configuration to use (for testbed, controller and peers)
1231 * @param num_peers number of peers to start; FIXME: maybe put that ALSO into cfg?
1232 * @param event_mask bit mask with set of events to call 'cc' for;
1233 * or-ed values of "1LL" shifted by the
1234 * respective 'enum GNUNET_TESTBED_EventType'
1235 * (e.g. "(1LL << GNUNET_TESTBED_ET_CONNECT) || ...")
1236 * @param cc controller callback to invoke on events; This callback is called
1237 * for all peer start events even if GNUNET_TESTBED_ET_PEER_START isn't
1238 * set in the event_mask as this is the only way get access to the
1239 * handle of each peer
1240 * @param cc_cls closure for cc
1241 * @param test_master this callback will be called once the test is ready
1242 * @param test_master_cls closure for 'test_master'.
1243 */
1244void
1245GNUNET_TESTBED_run (const char *host_filename,
1246 const struct GNUNET_CONFIGURATION_Handle *cfg,
1247 unsigned int num_peers, uint64_t event_mask,
1248 GNUNET_TESTBED_ControllerCallback cc, void *cc_cls,
1249 GNUNET_TESTBED_TestMaster test_master,
1250 void *test_master_cls)
1251{
1252 struct GNUNET_TESTBED_RunHandle *rc;
1253 char *topology;
1254 struct CompatibilityCheckContext *hc;
1255 struct GNUNET_TIME_Relative timeout;
1256 unsigned long long number;
1257 unsigned int hid;
1258 unsigned int nhost;
1259
1260 GNUNET_assert (num_peers > 0);
1261 rc = GNUNET_new (struct GNUNET_TESTBED_RunHandle);
1262 rc->cfg = GNUNET_CONFIGURATION_dup (cfg);
1263 if (NULL != host_filename)
1264 {
1265 rc->num_hosts =
1266 GNUNET_TESTBED_hosts_load_from_file (host_filename, rc->cfg,
1267 &rc->hosts);
1268 if (0 == rc->num_hosts)
1269 {
1270 LOG (GNUNET_ERROR_TYPE_WARNING,
1271 _ ("No hosts loaded. Need at least one host\n"));
1272 goto error_cleanup;
1273 }
1274 }
1275 else
1276 rc->h = GNUNET_TESTBED_host_create (NULL, NULL, rc->cfg, 0);
1277 rc->num_peers = num_peers;
1278 rc->event_mask = event_mask;
1279 rc->cc = cc;
1280 rc->cc_cls = cc_cls;
1281 rc->test_master = test_master;
1282 rc->test_master_cls = test_master_cls;
1283 rc->state = RC_INIT;
1284 rc->topology = GNUNET_TESTBED_TOPOLOGY_NONE;
1285 if (GNUNET_OK ==
1286 GNUNET_CONFIGURATION_get_value_string (rc->cfg, TESTBED_CONFIG_SECTION,
1287 "OVERLAY_TOPOLOGY", &topology))
1288 {
1289 if (GNUNET_NO == GNUNET_TESTBED_topology_get_ (&rc->topology, topology))
1290 {
1291 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1292 TESTBED_CONFIG_SECTION,
1293 "OVERLAY_TOPLOGY",
1294 _
1295 (
1296 "Specified topology must be supported by testbed"));
1297 }
1298 GNUNET_free (topology);
1299 }
1300 switch (rc->topology)
1301 {
1302 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1303 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1304 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1305 if (GNUNET_OK !=
1306 GNUNET_CONFIGURATION_get_value_number (rc->cfg, TESTBED_CONFIG_SECTION,
1307 "OVERLAY_RANDOM_LINKS",
1308 &number))
1309 {
1310 /* OVERLAY option RANDOM & SMALL_WORLD_RING requires OVERLAY_RANDOM_LINKS
1311 * option to be set to the number of random links to be established */
1312 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1313 TESTBED_CONFIG_SECTION,
1314 "OVERLAY_RANDOM_LINKS");
1315 goto error_cleanup;
1316 }
1317 if (number > UINT32_MAX)
1318 {
1319 GNUNET_break (0); /* Too big number */
1320 goto error_cleanup;
1321 }
1322 rc->random_links = (unsigned int) number;
1323 break;
1324
1325 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1326 if (GNUNET_OK !=
1327 GNUNET_CONFIGURATION_get_value_filename (rc->cfg,
1328 TESTBED_CONFIG_SECTION,
1329 "OVERLAY_TOPOLOGY_FILE",
1330 &rc->topo_file))
1331 {
1332 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1333 TESTBED_CONFIG_SECTION,
1334 "OVERLAY_TOPOLOGY_FILE");
1335 goto error_cleanup;
1336 }
1337 goto warn_ignore;
1338
1339 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
1340 if (GNUNET_OK !=
1341 GNUNET_CONFIGURATION_get_value_number (rc->cfg, TESTBED_CONFIG_SECTION,
1342 SCALE_FREE_CAP, &number))
1343 {
1344 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1345 TESTBED_CONFIG_SECTION,
1346 SCALE_FREE_CAP);
1347 goto error_cleanup;
1348 }
1349 if (UINT16_MAX < number)
1350 {
1351 LOG (GNUNET_ERROR_TYPE_ERROR,
1352 _ ("Maximum number of edges a peer can have in a scale free topology"
1353 " cannot be more than %u. Given `%s = %llu'"), UINT16_MAX,
1354 SCALE_FREE_CAP, number);
1355 goto error_cleanup;
1356 }
1357 if (GNUNET_OK !=
1358 GNUNET_CONFIGURATION_get_value_number (rc->cfg, TESTBED_CONFIG_SECTION,
1359 SCALE_FREE_M, &number))
1360 {
1361 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1362 TESTBED_CONFIG_SECTION,
1363 SCALE_FREE_M);
1364 goto error_cleanup;
1365 }
1366 if (UINT8_MAX < number)
1367 {
1368 LOG (GNUNET_ERROR_TYPE_ERROR,
1369 _ ("The number of edges that can established when adding a new node"
1370 " to scale free topology cannot be more than %u. Given `%s = %llu'"),
1371 UINT8_MAX, SCALE_FREE_M, number);
1372 goto error_cleanup;
1373 }
1374 goto warn_ignore;
1375
1376 case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
1377 /* not allowed! */
1378 GNUNET_assert (0);
1379
1380 default:
1381warn_ignore:
1382 /* Warn if OVERLAY_RANDOM_LINKS is present that it will be ignored */
1383 if (GNUNET_YES ==
1384 GNUNET_CONFIGURATION_have_value (rc->cfg, TESTBED_CONFIG_SECTION,
1385 "OVERLAY_RANDOM_LINKS"))
1386 LOG (GNUNET_ERROR_TYPE_WARNING,
1387 "Ignoring value of `OVERLAY_RANDOM_LINKS' in given configuration\n");
1388 break;
1389 }
1390 if (0 != rc->num_hosts)
1391 {
1392 rc->hclist = GNUNET_malloc (sizeof(struct CompatibilityCheckContext)
1393 * rc->num_hosts);
1394 for (nhost = 0; nhost < rc->num_hosts; nhost++)
1395 {
1396 hc = &rc->hclist[nhost];
1397 hc->index = nhost;
1398 hc->rc = rc;
1399 hc->h = GNUNET_TESTBED_is_host_habitable (rc->hosts[nhost], rc->cfg,
1400 &host_habitable_cb, hc);
1401 if (NULL == hc->h)
1402 {
1403 GNUNET_break (0);
1404 for (nhost = 0; nhost < rc->num_hosts; nhost++)
1405 {
1406 hc = &rc->hclist[nhost];
1407 if (NULL != hc->h)
1408 GNUNET_TESTBED_is_host_habitable_cancel (hc->h);
1409 }
1410 GNUNET_free (rc->hclist);
1411 rc->hclist = NULL;
1412 goto error_cleanup;
1413 }
1414 }
1415 }
1416 else
1417 rc->cproc =
1418 GNUNET_TESTBED_controller_start ("127.0.0.1", rc->h,
1419 &controller_status_cb, rc);
1420 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg,
1421 TESTBED_CONFIG_SECTION,
1422 "SETUP_TIMEOUT",
1423 &timeout))
1424 {
1425 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
1426 DEFAULT_SETUP_TIMEOUT);
1427 }
1428 rc->rcop_map = GNUNET_CONTAINER_multihashmap32_create (256);
1429 rc->timeout_task =
1430 GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task, rc);
1431 GNUNET_assert (NULL == rc->interrupt_task);
1432 rc->interrupt_task =
1433 GNUNET_SCHEDULER_add_shutdown (&interrupt,
1434 rc);
1435 return;
1436
1437error_cleanup:
1438 if (NULL != rc->h)
1439 GNUNET_TESTBED_host_destroy (rc->h);
1440 if (NULL != rc->hosts)
1441 {
1442 for (hid = 0; hid < rc->num_hosts; hid++)
1443 if (NULL != rc->hosts[hid])
1444 GNUNET_TESTBED_host_destroy (rc->hosts[hid]);
1445 GNUNET_free (rc->hosts);
1446 }
1447 if (NULL != rc->cfg)
1448 GNUNET_CONFIGURATION_destroy (rc->cfg);
1449 GNUNET_free (rc);
1450}
1451
1452
1453/**
1454 * Obtain handle to the master controller from a testbed run. The handle
1455 * returned should not be disconnected.
1456 *
1457 * @param h the testbed run handle
1458 * @return handle to the master controller
1459 */
1460struct GNUNET_TESTBED_Controller *
1461GNUNET_TESTBED_run_get_controller_handle (struct GNUNET_TESTBED_RunHandle *h)
1462{
1463 return h->c;
1464}
1465
1466
1467/* end of testbed_api_testbed.c */
diff --git a/src/testbed/testbed_api_topology.c b/src/testbed/testbed_api_topology.c
deleted file mode 100644
index f73be378e..000000000
--- a/src/testbed/testbed_api_topology.c
+++ /dev/null
@@ -1,1598 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_topology.c
23 * @brief topology-generation functions
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_testbed_service.h"
28#include "testbed_api.h"
29#include "testbed_api_peers.h"
30#include "testbed_api_operations.h"
31#include "testbed_api_topology.h"
32
33/**
34 * Generic loggins shorthand
35 */
36#define LOG(kind, ...) \
37 GNUNET_log_from (kind, "testbed-api-topology", __VA_ARGS__)
38
39
40/**
41 * Default number of retires
42 */
43#define DEFAULT_RETRY_CNT 3
44
45
46/**
47 * Context information for topology operations
48 */
49struct TopologyContext;
50
51
52/**
53 * Representation of an overlay link
54 */
55struct OverlayLink
56{
57 /**
58 * An operation corresponding to this link
59 */
60 struct GNUNET_TESTBED_Operation *op;
61
62 /**
63 * The topology context this link is a part of
64 */
65 struct TopologyContext *tc;
66
67 /**
68 * position of peer A's handle in peers array
69 */
70 uint32_t A;
71
72 /**
73 * position of peer B's handle in peers array
74 */
75 uint32_t B;
76};
77
78
79/**
80 * Representation of an underlay link
81 */
82struct UnderlayLink
83{
84 /**
85 * position of peer A's handle in peers array
86 */
87 uint32_t A;
88
89 /**
90 * position of peer B's handle in peers array
91 */
92 uint32_t B;
93
94 /**
95 * Bandwidth of the link in bytes per second
96 */
97 uint32_t bandwidth;
98
99 /**
100 * Latency of the link in milliseconds
101 */
102 uint32_t latency;
103
104 /**
105 * Loss in the link in percentage of message dropped
106 */
107 uint32_t loss;
108};
109
110
111struct RetryListEntry
112{
113 /**
114 * the next pointer for the DLL
115 */
116 struct RetryListEntry *next;
117
118 /**
119 * the prev pointer for the DLL
120 */
121 struct RetryListEntry *prev;
122
123 /**
124 * The link to be retired
125 */
126 struct OverlayLink *link;
127};
128
129
130/**
131 * Context information for overlay topologies
132 */
133struct TopologyContextOverlay
134{
135 /**
136 * The array of peers
137 */
138 struct GNUNET_TESTBED_Peer **peers;
139
140 /**
141 * An array of links; this array is of size link_array_size
142 */
143 struct OverlayLink *link_array;
144
145 /**
146 * The operation closure
147 */
148 void *op_cls;
149
150 /**
151 * topology generation completion callback
152 */
153 GNUNET_TESTBED_TopologyCompletionCallback comp_cb;
154
155 /**
156 * The closure for the above callback
157 */
158 void *comp_cb_cls;
159
160 /**
161 * DLL head for retry list
162 */
163 struct RetryListEntry *rl_head;
164
165 /**
166 * DLL tail for retry list
167 */
168 struct RetryListEntry *rl_tail;
169
170 /**
171 * How many retries to do before we give up
172 */
173 unsigned int retry_cnt;
174
175 /**
176 * Number of links to try
177 */
178 unsigned int nlinks;
179
180 /**
181 * How many links have been completed
182 */
183 unsigned int ncompleted;
184
185 /**
186 * Total successfully established overlay connections
187 */
188 unsigned int nsuccess;
189
190 /**
191 * Total failed overlay connections
192 */
193 unsigned int nfailures;
194};
195
196
197/**
198 * Topology context information for underlay topologies
199 */
200struct TopologyContextUnderlay
201{
202 /**
203 * The link array
204 */
205 struct UnderlayLink *link_array;
206};
207
208
209/**
210 * Context information for topology operations
211 */
212struct TopologyContext
213{
214 /**
215 * The type of this context
216 */
217 enum
218 {
219 /**
220 * Type for underlay topology
221 */
222 TOPOLOGYCONTEXT_TYPE_UNDERLAY = 0,
223
224 /**
225 * Type for overlay topology
226 */
227 TOPOLOGYCONTEXT_TYPE_OVERLAY
228 } type;
229
230 union
231 {
232 /**
233 * Topology context information for overlay topology
234 */
235 struct TopologyContextOverlay overlay;
236
237 /**
238 * Topology context information for underlay topology
239 */
240 struct TopologyContextUnderlay underlay;
241 } u;
242
243 /**
244 * The number of peers
245 */
246 unsigned int num_peers;
247
248 /**
249 * The size of the link array
250 */
251 unsigned int link_array_size;
252};
253
254
255/**
256 * A array of names representing topologies. Should be in sync with enum
257 * GNUNET_TESTBED_TopologyOption
258 */
259static const char *topology_strings[] = {
260 /**
261 * A clique (everyone connected to everyone else). No options. If there are N
262 * peers this topology results in (N * (N -1)) connections.
263 */
264 "CLIQUE",
265
266 /*
267 * Small-world network (2d torus plus random links). Followed
268 * by the number of random links to add (unsigned int).
269 */
270 "SMALL_WORLD",
271
272 /**
273 * Small-world network (ring plus random links). Followed
274 * by the number of random links to add (unsigned int).
275 */
276 "SMALL_WORLD_RING",
277
278 /**
279 * Ring topology. No options.
280 */
281 "RING",
282
283 /**
284 * Star topology. No options.
285 */
286 "STAR",
287
288 /**
289 * 2-d torus. No options.
290 */
291 "2D_TORUS",
292
293 /**
294 * Random graph. Followed by the number of random links to be established
295 * (unsigned int)
296 */
297 "RANDOM", // GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI
298
299 /**
300 * Certain percentage of peers are unable to communicate directly
301 * replicating NAT conditions. Followed by the fraction of
302 * NAT'ed peers (float).
303 */
304 "INTERNAT",
305
306 /**
307 * Scale free topology. Followed by the maximum number of links a node can
308 * have (unsigned int); and the number of links a new node should have when
309 * it is added to the network (unsigned int)
310 */
311 "SCALE_FREE",
312
313 /**
314 * Straight line topology. No options.
315 */
316 "LINE",
317
318 /**
319 * Read a topology from a given file. Followed by the name of the file (const char *).
320 */
321 "FROM_FILE",
322
323 /**
324 * All peers are disconnected. No options.
325 */
326 "NONE",
327
328 /**
329 * End of strings
330 */
331 NULL
332};
333
334
335/**
336 * Callback to be called when an overlay_link operation complete
337 *
338 * @param cls element of the link_op array which points to the corresponding operation
339 * @param op the operation that has been finished
340 * @param emsg error message in case the operation has failed; will be NULL if
341 * operation has executed successfully.
342 */
343static void
344overlay_link_completed (void *cls,
345 struct GNUNET_TESTBED_Operation *op,
346 const char *emsg)
347{
348 struct OverlayLink *link = cls;
349 struct TopologyContext *tc;
350 struct TopologyContextOverlay *overlay;
351 struct RetryListEntry *retry_entry;
352
353 GNUNET_assert (op == link->op);
354 GNUNET_TESTBED_operation_done (op);
355 link->op = NULL;
356 tc = link->tc;
357 GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
358 overlay = &tc->u.overlay;
359 if (NULL != emsg)
360 {
361 overlay->nfailures++;
362 if (0 != overlay->retry_cnt)
363 {
364 LOG (GNUNET_ERROR_TYPE_WARNING,
365 "Error while establishing a link: %s -- Retrying\n",
366 emsg);
367 retry_entry = GNUNET_new (struct RetryListEntry);
368 retry_entry->link = link;
369 GNUNET_CONTAINER_DLL_insert_tail (overlay->rl_head,
370 overlay->rl_tail,
371 retry_entry);
372 }
373 }
374 else
375 overlay->nsuccess++;
376 overlay->ncompleted++;
377 if (overlay->ncompleted < overlay->nlinks)
378 return;
379 if ((0 != overlay->retry_cnt) && (NULL != overlay->rl_head))
380 {
381 overlay->retry_cnt--;
382 overlay->ncompleted = 0;
383 overlay->nlinks = 0;
384 while (NULL != (retry_entry = overlay->rl_head))
385 {
386 link = retry_entry->link;
387 link->op =
388 GNUNET_TESTBED_overlay_connect (overlay->op_cls,
389 &overlay_link_completed,
390 link,
391 overlay->peers[link->A],
392 overlay->peers[link->B]);
393 overlay->nlinks++;
394 GNUNET_CONTAINER_DLL_remove (overlay->rl_head,
395 overlay->rl_tail,
396 retry_entry);
397 GNUNET_free (retry_entry);
398 }
399 return;
400 }
401 if (NULL != overlay->comp_cb)
402 {
403 overlay->comp_cb (overlay->comp_cb_cls,
404 overlay->nsuccess,
405 overlay->nfailures);
406 }
407}
408
409
410/**
411 * Function called when a overlay connect operation is ready
412 *
413 * @param cls the Topology context
414 */
415static void
416opstart_overlay_configure_topology (void *cls)
417{
418 struct TopologyContext *tc = cls;
419 struct TopologyContextOverlay *overlay;
420 unsigned int p;
421
422 GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
423 overlay = &tc->u.overlay;
424 overlay->nlinks = tc->link_array_size;
425 for (p = 0; p < tc->link_array_size; p++)
426 {
427 overlay->link_array[p].op =
428 GNUNET_TESTBED_overlay_connect (overlay->op_cls,
429 &overlay_link_completed,
430 &overlay->link_array[p],
431 overlay->peers[overlay->link_array[p].A],
432 overlay->peers[overlay->link_array[p].B]);
433 }
434}
435
436
437/**
438 * Callback which will be called when overlay connect operation is released
439 *
440 * @param cls the Topology context
441 */
442static void
443oprelease_overlay_configure_topology (void *cls)
444{
445 struct TopologyContext *tc = cls;
446 struct TopologyContextOverlay *overlay;
447 struct RetryListEntry *retry_entry;
448 unsigned int p;
449
450 GNUNET_assert (TOPOLOGYCONTEXT_TYPE_OVERLAY == tc->type);
451 overlay = &tc->u.overlay;
452 while (NULL != (retry_entry = overlay->rl_head))
453 {
454 GNUNET_CONTAINER_DLL_remove (overlay->rl_head, overlay->rl_tail,
455 retry_entry);
456 GNUNET_free (retry_entry);
457 }
458 if (NULL != overlay->link_array)
459 {
460 for (p = 0; p < tc->link_array_size; p++)
461 if (NULL != overlay->link_array[p].op)
462 GNUNET_TESTBED_operation_done (overlay->link_array[p].op);
463 GNUNET_free (overlay->link_array);
464 }
465 GNUNET_free (tc);
466}
467
468
469/**
470 * Populates the OverlayLink structure.
471 *
472 * @param offset the offset of the link array to use
473 * @param A the peer A. Should be different from B
474 * @param B the peer B. Should be different from A
475 * @param tc the TopologyContext
476 * @return
477 */
478static void
479make_link (unsigned int offset,
480 uint32_t A,
481 uint32_t B,
482 struct TopologyContext *tc)
483{
484 GNUNET_assert (A != B);
485 switch (tc->type)
486 {
487 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
488 {
489 struct TopologyContextOverlay *overlay;
490 struct OverlayLink *olink;
491
492 overlay = &tc->u.overlay;
493 GNUNET_assert (offset < tc->link_array_size);
494 olink = &overlay->link_array[offset];
495 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %u to %u\n", B, A);
496 olink->A = A;
497 olink->B = B;
498 olink->op = NULL;
499 olink->tc = tc;
500 }
501 break;
502
503 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
504 {
505 struct TopologyContextUnderlay *underlay;
506 struct UnderlayLink *ulink;
507
508 underlay = &tc->u.underlay;
509 GNUNET_assert (offset < tc->link_array_size);
510 ulink = &underlay->link_array[offset];
511 ulink->A = A;
512 ulink->B = B;
513 }
514 break;
515 }
516}
517
518
519/**
520 * Generates line topology
521 *
522 * @param tc the topology context
523 */
524static void
525gen_topo_line (struct TopologyContext *tc)
526{
527 unsigned int cnt;
528
529 tc->link_array_size = tc->num_peers - 1;
530 switch (tc->type)
531 {
532 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
533 {
534 struct TopologyContextOverlay *overlay;
535
536 overlay = &tc->u.overlay;
537 overlay->link_array =
538 GNUNET_new_array (tc->link_array_size,
539 struct OverlayLink);
540 }
541 break;
542
543 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
544 {
545 struct TopologyContextUnderlay *underlay;
546
547 underlay = &tc->u.underlay;
548 underlay->link_array =
549 GNUNET_new_array (tc->link_array_size,
550 struct UnderlayLink);
551 }
552 break;
553 }
554 for (cnt = 0; cnt < (tc->link_array_size); cnt++)
555 make_link (cnt, cnt, cnt + 1, tc);
556}
557
558
559/**
560 * Generates star topology
561 *
562 * @param tc the topology context
563 */
564static void
565gen_topo_star (struct TopologyContext *tc)
566{
567 unsigned int cnt;
568
569 tc->link_array_size = tc->num_peers - 1;
570 switch (tc->type)
571 {
572 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
573 {
574 struct TopologyContextOverlay *overlay;
575
576 overlay = &tc->u.overlay;
577 overlay->link_array =
578 GNUNET_new_array (tc->link_array_size,
579 struct OverlayLink);
580 }
581 break;
582
583 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
584 {
585 struct TopologyContextUnderlay *underlay;
586
587 underlay = &tc->u.underlay;
588 underlay->link_array =
589 GNUNET_new_array (tc->link_array_size,
590 struct UnderlayLink);
591 }
592 break;
593 }
594 for (cnt = tc->link_array_size; cnt; cnt--)
595 make_link (cnt - 1,
596 0,
597 cnt,
598 tc);
599}
600
601
602/**
603 * Generates ring topology
604 *
605 * @param tc the topology context
606 */
607static void
608gen_topo_ring (struct TopologyContext *tc)
609{
610 gen_topo_line (tc);
611 tc->link_array_size++;
612 switch (tc->type)
613 {
614 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
615 {
616 struct TopologyContextOverlay *overlay;
617
618 overlay = &tc->u.overlay;
619 overlay->link_array =
620 GNUNET_realloc (overlay->link_array, sizeof(struct OverlayLink)
621 * tc->link_array_size);
622 }
623 break;
624
625 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
626 {
627 struct TopologyContextUnderlay *underlay;
628
629 underlay = &tc->u.underlay;
630 underlay->link_array =
631 GNUNET_realloc (underlay->link_array, sizeof(struct UnderlayLink)
632 * tc->link_array_size);
633 }
634 break;
635 }
636 make_link (tc->link_array_size - 1, tc->num_peers - 1, 0, tc);
637}
638
639
640unsigned int
641GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
642 unsigned int **rows_len)
643{
644 double sq;
645 unsigned int sq_floor;
646 unsigned int _rows;
647 unsigned int *_rows_len;
648 unsigned int x;
649 unsigned int y;
650 unsigned int _num_peers;
651 unsigned int cnt;
652
653 sq = sqrt (num_peers);
654 sq = floor (sq);
655 sq_floor = (unsigned int) sq;
656 _rows = (sq_floor + 1);
657 _rows_len = GNUNET_malloc (sizeof(unsigned int) * _rows);
658 for (y = 0; y < _rows - 1; y++)
659 _rows_len[y] = sq_floor;
660 _num_peers = sq_floor * sq_floor;
661 cnt = (_num_peers < 2) ? _num_peers : 2 * _num_peers;
662 x = 0;
663 y = 0;
664 while (_num_peers < num_peers)
665 {
666 if (x < y)
667 _rows_len[_rows - 1] = ++x;
668 else
669 _rows_len[y++]++;
670 _num_peers++;
671 }
672 cnt += (x < 2) ? x : 2 * x;
673 cnt += (y < 2) ? y : 2 * y;
674 if (0 == _rows_len[_rows - 1])
675 _rows--;
676 if (NULL != rows)
677 *rows = _rows;
678 if (NULL != rows_len)
679 *rows_len = _rows_len;
680 else
681 GNUNET_free (_rows_len);
682 return cnt;
683}
684
685
686/**
687 * Generates ring topology
688 *
689 * @param tc the topology context
690 */
691static void
692gen_topo_2dtorus (struct TopologyContext *tc)
693{
694 unsigned int rows;
695 unsigned int *rows_len;
696 unsigned int x;
697 unsigned int y;
698 unsigned int cnt;
699 unsigned int offset;
700
701 tc->link_array_size =
702 GNUNET_TESTBED_2dtorus_calc_links (tc->num_peers, &rows, &rows_len);
703 switch (tc->type)
704 {
705 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
706 {
707 struct TopologyContextOverlay *overlay;
708
709 overlay = &tc->u.overlay;
710 overlay->link_array =
711 GNUNET_malloc (sizeof(struct OverlayLink) * tc->link_array_size);
712 }
713 break;
714
715 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
716 {
717 struct TopologyContextUnderlay *underlay;
718
719 underlay = &tc->u.underlay;
720 underlay->link_array =
721 GNUNET_malloc (sizeof(struct UnderlayLink) * tc->link_array_size);
722 break;
723 }
724 }
725 cnt = 0;
726 offset = 0;
727 for (y = 0; y < rows; y++)
728 {
729 for (x = 0; x < rows_len[y] - 1; x++)
730 {
731 make_link (cnt, offset + x, offset + x + 1, tc);
732 cnt++;
733 }
734 if (0 == x)
735 break;
736 make_link (cnt, offset + x, offset, tc);
737 cnt++;
738 offset += rows_len[y];
739 }
740 for (x = 0; x < rows_len[0]; x++)
741 {
742 offset = 0;
743 for (y = 0; y < rows - 1; y++)
744 {
745 if (x >= rows_len[y + 1])
746 break;
747 GNUNET_assert (x < rows_len[y + 1]);
748 make_link (cnt, offset + x, offset + rows_len[y] + x, tc);
749 offset += rows_len[y];
750 cnt++;
751 }
752 if (0 == offset)
753 break;
754 make_link (cnt, offset + x, x, tc);
755 cnt++;
756 }
757 GNUNET_assert (cnt == tc->link_array_size);
758 GNUNET_free (rows_len);
759}
760
761
762/**
763 * Generates ring topology
764 *
765 * @param tc the topology context
766 * @param links the number of random links to establish
767 * @param append #GNUNET_YES to add links to existing link array; #GNUNET_NO to
768 * create a new link array
769 */
770static void
771gen_topo_random (struct TopologyContext *tc,
772 unsigned int links,
773 int append)
774{
775 unsigned int cnt;
776 unsigned int index;
777 uint32_t A_rand;
778 uint32_t B_rand;
779
780 if (1 == tc->num_peers)
781 return;
782 if (GNUNET_YES == append)
783 {
784 index = tc->link_array_size;
785 tc->link_array_size += links;
786 }
787 else
788 {
789 index = 0;
790 tc->link_array_size = links;
791 }
792 switch (tc->type)
793 {
794 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
795 {
796 struct TopologyContextOverlay *overlay;
797
798 overlay = &tc->u.overlay;
799 if (GNUNET_YES != append)
800 {
801 GNUNET_assert (NULL == overlay->link_array);
802 overlay->link_array =
803 GNUNET_malloc (sizeof(struct OverlayLink) * tc->link_array_size);
804 break;
805 }
806 GNUNET_assert ((0 < tc->link_array_size) && (NULL !=
807 overlay->link_array));
808 overlay->link_array =
809 GNUNET_realloc (overlay->link_array,
810 sizeof(struct OverlayLink) * tc->link_array_size);
811 break;
812 }
813
814 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
815 {
816 struct TopologyContextUnderlay *underlay;
817
818 underlay = &tc->u.underlay;
819 if (GNUNET_YES != append)
820 {
821 GNUNET_assert (NULL == underlay->link_array);
822 underlay->link_array =
823 GNUNET_malloc (sizeof(struct UnderlayLink) * tc->link_array_size);
824 break;
825 }
826 GNUNET_assert ((0 < tc->link_array_size) && (NULL !=
827 underlay->link_array));
828 underlay->link_array =
829 GNUNET_realloc (underlay->link_array,
830 sizeof(struct UnderlayLink) * tc->link_array_size);
831 break;
832 }
833 }
834 for (cnt = 0; cnt < links; cnt++)
835 {
836 do
837 {
838 A_rand =
839 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
840 B_rand =
841 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, tc->num_peers);
842 }
843 while (A_rand == B_rand);
844 make_link (index + cnt, A_rand, B_rand, tc);
845 }
846}
847
848
849/**
850 * Generates scale free network. Its construction is described in:
851 *
852 * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
853 *
854 * @param tc the topology context
855 * @param cap maximum allowed node degree
856 * @param m number of edges to establish for a new node when it is added to the
857 * network
858 */
859static void
860gen_topo_scale_free (struct TopologyContext *tc,
861 uint16_t cap,
862 uint8_t m)
863{
864 unsigned int *deg;
865 unsigned int *etab;
866 unsigned int *used;
867 unsigned int etaboff;
868 unsigned int cnt;
869 unsigned int cnt2;
870 unsigned int peer;
871 unsigned int random_peer;
872 unsigned int links;
873 unsigned int off;
874 unsigned int redo_threshold;
875
876 etaboff = 0;
877 tc->link_array_size = tc->num_peers * m;
878 switch (tc->type)
879 {
880 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
881 {
882 struct TopologyContextOverlay *overlay;
883
884 overlay = &tc->u.overlay;
885 overlay->link_array = GNUNET_malloc_large (sizeof(struct OverlayLink)
886 * tc->link_array_size);
887 }
888 break;
889
890 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
891 {
892 struct TopologyContextUnderlay *underlay;
893
894 underlay = &tc->u.underlay;
895 underlay->link_array = GNUNET_malloc_large (sizeof(struct UnderlayLink)
896 * tc->link_array_size);
897 }
898 break;
899 }
900 etab = GNUNET_malloc_large (sizeof(unsigned int) * 2 * tc->link_array_size);
901 deg = GNUNET_malloc (sizeof(unsigned int) * tc->num_peers);
902 used = GNUNET_malloc (sizeof(unsigned int) * m);
903 /* start by connecting peer 1 to peer 0 */
904 make_link (0, 0, 1, tc);
905 deg[0]++;
906 deg[1]++;
907 etab[etaboff++] = 0;
908 etab[etaboff++] = 1;
909 links = 1;
910 for (peer = 2; peer < tc->num_peers; peer++)
911 {
912 if (cap < deg[peer])
913 continue;
914 for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
915 {
916 redo_threshold = 0;
917redo:
918 off = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, etaboff);
919 random_peer = etab[off];
920 if (cap < deg[random_peer])
921 {
922 if (++redo_threshold > GNUNET_MAX (1, cap / 2))
923 {
924 redo_threshold = 0;
925 off = 0;
926 for (cnt2 = 0; cnt2 < etaboff; cnt2++)
927 {
928 if (random_peer == etab[cnt2])
929 {
930 off++;
931 continue;
932 }
933 etab[cnt2 - off] = etab[cnt2];
934 }
935 etaboff -= off;
936 }
937 goto redo;
938 }
939 for (cnt2 = 0; cnt2 < cnt; cnt2++)
940 if (random_peer == used[cnt2])
941 goto redo;
942 make_link (links + cnt, random_peer, peer, tc);
943 deg[random_peer]++;
944 deg[peer]++;
945 used[cnt] = random_peer;
946 }
947 for (cnt = 0; cnt < GNUNET_MIN (peer, m); cnt++)
948 {
949 etab[etaboff++] = used[cnt];
950 etab[etaboff++] = peer;
951 }
952 links += GNUNET_MIN (peer, m);
953 }
954 GNUNET_free (etab);
955 GNUNET_free (used);
956 GNUNET_free (deg);
957 GNUNET_assert (links <= tc->link_array_size);
958 tc->link_array_size = links;
959 switch (tc->type)
960 {
961 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
962 {
963 struct TopologyContextOverlay *overlay;
964
965 overlay = &tc->u.overlay;
966 overlay->link_array =
967 GNUNET_realloc (overlay->link_array, sizeof(struct OverlayLink)
968 * tc->link_array_size);
969 }
970 break;
971
972 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
973 {
974 struct TopologyContextUnderlay *underlay;
975
976 underlay = &tc->u.underlay;
977 underlay->link_array =
978 GNUNET_realloc (underlay->link_array, sizeof(struct UnderlayLink)
979 * tc->link_array_size);
980 }
981 break;
982 }
983}
984
985
986/**
987 * Generates topology from the given file
988 *
989 * @param tc the topology context
990 * @param filename the filename of the file containing topology data
991 */
992static void
993gen_topo_from_file (struct TopologyContext *tc,
994 const char *filename)
995{
996 char *data;
997 char *end;
998 char *buf;
999 uint64_t fs;
1000 uint64_t offset;
1001 unsigned long int peer_id;
1002 unsigned long int other_peer_id;
1003 enum ParseState
1004 {
1005 /**
1006 * We read the peer index
1007 */
1008 PEER_INDEX,
1009
1010 /**
1011 * We read the other peer indices
1012 */
1013 OTHER_PEER_INDEX,
1014 } state;
1015 int status;
1016
1017 status = GNUNET_SYSERR;
1018 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
1019 {
1020 LOG (GNUNET_ERROR_TYPE_ERROR,
1021 _ ("Topology file %s not found\n"),
1022 filename);
1023 return;
1024 }
1025 if (GNUNET_OK !=
1026 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
1027 {
1028 LOG (GNUNET_ERROR_TYPE_ERROR,
1029 _ ("Topology file %s has no data\n"),
1030 filename);
1031 return;
1032 }
1033 data = GNUNET_malloc (fs);
1034 if (fs != GNUNET_DISK_fn_read (filename, data, fs))
1035 {
1036 LOG (GNUNET_ERROR_TYPE_ERROR,
1037 _ ("Topology file %s cannot be read\n"),
1038 filename);
1039 goto _exit;
1040 }
1041
1042 offset = 0;
1043 peer_id = 0;
1044 state = PEER_INDEX;
1045 while (offset < fs)
1046 {
1047 if (0 != isspace ((unsigned char) data[offset]))
1048 {
1049 offset++;
1050 continue;
1051 }
1052 switch (state)
1053 {
1054 case PEER_INDEX:
1055 buf = strchr (&data[offset], ':');
1056 if (NULL == buf)
1057 {
1058 LOG (GNUNET_ERROR_TYPE_ERROR,
1059 _ ("Failed to read peer index from toology file: %s"), filename);
1060 goto _exit;
1061 }
1062 *buf = '\0';
1063 errno = 0;
1064 peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
1065 if (0 != errno)
1066 {
1067 LOG (GNUNET_ERROR_TYPE_ERROR,
1068 _ ("Value in given topology file: %s out of range\n"), filename);
1069 goto _exit;
1070 }
1071 if (&data[offset] == end)
1072 {
1073 LOG (GNUNET_ERROR_TYPE_ERROR,
1074 _ ("Failed to read peer index from topology file: %s"), filename);
1075 goto _exit;
1076 }
1077 if (tc->num_peers <= peer_id)
1078 {
1079 LOG (GNUNET_ERROR_TYPE_ERROR,
1080 _ ("Topology file needs more peers than given ones\n"));
1081 goto _exit;
1082 }
1083 state = OTHER_PEER_INDEX;
1084 offset += ((unsigned int) (buf - &data[offset])) + 1;
1085 break;
1086
1087 case OTHER_PEER_INDEX:
1088 errno = 0;
1089 other_peer_id = (unsigned int) strtoul (&data[offset], &end, 10);
1090 if (0 != errno)
1091 {
1092 LOG (GNUNET_ERROR_TYPE_ERROR,
1093 _ ("Value in given topology file: %s out of range\n"), filename);
1094 goto _exit;
1095 }
1096 if (&data[offset] == end)
1097 {
1098 LOG (GNUNET_ERROR_TYPE_ERROR,
1099 _ ("Failed to read peer index from topology file: %s"), filename);
1100 goto _exit;
1101 }
1102 if (tc->num_peers <= other_peer_id)
1103 {
1104 LOG (GNUNET_ERROR_TYPE_ERROR,
1105 _ ("Topology file needs more peers than given ones\n"));
1106 goto _exit;
1107 }
1108 if (peer_id != other_peer_id)
1109 {
1110 tc->link_array_size++;
1111 switch (tc->type)
1112 {
1113 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1114 {
1115 struct TopologyContextOverlay *overlay;
1116
1117 overlay = &tc->u.overlay;
1118 overlay->link_array =
1119 GNUNET_realloc (overlay->link_array,
1120 sizeof(struct OverlayLink) * tc->link_array_size);
1121 }
1122 break;
1123
1124 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1125 {
1126 struct TopologyContextUnderlay *underlay;
1127
1128 underlay = &tc->u.underlay;
1129 underlay->link_array =
1130 GNUNET_realloc (underlay->link_array,
1131 sizeof(struct UnderlayLink)
1132 * tc->link_array_size);
1133 }
1134 break;
1135 }
1136 offset += end - &data[offset];
1137 make_link (tc->link_array_size - 1, peer_id, other_peer_id, tc);
1138 }
1139 else
1140 LOG (GNUNET_ERROR_TYPE_WARNING,
1141 _ ("Ignoring to connect peer %lu to peer %lu\n"),
1142 peer_id,
1143 other_peer_id);
1144 while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
1145 offset++;
1146 if ((offset < fs) &&
1147 ('\n' == data[offset]))
1148 state = PEER_INDEX;
1149 else if ((offset < fs) &&
1150 ('|' == data[offset]))
1151 {
1152 state = OTHER_PEER_INDEX;
1153 offset++;
1154 }
1155 break;
1156 }
1157 }
1158 status = GNUNET_OK;
1159
1160_exit:
1161 GNUNET_free (data);
1162 if (GNUNET_OK != status)
1163 {
1164 LOG (GNUNET_ERROR_TYPE_WARNING,
1165 "Removing link data read from the file\n");
1166 tc->link_array_size = 0;
1167 switch (tc->type)
1168 {
1169 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1170 {
1171 struct TopologyContextOverlay *overlay;
1172
1173 overlay = &tc->u.overlay;
1174 GNUNET_free (overlay->link_array);
1175 overlay->link_array = NULL;
1176 }
1177 break;
1178
1179 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1180 {
1181 struct TopologyContextUnderlay *underlay;
1182
1183 underlay = &tc->u.underlay;
1184 GNUNET_free (underlay->link_array);
1185 underlay->link_array = NULL;
1186 }
1187 break;
1188 }
1189 }
1190}
1191
1192
1193/**
1194 * Generates clique topology
1195 *
1196 * @param tc the topology context
1197 */
1198static void
1199gen_topo_clique (struct TopologyContext *tc)
1200{
1201 unsigned int cnt;
1202 unsigned int offset;
1203 unsigned int neighbour;
1204
1205 tc->link_array_size = tc->num_peers * (tc->num_peers - 1);
1206 switch (tc->type)
1207 {
1208 case TOPOLOGYCONTEXT_TYPE_OVERLAY:
1209 {
1210 struct TopologyContextOverlay *overlay;
1211
1212 overlay = &tc->u.overlay;
1213 overlay->link_array = GNUNET_new_array (tc->link_array_size,
1214 struct OverlayLink);
1215 }
1216 break;
1217
1218 case TOPOLOGYCONTEXT_TYPE_UNDERLAY:
1219 {
1220 struct TopologyContextUnderlay *underlay;
1221
1222 underlay = &tc->u.underlay;
1223 underlay->link_array = GNUNET_new_array (tc->link_array_size,
1224 struct UnderlayLink);
1225 }
1226 }
1227 offset = 0;
1228 for (cnt = 0; cnt < tc->num_peers; cnt++)
1229 {
1230 for (neighbour = 0; neighbour < tc->num_peers; neighbour++)
1231 {
1232 if (neighbour == cnt)
1233 continue;
1234 make_link (offset, cnt, neighbour, tc);
1235 offset++;
1236 }
1237 }
1238}
1239
1240
1241struct GNUNET_TESTBED_Operation *
1242GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
1243 unsigned int num_peers,
1244 struct GNUNET_TESTBED_Peer
1245 **peers,
1246 enum
1247 GNUNET_TESTBED_TopologyOption
1248 topo, va_list ap)
1249{
1250 GNUNET_break (0);
1251 return NULL;
1252}
1253
1254
1255struct GNUNET_TESTBED_Operation *
1256GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
1257 unsigned int num_peers,
1258 struct GNUNET_TESTBED_Peer **peers,
1259 enum GNUNET_TESTBED_TopologyOption
1260 topo, ...)
1261{
1262 GNUNET_break (0);
1263 return NULL;
1264}
1265
1266
1267struct GNUNET_TESTBED_Operation *
1268GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
1269 unsigned int num_peers,
1270 struct GNUNET_TESTBED_Peer **peers,
1271 unsigned int *max_connections,
1272 GNUNET_TESTBED_TopologyCompletionCallback
1273 comp_cb,
1274 void *comp_cb_cls,
1275 enum GNUNET_TESTBED_TopologyOption
1276 topo,
1277 va_list va)
1278{
1279 struct TopologyContext *tc;
1280 struct TopologyContextOverlay *overlay;
1281 struct GNUNET_TESTBED_Operation *op;
1282 struct GNUNET_TESTBED_Controller *c;
1283 enum GNUNET_TESTBED_TopologyOption secondary_option;
1284
1285 if (num_peers < 2)
1286 return NULL;
1287 c = peers[0]->controller;
1288 tc = GNUNET_new (struct TopologyContext);
1289 tc->type = TOPOLOGYCONTEXT_TYPE_OVERLAY;
1290 overlay = &tc->u.overlay;
1291 overlay->peers = peers;
1292 tc->num_peers = num_peers;
1293 overlay->op_cls = op_cls;
1294 overlay->retry_cnt = DEFAULT_RETRY_CNT;
1295 overlay->comp_cb = comp_cb;
1296 overlay->comp_cb_cls = comp_cb_cls;
1297 switch (topo)
1298 {
1299 case GNUNET_TESTBED_TOPOLOGY_LINE:
1300 gen_topo_line (tc);
1301 break;
1302
1303 case GNUNET_TESTBED_TOPOLOGY_STAR:
1304 gen_topo_star (tc);
1305 break;
1306
1307 case GNUNET_TESTBED_TOPOLOGY_RING:
1308 gen_topo_ring (tc);
1309 break;
1310
1311 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1312 gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_NO);
1313 break;
1314
1315 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1316 gen_topo_ring (tc);
1317 gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
1318 break;
1319
1320 case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
1321 gen_topo_clique (tc);
1322 break;
1323
1324 case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
1325 gen_topo_2dtorus (tc);
1326 break;
1327
1328 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1329 gen_topo_2dtorus (tc);
1330 gen_topo_random (tc, va_arg (va, unsigned int), GNUNET_YES);
1331
1332 break;
1333
1334 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
1335 {
1336 uint16_t cap;
1337 uint8_t m;
1338
1339 cap = (uint16_t) va_arg (va, unsigned int);
1340 m = (uint8_t) va_arg (va, unsigned int);
1341 gen_topo_scale_free (tc, cap, m);
1342 }
1343 break;
1344
1345 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1346 {
1347 const char *filename;
1348
1349 filename = va_arg (va, const char *);
1350
1351 GNUNET_assert (NULL != filename);
1352 gen_topo_from_file (tc, filename);
1353 }
1354 break;
1355
1356 default:
1357 GNUNET_break (0);
1358 GNUNET_free (tc);
1359 return NULL;
1360 }
1361 do
1362 {
1363 secondary_option = GNUNET_VA_ARG_ENUM (va, GNUNET_TESTBED_TopologyOption);
1364
1365 switch (secondary_option)
1366 {
1367 case GNUNET_TESTBED_TOPOLOGY_RETRY_CNT:
1368 overlay->retry_cnt = va_arg (va, unsigned int);
1369 break;
1370
1371 case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
1372 break;
1373
1374 default:
1375 GNUNET_break (0); /* Should not use any other option apart from
1376 * the ones handled here */
1377 GNUNET_free (overlay->link_array);
1378 GNUNET_free (tc);
1379 return NULL;
1380 }
1381 }
1382 while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
1383 op = GNUNET_TESTBED_operation_create_ (tc,
1384 &opstart_overlay_configure_topology,
1385 &oprelease_overlay_configure_topology);
1386 GNUNET_TESTBED_operation_queue_insert_
1387 (c->opq_parallel_topology_config_operations, op);
1388 GNUNET_TESTBED_operation_begin_wait_ (op);
1389 LOG (GNUNET_ERROR_TYPE_DEBUG,
1390 "Generated topology with %u connections\n",
1391 tc->link_array_size);
1392 if (NULL != max_connections)
1393 *max_connections = tc->link_array_size;
1394 return op;
1395}
1396
1397
1398/**
1399 * All peers must have been started before calling this function.
1400 * This function then connects the given peers in the P2P overlay
1401 * using the given topology.
1402 *
1403 * @param op_cls closure argument to give with the peer connect operation events
1404 * generated through this function
1405 * @param num_peers number of peers in 'peers'
1406 * @param peers array of 'num_peers' with the peers to configure
1407 * @param max_connections the maximums number of overlay connections that will
1408 * be made to achieve the given topology
1409 * @param comp_cb the completion callback to call when the topology generation
1410 * is completed
1411 * @param comp_cb_cls closure for the above completion callback
1412 * @param topo desired underlay topology to use
1413 * @param ... topology-specific options
1414 * @return handle to the operation, NULL if connecting these
1415 * peers is fundamentally not possible at this time (peers
1416 * not running or underlay disallows) or if num_peers is less than 2
1417 */
1418struct GNUNET_TESTBED_Operation *
1419GNUNET_TESTBED_overlay_configure_topology (void *op_cls,
1420 unsigned int num_peers,
1421 struct GNUNET_TESTBED_Peer **peers,
1422 unsigned int *max_connections,
1423 GNUNET_TESTBED_TopologyCompletionCallback
1424 comp_cb,
1425 void *comp_cb_cls,
1426 enum GNUNET_TESTBED_TopologyOption
1427 topo,
1428 ...)
1429{
1430 struct GNUNET_TESTBED_Operation *op;
1431 va_list vargs;
1432
1433 GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
1434 va_start (vargs, topo);
1435 op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
1436 max_connections,
1437 comp_cb, comp_cb_cls,
1438 topo,
1439 vargs);
1440 va_end (vargs);
1441 return op;
1442}
1443
1444
1445int
1446GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
1447 const char *topology_string)
1448{
1449 unsigned int cnt;
1450
1451 for (cnt = 0; NULL != topology_strings[cnt]; cnt++)
1452 {
1453 if (0 == strcasecmp (topology_string, topology_strings[cnt]))
1454 {
1455 if (NULL != topology)
1456 *topology = (enum GNUNET_TESTBED_TopologyOption) cnt;
1457 GNUNET_assert (GNUNET_TESTBED_TOPOLOGY_OPTION_END !=
1458 (enum GNUNET_TESTBED_TopologyOption) cnt);
1459 return GNUNET_YES;
1460 }
1461 }
1462 return GNUNET_NO;
1463}
1464
1465
1466/**
1467 * Returns the string corresponding to the given topology
1468 *
1469 * @param topology the topology
1470 * @return the string (freshly allocated) of given topology; NULL if topology cannot be
1471 * expressed as a string
1472 */
1473char *
1474GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology)
1475{
1476 if (GNUNET_TESTBED_TOPOLOGY_OPTION_END <= topology)
1477 return NULL;
1478 return GNUNET_strdup (topology_strings[topology]);
1479}
1480
1481
1482/**
1483 * Function to construct an underlay topology
1484 *
1485 * @param num_peers the number of peers for which the topology should be
1486 * generated
1487 * @param proc the underlay link processor callback. Will be called for each
1488 * underlay link generated unless a previous call to this callback
1489 * returned #GNUNET_SYSERR. Cannot be NULL.
1490 * @param cls closure for @a proc
1491 * @param ... variable arguments denoting the topology and its parameters. They
1492 * should start with the type of topology to generate followed by their
1493 * options.
1494 * @return #GNUNET_OK if underlay link generation is successful; #GNUNET_SYSERR
1495 * upon error in generating the underlay or if any calls to the
1496 * underlay link processor returned #GNUNET_SYSERR
1497 */
1498int
1499GNUNET_TESTBED_underlay_construct_ (int num_peers,
1500 underlay_link_processor proc,
1501 void *cls,
1502 ...)
1503{
1504 struct TopologyContext tc;
1505 struct TopologyContextUnderlay *underlay;
1506 struct UnderlayLink *ulink;
1507 va_list vargs;
1508 enum GNUNET_TESTBED_TopologyOption topology;
1509 unsigned int cnt;
1510 int ret;
1511
1512 GNUNET_assert (NULL != proc);
1513 ret = GNUNET_OK;
1514 memset (&tc, 0, sizeof(tc));
1515 tc.num_peers = num_peers;
1516 tc.type = TOPOLOGYCONTEXT_TYPE_UNDERLAY;
1517 underlay = &tc.u.underlay;
1518 va_start (vargs, cls);
1519 topology = GNUNET_VA_ARG_ENUM (vargs, GNUNET_TESTBED_TopologyOption);
1520 switch (topology)
1521 {
1522 case GNUNET_TESTBED_TOPOLOGY_LINE:
1523 gen_topo_line (&tc);
1524 break;
1525
1526 case GNUNET_TESTBED_TOPOLOGY_STAR:
1527 gen_topo_star (&tc);
1528 break;
1529
1530 case GNUNET_TESTBED_TOPOLOGY_RING:
1531 gen_topo_ring (&tc);
1532 break;
1533
1534 case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
1535 gen_topo_clique (&tc);
1536 break;
1537
1538 case GNUNET_TESTBED_TOPOLOGY_2D_TORUS:
1539 gen_topo_2dtorus (&tc);
1540 break;
1541
1542 case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
1543 gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_NO);
1544 break;
1545
1546 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD_RING:
1547 gen_topo_ring (&tc);
1548 gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
1549 break;
1550
1551 case GNUNET_TESTBED_TOPOLOGY_SMALL_WORLD:
1552 gen_topo_2dtorus (&tc);
1553 gen_topo_random (&tc, va_arg (vargs, unsigned int), GNUNET_YES);
1554 break;
1555
1556 case GNUNET_TESTBED_TOPOLOGY_FROM_FILE:
1557 {
1558 const char *filename;
1559 filename = va_arg (vargs, char *);
1560 GNUNET_assert (NULL != filename);
1561 gen_topo_from_file (&tc, filename);
1562 }
1563 break;
1564
1565 case GNUNET_TESTBED_TOPOLOGY_SCALE_FREE:
1566 {
1567 uint16_t cap;
1568 uint8_t m;
1569 cap = (uint16_t) va_arg (vargs, unsigned int);
1570 m = (uint8_t) va_arg (vargs, unsigned int);
1571 gen_topo_scale_free (&tc, cap, m);
1572 }
1573 break;
1574
1575 default:
1576 GNUNET_assert (0);
1577 }
1578 va_end (vargs);
1579 for (cnt = 0; cnt < tc.link_array_size; cnt++)
1580 {
1581 ulink = &underlay->link_array[cnt];
1582 if (GNUNET_SYSERR == proc (cls,
1583 ulink->A,
1584 ulink->B,
1585 ulink->bandwidth,
1586 ulink->latency,
1587 ulink->loss))
1588 {
1589 ret = GNUNET_SYSERR;
1590 break;
1591 }
1592 }
1593 GNUNET_free (underlay->link_array);
1594 return ret;
1595}
1596
1597
1598/* end of testbed_api_topology.c */
diff --git a/src/testbed/testbed_api_topology.h b/src/testbed/testbed_api_topology.h
deleted file mode 100644
index ffa32dfa5..000000000
--- a/src/testbed/testbed_api_topology.h
+++ /dev/null
@@ -1,115 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_topology.h
23 * @brief header for intra library exported functions
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#ifndef TESTBED_API_TOPOLOGY_H
28#define TESTBED_API_TOPOLOGY_H
29
30/**
31 * Returns the number of links that are required to generate a 2d torus for the
32 * given number of peers. Also returns the arrangement (number of rows and the
33 * length of each row)
34 *
35 * @param num_peers number of peers
36 * @param rows number of rows in the 2d torus. Can be NULL.
37 * @param rows_len the length of each row. This array will be allocated
38 * fresh. The caller should free it. Can be NULL.
39 * @return the number of links that are required to generate a 2d torus for the
40 * given number of peers
41 */
42unsigned int
43GNUNET_TESTBED_2dtorus_calc_links (unsigned int num_peers, unsigned int *rows,
44 unsigned int **rows_len);
45
46
47/**
48 * Get a topology from a string input.
49 *
50 * @param topology where to write the retrieved topology
51 * @param topology_string The string to attempt to
52 * get a configuration value from
53 * @return #GNUNET_YES if topology string matched a
54 * known topology, #GNUNET_NO if not
55 */
56int
57GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
58 const char *topology_string);
59
60
61/**
62 * Returns the string corresponding to the given topology
63 *
64 * @param topology the topology
65 * @return the string (freshly allocated) of given topology; NULL if topology cannot be
66 * expressed as a string
67 */
68char *
69GNUNET_TESTBED_topology_to_str_ (enum GNUNET_TESTBED_TopologyOption topology);
70
71
72/**
73 * Functions of this type are called to process underlay link
74 *
75 * @param cls closure
76 * @param A offset of first peer
77 * @param B offset of second peer
78 * @param bandwidth the bandwidth of the link in bytes per second
79 * @param latency the latency of link in milliseconds
80 * @param loss the percentage of messages dropped on the link
81 * @return GNUNET_OK to continue processing; GNUNET_SYSERR to abort
82 */
83typedef int (*underlay_link_processor) (void *cls,
84 unsigned int A,
85 unsigned int B,
86 unsigned int bandwidth,
87 unsigned int latency,
88 unsigned int loss);
89
90
91/**
92 * Function to construct an underlay topology
93 *
94 * @param num_peers the number of peers for which the topology should be
95 * generated
96 * @param proc the underlay link processor callback. Will be called for each
97 * underlay link generated unless a previous call to this callback
98 * returned GNUNET_SYSERR. Cannot be NULL.
99 * @param cls closure for proc
100 * @param ... variable arguments denoting the topology and its parameters. They
101 * should start with the type of topology to generate followed by their
102 * options. These arguments should *always* end with
103 * GNUNET_TESTBED_TOPOLOGY_OPTION_END option
104 * @return GNUNET_OK if underlay link generation is successful; GNUNET_SYSERR
105 * upon error in generating the underlay or if any calls to the
106 * underlay link processor returned GNUNET_SYSERR
107 */
108int
109GNUNET_TESTBED_underlay_construct_ (int num_peers,
110 underlay_link_processor proc,
111 void *cls,
112 ...);
113
114#endif
115/* end of testbed_api_topology.h */
diff --git a/src/testbed/testbed_api_underlay.c b/src/testbed/testbed_api_underlay.c
deleted file mode 100644
index 8c01e4503..000000000
--- a/src/testbed/testbed_api_underlay.c
+++ /dev/null
@@ -1,260 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_api_underlay.c
23 * @brief testbed underlay API implementation
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "testbed_api_peers.h"
29
30
31/**
32 * An underlay link
33 */
34struct LinkProperty
35{
36 /**
37 * next pointer for list
38 */
39 struct LinkProperty *next;
40
41 /**
42 * the peer whose link is defined by these properties
43 */
44 struct GNUNET_TESTBED_Peer *peer;
45
46 /**
47 * latency of the link in microseconds
48 */
49 uint32_t latency;
50
51 /**
52 * data loss on the link expressed as percentage
53 */
54 uint32_t loss;
55
56 /**
57 * bandwidth of the link in kilobytes per second
58 */
59 uint32_t bandwidth;
60};
61
62
63/**
64 * Container for holding a peer in whitelist/blacklist
65 */
66struct ListEntry
67{
68 /**
69 * the next pointer
70 */
71 struct ListEntry *next;
72
73 /**
74 * the peer
75 */
76 struct GNUNET_TESTBED_Peer *peer;
77};
78
79
80/**
81 * Model for configuring underlay links of a peer
82 * @ingroup underlay
83 */
84struct GNUNET_TESTBED_UnderlayLinkModel
85{
86 /**
87 * The peer associated with this model
88 */
89 struct GNUNET_TESTBED_Peer *peer;
90
91 /**
92 * List of peers in the list
93 */
94 struct ListEntry *entries;
95
96 /**
97 * list of link properties
98 */
99 struct LinkProperty *props;
100
101 /**
102 * the type of this model
103 */
104 enum GNUNET_TESTBED_UnderlayLinkModelType type;
105}
106
107
108/**
109 * Function to free resources of list entries
110 *
111 * @param model the model
112 */
113static void
114free_entries (struct GNUNET_TESTBED_UnderlayLinkModel *model)
115{
116 struct ListEntry *e;
117
118 while (NULL != (e = model->entries))
119 {
120 model->entries = e->next;
121 GNUNET_free (e);
122 }
123}
124
125
126/**
127 * Function to free resources of link properties added to the given model
128 *
129 * @param model the model
130 */
131static void
132free_link_properties (struct GNUNET_TESTBED_UnderlayLinkModel *model)
133{
134 struct LinkProperty *p;
135
136 while (NULL != (p = model->props))
137 {
138 model->props = p->next;
139 GNUNET_free (p);
140 }
141}
142
143
144/**
145 * Create a GNUNET_TESTBED_UnderlayLinkModel for the given peer. A peer can
146 * have ONLY ONE model and it can be either a blacklist or whitelist based one.
147 *
148 * @ingroup underlay
149 * @param peer the peer for which the model has to be created
150 * @param type the type of the model
151 * @return the model
152 */
153struct GNUNET_TESTBED_UnderlayLinkModel *
154GNUNET_TESTBED_underlaylinkmodel_create (struct GNUNET_TESTBED_Peer *peer,
155 enum
156 GNUNET_TESTBED_UnderlayLinkModelType
157 type)
158{
159 struct GNUNET_TESTBED_UnderlayLinkModel *m;
160
161 GNUNET_assert (0 == peer->underlay_model_exists);
162 m = GNUNET_new (struct GNUNET_TESTBED_UnderlayLinkModel);
163 peer->underlay_model_exists = 1;
164 m->type = type;
165 return m;
166}
167
168
169/**
170 * Add a peer to the given model. Underlay connections to the given peer will
171 * be permitted if the model is whitelist based; otherwise they will not be
172 * permitted.
173 *
174 * @ingroup underlay
175 * @param model the model
176 * @param peer the peer to add
177 */
178void
179GNUNET_TESTBED_underlaylinkmodel_add_peer (struct
180 GNUNET_TESTBED_UnderlayLinkModel *
181 model,
182 struct GNUNET_TESTBED_Peer *peer)
183{
184 struct ListEntry *entry;
185
186 entry = GNUNET_new (struct ListEntry);
187 entry->peer = peer;
188 entry->next = model->entries;
189 model->entries = entry;
190}
191
192
193/**
194 * Set the metrics for a link to the given peer in the underlay model. The link
195 * SHOULD be permittable according to the given model.
196 *
197 * @ingroup underlay
198 * @param model the model
199 * @param peer the other end peer of the link
200 * @param latency latency of the link in microseconds
201 * @param loss data loss of the link expressed as a percentage
202 * @param bandwidth bandwidth of the link in kilobytes per second [kB/s]
203 */
204void
205GNUNET_TESTBED_underlaylinkmodel_set_link (struct
206 GNUNET_TESTBED_UnderlayLinkModel *
207 model,
208 struct GNUNET_TESTBED_Peer *peer,
209 uint32_t latency,
210 uint32_t loss,
211 uint32_t bandwidth)
212{
213 struct LinkProperty *prop;
214
215 prop = GNUNET_new (struct LinkProperty);
216 prop->peer = peer;
217 prop->latency = latency;
218 prop->loss = loss;
219 prop->bandwidth = bandwidth;
220 prop->next = model->props;
221 model->props = prop;
222}
223
224
225/**
226 * Free the resources of the model. Use this function only if the model has not
227 * be committed and has to be unallocated. The peer can then have another model
228 * created.
229 *
230 * @ingroup underlay
231 * @param model the model to unallocate
232 */
233void
234GNUNET_TESTBED_underlaylinkmodel_free (struct
235 GNUNET_TESTBED_UnderlayLinkModel *model)
236{
237 model->peer->underlay_model_exists = 0;
238 free_entries (model);
239 free_link_properties (model);
240 gnunet_free (model);
241}
242
243
244/**
245 * Commit the model. The model is freed in this function(!).
246 *
247 * @ingroup underlay
248 * @param model the model to commit
249 */
250void
251GNUNET_TESTBED_underlaylinkmodel_commit (struct
252 GNUNET_TESTBED_UnderlayLinkModel *model)
253{
254 /* FIXME: Marshal the model into a message */
255 GNUNET_break (0);
256 /* do not reset the value of model->peer->underlay_model_exists */
257 free_entries (model);
258 free_link_properties (model);
259 GNUNET_free (model);
260}
diff --git a/src/testbed/testbed_helper.h b/src/testbed/testbed_helper.h
deleted file mode 100644
index 817ad559d..000000000
--- a/src/testbed/testbed_helper.h
+++ /dev/null
@@ -1,89 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2008--2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/testbed_helper.h
23 * @brief Message formats for communication between testbed api and
24 * gnunet-helper-testbed process
25 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
26 */
27
28#ifndef TESTBED_HELPER_H
29#define TESTBED_HELPER_H
30
31GNUNET_NETWORK_STRUCT_BEGIN
32/**
33 * Initialization message for gnunet-helper-testbed to start testbed service
34 */
35struct GNUNET_TESTBED_HelperInit
36{
37 /**
38 * Type is GNUNET_MESSAGE_TYPE_TESTBED_HELPER_INIT
39 */
40 struct GNUNET_MessageHeader header;
41
42 /**
43 * The controller hostname size excluding the NULL termination character -
44 * strlen (hostname); cannot be zero
45 */
46 uint16_t trusted_ip_size GNUNET_PACKED;
47
48 /**
49 * The hostname size excluding the NULL termination character - strlen
50 * (hostname); cannot be zero
51 */
52 uint16_t hostname_size GNUNET_PACKED;
53
54 /**
55 * The size of the uncompressed configuration
56 */
57 uint16_t config_size GNUNET_PACKED;
58
59 /* Followed by NULL terminated trusted ip */
60
61 /* Followed by hostname of the machine on which helper runs. This is not NULL
62 * terminated */
63
64 /* Followed by serialized and compressed configuration which should be
65 * config_size long when un-compressed */
66};
67
68/**
69 * Reply message from helper process
70 */
71struct GNUNET_TESTBED_HelperReply
72{
73 /**
74 * Type is GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY
75 */
76 struct GNUNET_MessageHeader header;
77
78 /**
79 * Size of the uncompressed configuration
80 */
81 uint16_t config_size GNUNET_PACKED;
82
83 /* Followed by compressed configuration which should be config_size long when
84 * un-compressed */
85};
86
87GNUNET_NETWORK_STRUCT_END
88#endif
89/* end of testbed_helper.h */
diff --git a/src/testbed/valgrind-zlib.supp b/src/testbed/valgrind-zlib.supp
deleted file mode 100644
index ca6ce115f..000000000
--- a/src/testbed/valgrind-zlib.supp
+++ /dev/null
@@ -1,6 +0,0 @@
1{
2 <ZlibInflateReset2UninitJump>
3 Memcheck:Cond
4 fun:inflateReset2
5 ...
6}
diff --git a/src/testbed/x64_misc.supp b/src/testbed/x64_misc.supp
deleted file mode 100644
index e6a19c33e..000000000
--- a/src/testbed/x64_misc.supp
+++ /dev/null
@@ -1,34 +0,0 @@
1{
2 <unknown invalid free>
3 Memcheck:Free
4 fun:free
5 fun:free_mem
6 fun:__libc_freeres
7 fun:_vgnU_freeres
8 fun:__run_exit_handlers
9 fun:exit
10 fun:(below main)
11}
12{
13 <gnunet_crypto_init>
14 Memcheck:Leak
15 fun:malloc
16 obj:/usr/lib/libgcrypt.so.11.5.3
17 ...
18 obj:/usr/lib/libgcrypt.so.11.5.3
19 fun:gcry_control
20 fun:GNUNET_CRYPTO_random_init
21 obj:/home/harsha/repos/gnunet/src/util/.libs/libgnunetutil.so.8.0.0
22 obj:/home/harsha/repos/gnunet/src/util/.libs/libgnunetutil.so.8.0.0
23}
24
25{
26 <insert_a_suppression_name_here>
27 Memcheck:Leak
28 fun:malloc
29 ...
30 fun:gcry_control
31 fun:GNUNET_CRYPTO_random_init
32 obj:/home/totakura/gnunet/src/util/.libs/libgnunetutil.so.8.0.0
33 obj:/home/totakura/gnunet/src/util/.libs/libgnunetutil.so.8.0.0
34}