diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-06-09 15:35:06 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-06-09 15:35:06 +0000 |
commit | e0033c1da56e1889775d7dccf92ea78ee52e4d5c (patch) | |
tree | 82a835de1f924de68dff5702d9e2b46b2f64ffdd /src/testing | |
parent | 5e29c9683d2c0dfff71d2ead9ebb98d74a844bd5 (diff) | |
download | gnunet-e0033c1da56e1889775d7dccf92ea78ee52e4d5c.tar.gz gnunet-e0033c1da56e1889775d7dccf92ea78ee52e4d5c.zip |
-moving old testing code to legacy location
Diffstat (limited to 'src/testing')
40 files changed, 6 insertions, 16288 deletions
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index 455df6989..dcefc34d1 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am | |||
@@ -14,301 +14,46 @@ pkgcfgdir= $(pkgdatadir)/config.d/ | |||
14 | dist_pkgcfg_DATA = \ | 14 | dist_pkgcfg_DATA = \ |
15 | testing.conf | 15 | testing.conf |
16 | 16 | ||
17 | if HAVE_EXPENSIVE_TESTS | ||
18 | EXPENSIVE_TESTS = \ | ||
19 | test_testing_topology_stability \ | ||
20 | test_testing_topology_clique_random \ | ||
21 | test_testing_topology_clique_minimum \ | ||
22 | test_testing_topology_clique_dfs \ | ||
23 | test_testing_topology_churn \ | ||
24 | test_testing_topology_line \ | ||
25 | test_testing_topology_blacklist \ | ||
26 | test_testing_group_remote \ | ||
27 | test_testing_topology_ring \ | ||
28 | test_testing_topology_2d_torus \ | ||
29 | test_testing_topology_small_world_ring \ | ||
30 | test_testing_topology_small_world_torus \ | ||
31 | test_testing_topology_erdos_renyi \ | ||
32 | test_testing_topology_internat \ | ||
33 | test_testing_topology_scale_free | ||
34 | endif | ||
35 | |||
36 | lib_LTLIBRARIES = \ | 17 | lib_LTLIBRARIES = \ |
37 | libgnunettesting.la \ | 18 | libgnunettesting.la |
38 | libgnunettesting_new.la | ||
39 | 19 | ||
40 | libgnunettesting_la_SOURCES = \ | 20 | libgnunettesting_la_SOURCES = \ |
41 | helper.c \ | ||
42 | testing.c \ | ||
43 | testing_group.c \ | ||
44 | testing_peergroup.c | ||
45 | libgnunettesting_la_LIBADD = $(XLIB) \ | ||
46 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
47 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
48 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
49 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
50 | -lm \ | ||
51 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
52 | $(LTLIBINTL) | ||
53 | libgnunettesting_la_LDFLAGS = \ | ||
54 | $(GN_LIB_LDFLAGS) \ | ||
55 | -version-info 0:1:0 | ||
56 | |||
57 | |||
58 | libgnunettesting_new_la_SOURCES = \ | ||
59 | testing_new.c | 21 | testing_new.c |
60 | libgnunettesting_new_la_LIBADD = \ | 22 | libgnunettesting_la_LIBADD = \ |
61 | $(top_builddir)/src/util/libgnunetutil.la \ | 23 | $(top_builddir)/src/util/libgnunetutil.la \ |
62 | $(LTLIBINTL) | 24 | $(LTLIBINTL) |
63 | libgnunettesting_new_la_LDFLAGS = \ | 25 | libgnunettesting_la_LDFLAGS = \ |
64 | $(GN_LIB_LDFLAGS) \ | 26 | $(GN_LIB_LDFLAGS) \ |
65 | -version-info 0:1:0 | 27 | -version-info 0:1:0 |
66 | 28 | ||
67 | 29 | ||
68 | bin_PROGRAMS = \ | ||
69 | gnunet-testing | ||
70 | |||
71 | check_PROGRAMS = \ | 30 | check_PROGRAMS = \ |
72 | test_testing \ | ||
73 | test_testing_connect \ | ||
74 | test_testing_reconnect \ | ||
75 | test_testing_group \ | ||
76 | test_testing_peergroup \ | ||
77 | test_testing_topology_stability \ | ||
78 | test_testing_topology_clique \ | ||
79 | test_testing_topology_clique_random \ | ||
80 | test_testing_topology_clique_minimum \ | ||
81 | test_testing_topology_clique_dfs \ | ||
82 | test_testing_topology_churn \ | ||
83 | test_testing_topology_line \ | ||
84 | test_testing_topology_blacklist \ | ||
85 | test_testing_group_remote \ | ||
86 | test_testing_2dtorus \ | ||
87 | test_testing_topology_ring \ | ||
88 | test_testing_topology_2d_torus \ | ||
89 | test_testing_topology_small_world_ring \ | ||
90 | test_testing_topology_small_world_torus \ | ||
91 | test_testing_topology_erdos_renyi \ | ||
92 | test_testing_topology_internat \ | ||
93 | test_testing_topology_none \ | ||
94 | test_testing_topology_scale_free \ | ||
95 | test_testing_new_portreservation \ | 31 | test_testing_new_portreservation \ |
96 | test_testing_new_peerstartup \ | 32 | test_testing_new_peerstartup \ |
97 | test_testing_new_servicestartup | 33 | test_testing_new_servicestartup |
98 | 34 | ||
99 | if ENABLE_TEST_RUN | 35 | if ENABLE_TEST_RUN |
100 | TESTS = \ | 36 | TESTS = \ |
101 | test_testing \ | ||
102 | test_testing_connect \ | ||
103 | test_testing_reconnect \ | ||
104 | test_testing_group \ | ||
105 | test_testing_peergroup \ | ||
106 | test_testing_new_portreservation \ | 37 | test_testing_new_portreservation \ |
107 | test_testing_new_peerstartup \ | 38 | test_testing_new_peerstartup \ |
108 | test_testing_new_servicestartup | 39 | test_testing_new_servicestartup |
109 | endif | 40 | endif |
110 | 41 | ||
111 | gnunet_testing_SOURCES = \ | ||
112 | gnunet-testing.c | ||
113 | gnunet_testing_LDADD = \ | ||
114 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
115 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
116 | $(GN_LIBINTL) | ||
117 | gnunet_testing_DEPENDENCIES = \ | ||
118 | libgnunettesting.la | ||
119 | |||
120 | |||
121 | test_testing_SOURCES = \ | ||
122 | test_testing.c | ||
123 | test_testing_LDADD = \ | ||
124 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
125 | $(top_builddir)/src/util/libgnunetutil.la | ||
126 | |||
127 | test_testing_connect_SOURCES = \ | ||
128 | test_testing_connect.c | ||
129 | test_testing_connect_LDADD = \ | ||
130 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
131 | $(top_builddir)/src/util/libgnunetutil.la | ||
132 | |||
133 | test_testing_reconnect_SOURCES = \ | ||
134 | test_testing_reconnect.c | ||
135 | test_testing_reconnect_LDADD = \ | ||
136 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
137 | $(top_builddir)/src/util/libgnunetutil.la | ||
138 | |||
139 | test_testing_group_SOURCES = \ | ||
140 | test_testing_group.c | ||
141 | test_testing_group_LDADD = \ | ||
142 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
143 | $(top_builddir)/src/util/libgnunetutil.la | ||
144 | |||
145 | test_testing_peergroup_SOURCES = \ | ||
146 | test_testing_peergroup.c | ||
147 | test_testing_peergroup_LDADD = \ | ||
148 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
149 | $(top_builddir)/src/util/libgnunetutil.la | ||
150 | |||
151 | test_testing_topology_clique_SOURCES = \ | ||
152 | test_testing_topology.c | ||
153 | test_testing_topology_clique_LDADD = \ | ||
154 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
155 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
156 | $(top_builddir)/src/util/libgnunetutil.la | ||
157 | |||
158 | test_testing_topology_stability_SOURCES = \ | ||
159 | test_testing_topology.c | ||
160 | test_testing_topology_stability_LDADD = \ | ||
161 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
162 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
163 | $(top_builddir)/src/util/libgnunetutil.la | ||
164 | |||
165 | test_testing_topology_blacklist_SOURCES = \ | ||
166 | test_testing_topology_blacklist.c | ||
167 | test_testing_topology_blacklist_LDADD = \ | ||
168 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
169 | $(top_builddir)/src/util/libgnunetutil.la | ||
170 | |||
171 | test_testing_topology_churn_SOURCES = \ | ||
172 | test_testing_topology_churn.c | ||
173 | test_testing_topology_churn_LDADD = \ | ||
174 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
175 | $(top_builddir)/src/util/libgnunetutil.la | ||
176 | |||
177 | test_testing_topology_clique_random_SOURCES = \ | ||
178 | test_testing_topology.c | ||
179 | test_testing_topology_clique_random_LDADD = \ | ||
180 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
181 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
182 | $(top_builddir)/src/util/libgnunetutil.la | ||
183 | |||
184 | test_testing_topology_clique_minimum_SOURCES = \ | ||
185 | test_testing_topology.c | ||
186 | test_testing_topology_clique_minimum_LDADD = \ | ||
187 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
188 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
189 | $(top_builddir)/src/util/libgnunetutil.la | ||
190 | |||
191 | test_testing_topology_clique_dfs_SOURCES = \ | ||
192 | test_testing_topology.c | ||
193 | test_testing_topology_clique_dfs_LDADD = \ | ||
194 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
195 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
196 | $(top_builddir)/src/util/libgnunetutil.la | ||
197 | |||
198 | test_testing_topology_line_SOURCES = \ | ||
199 | test_testing_topology.c | ||
200 | test_testing_topology_line_LDADD = \ | ||
201 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
202 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
203 | $(top_builddir)/src/util/libgnunetutil.la | ||
204 | |||
205 | |||
206 | test_testing_group_remote_SOURCES = \ | ||
207 | test_testing_group_remote.c | ||
208 | test_testing_group_remote_LDADD = \ | ||
209 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
210 | $(top_builddir)/src/util/libgnunetutil.la | ||
211 | |||
212 | test_testing_2dtorus_SOURCES = \ | ||
213 | test_testing_2dtorus.c | ||
214 | test_testing_2dtorus_LDADD = \ | ||
215 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
216 | $(top_builddir)/src/util/libgnunetutil.la | ||
217 | |||
218 | test_testing_topology_ring_SOURCES = \ | ||
219 | test_testing_topology.c | ||
220 | test_testing_topology_ring_LDADD = \ | ||
221 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
222 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
223 | $(top_builddir)/src/util/libgnunetutil.la | ||
224 | |||
225 | test_testing_topology_2d_torus_SOURCES = \ | ||
226 | test_testing_topology.c | ||
227 | test_testing_topology_2d_torus_LDADD = \ | ||
228 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
229 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
230 | $(top_builddir)/src/util/libgnunetutil.la | ||
231 | |||
232 | test_testing_topology_small_world_ring_SOURCES = \ | ||
233 | test_testing_topology.c | ||
234 | test_testing_topology_small_world_ring_LDADD = \ | ||
235 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
236 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
237 | $(top_builddir)/src/util/libgnunetutil.la | ||
238 | |||
239 | test_testing_topology_small_world_torus_SOURCES = \ | ||
240 | test_testing_topology.c | ||
241 | test_testing_topology_small_world_torus_LDADD = \ | ||
242 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
243 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
244 | $(top_builddir)/src/util/libgnunetutil.la | ||
245 | |||
246 | test_testing_topology_internat_SOURCES = \ | ||
247 | test_testing_topology.c | ||
248 | test_testing_topology_internat_LDADD = \ | ||
249 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
250 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
251 | $(top_builddir)/src/util/libgnunetutil.la | ||
252 | |||
253 | test_testing_topology_erdos_renyi_SOURCES = \ | ||
254 | test_testing_topology.c | ||
255 | test_testing_topology_erdos_renyi_LDADD = \ | ||
256 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
257 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
258 | $(top_builddir)/src/util/libgnunetutil.la | ||
259 | |||
260 | test_testing_topology_scale_free_SOURCES = \ | ||
261 | test_testing_topology.c | ||
262 | test_testing_topology_scale_free_LDADD = \ | ||
263 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
264 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
265 | $(top_builddir)/src/util/libgnunetutil.la | ||
266 | |||
267 | test_testing_topology_none_SOURCES = \ | ||
268 | test_testing_topology.c | ||
269 | test_testing_topology_none_LDADD = \ | ||
270 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
271 | $(top_builddir)/src/core/libgnunetcore.la \ | ||
272 | $(top_builddir)/src/util/libgnunetutil.la | ||
273 | |||
274 | test_testing_new_portreservation_SOURCES = \ | 42 | test_testing_new_portreservation_SOURCES = \ |
275 | test_testing_new_portreservation.c | 43 | test_testing_new_portreservation.c |
276 | test_testing_new_portreservation_LDADD = \ | 44 | test_testing_new_portreservation_LDADD = \ |
277 | $(top_builddir)/src/testing/libgnunettesting_new.la \ | 45 | $(top_builddir)/src/testing/libgnunettesting.la \ |
278 | $(top_builddir)/src/util/libgnunetutil.la | 46 | $(top_builddir)/src/util/libgnunetutil.la |
279 | 47 | ||
280 | test_testing_new_peerstartup_SOURCES = \ | 48 | test_testing_new_peerstartup_SOURCES = \ |
281 | test_testing_new_peerstartup.c | 49 | test_testing_new_peerstartup.c |
282 | test_testing_new_peerstartup_LDADD = \ | 50 | test_testing_new_peerstartup_LDADD = \ |
283 | $(top_builddir)/src/testing/libgnunettesting_new.la \ | 51 | $(top_builddir)/src/testing/libgnunettesting.la \ |
284 | $(top_builddir)/src/util/libgnunetutil.la | 52 | $(top_builddir)/src/util/libgnunetutil.la |
285 | 53 | ||
286 | test_testing_new_servicestartup_SOURCES = \ | 54 | test_testing_new_servicestartup_SOURCES = \ |
287 | test_testing_new_servicestartup.c | 55 | test_testing_new_servicestartup.c |
288 | test_testing_new_servicestartup_LDADD = \ | 56 | test_testing_new_servicestartup_LDADD = \ |
289 | $(top_builddir)/src/testing/libgnunettesting_new.la \ | 57 | $(top_builddir)/src/testing/libgnunettesting.la \ |
290 | $(top_builddir)/src/util/libgnunetutil.la | 58 | $(top_builddir)/src/util/libgnunetutil.la |
291 | 59 | ||
292 | EXTRA_DIST = \ | ||
293 | test_testing_defaults.conf \ | ||
294 | test_testing_data.conf \ | ||
295 | test_testing_connect_peer1.conf \ | ||
296 | test_testing_connect_peer2.conf \ | ||
297 | test_testing_2dtorus.conf \ | ||
298 | test_testing_data_topology_clique.conf \ | ||
299 | test_testing_data_topology_clique_random.conf \ | ||
300 | test_testing_data_topology_clique_minimum.conf \ | ||
301 | test_testing_data_topology_clique_dfs.conf \ | ||
302 | test_testing_data_topology_ring.conf \ | ||
303 | test_testing_data_topology_2d_torus.conf \ | ||
304 | test_testing_data_topology_small_world_ring.conf \ | ||
305 | test_testing_data_topology_small_world_torus.conf \ | ||
306 | test_testing_data_topology_erdos_renyi.conf \ | ||
307 | test_testing_data_topology_internat.conf \ | ||
308 | test_testing_data_topology_scale_free.conf \ | ||
309 | test_testing_data_topology_blacklist.conf \ | ||
310 | test_testing_data_topology_churn.conf \ | ||
311 | test_testing_data_topology_none.conf \ | ||
312 | test_testing_data_remote.conf \ | ||
313 | test_testing_data_topology_stability.conf \ | ||
314 | test_testing_peergroup_data.conf | ||
diff --git a/src/testing/gnunet-testing-remote-peer-start.pl b/src/testing/gnunet-testing-remote-peer-start.pl deleted file mode 100755 index e4f72e9d0..000000000 --- a/src/testing/gnunet-testing-remote-peer-start.pl +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | # | ||
2 | # This file is part of GNUnet | ||
3 | # (C) 2008, 2009 Christian Grothoff (and other contributing authors) | ||
4 | # | ||
5 | # GNUnet is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published | ||
7 | # by the Free Software Foundation; either version 3, or (at your | ||
8 | # option) any later version. | ||
9 | # | ||
10 | # GNUnet is distributed in the hope that it will be useful, but | ||
11 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with GNUnet; see the file COPYING. If not, write to the | ||
17 | # Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | # Boston, MA 02111-1307, USA. | ||
19 | # | ||
20 | # | ||
21 | # | ||
22 | # @file contrib/peerStartHelper.pl | ||
23 | # @brief Helper process for starting gnunet-testing peers. | ||
24 | # @author Nathan Evans | ||
25 | # | ||
26 | # Finds configuration files (or any files) of the format | ||
27 | # /path/*/gnunet-testing-config* and runs gnunet-arm with | ||
28 | # each as the given configuration. | ||
29 | # | ||
30 | # usage: peerStartHelper.pl /path/to/testing_dir/ | ||
31 | #!/usr/bin/perl | ||
32 | use strict; | ||
33 | |||
34 | my $max_outstanding = 300; | ||
35 | |||
36 | $ARGV[0] || die "No directory provided for peer information, exiting!\n"; | ||
37 | |||
38 | my $directory = $ARGV[0]; | ||
39 | my @config_files = `find $directory -iname gnunet-testing-config*`; | ||
40 | my @child_arr = {}; | ||
41 | my $count = 0; | ||
42 | my $outstanding = 0; | ||
43 | foreach my $file (@config_files) | ||
44 | { | ||
45 | chomp($file); | ||
46 | #print "Starting GNUnet peer with config file $file\n"; | ||
47 | my $pid = fork(); | ||
48 | if ($pid == -1) | ||
49 | { | ||
50 | die; | ||
51 | } | ||
52 | elsif ($pid == 0) | ||
53 | { | ||
54 | exec "gnunet-arm -q -c $file -s" or die; | ||
55 | } | ||
56 | |||
57 | if ($pid != 0) | ||
58 | { | ||
59 | push @child_arr, $pid; | ||
60 | $count++; | ||
61 | $outstanding++; | ||
62 | if ($outstanding > $max_outstanding) | ||
63 | { | ||
64 | for (my $i = 0; $i < $max_outstanding / 5; $i++) | ||
65 | { | ||
66 | #print "Too many outstanding peers, waiting!\n"; | ||
67 | waitpid($child_arr[0], 0); | ||
68 | shift(@child_arr); | ||
69 | $outstanding--; | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | print "All $count peers started (waiting for them to finish!\n"; | ||
76 | |||
77 | while ($outstanding > 0) | ||
78 | { | ||
79 | waitpid($child_arr[0], 0); | ||
80 | shift(@child_arr); | ||
81 | $outstanding--; | ||
82 | if ($outstanding % 50 == 0) | ||
83 | { | ||
84 | print "All $count peers started (waiting for $outstanding to finish!\n"; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | while (wait() != -1) {sleep 1} | ||
89 | |||
90 | print "All $count peers started!\n"; | ||
91 | |||
92 | |||
diff --git a/src/testing/gnunet-testing.c b/src/testing/gnunet-testing.c deleted file mode 100644 index bdbb5e8c5..000000000 --- a/src/testing/gnunet-testing.c +++ /dev/null | |||
@@ -1,291 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file testing/gnunet-testing.c | ||
23 | * @brief tool to use testing functionality from cmd line | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_getopt_lib.h" | ||
28 | #include "gnunet_program_lib.h" | ||
29 | #include "gnunet_testing_lib.h" | ||
30 | |||
31 | #define HOSTKEYFILESIZE 914 | ||
32 | |||
33 | /** | ||
34 | * Final status code. | ||
35 | */ | ||
36 | static int ret; | ||
37 | |||
38 | static unsigned int create_hostkey; | ||
39 | |||
40 | static unsigned int create_cfg; | ||
41 | |||
42 | static int create_no; | ||
43 | |||
44 | static char * create_cfg_template; | ||
45 | |||
46 | static char * create_hostkey_file; | ||
47 | |||
48 | static int | ||
49 | create_unique_cfgs (const char * template, const unsigned int no) | ||
50 | { | ||
51 | int fail = GNUNET_NO; | ||
52 | |||
53 | uint16_t port = 20000; | ||
54 | uint32_t upnum = 1; | ||
55 | uint32_t fdnum = 1; | ||
56 | |||
57 | if (GNUNET_NO == GNUNET_DISK_file_test(template)) | ||
58 | { | ||
59 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Configuration template `%s': file not found\n", create_cfg_template); | ||
60 | return 1; | ||
61 | } | ||
62 | |||
63 | int cur = 0; | ||
64 | char * cur_file; | ||
65 | char *service_home = NULL; | ||
66 | char *cur_service_home = NULL; | ||
67 | |||
68 | struct GNUNET_CONFIGURATION_Handle *cfg_new = NULL; | ||
69 | struct GNUNET_CONFIGURATION_Handle *cfg_tmpl = GNUNET_CONFIGURATION_create(); | ||
70 | |||
71 | /* load template */ | ||
72 | if ((create_cfg_template != NULL) && (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, create_cfg_template))) | ||
73 | { | ||
74 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load template `%s'\n", create_cfg_template); | ||
75 | GNUNET_CONFIGURATION_destroy(cfg_tmpl); | ||
76 | |||
77 | return 1; | ||
78 | } | ||
79 | /* load defaults */ | ||
80 | else if (GNUNET_OK != GNUNET_CONFIGURATION_load(cfg_tmpl, NULL)) | ||
81 | { | ||
82 | GNUNET_break (0); | ||
83 | return 1; | ||
84 | } | ||
85 | |||
86 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg_tmpl, "PATHS", "SERVICEHOME", &service_home)) | ||
87 | { | ||
88 | GNUNET_asprintf(&service_home, "%s", "/tmp/testing"); | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | int s = strlen (service_home); | ||
93 | if (service_home[s-1] == DIR_SEPARATOR) | ||
94 | service_home[s-1] = '\0'; | ||
95 | } | ||
96 | |||
97 | while (cur < no) | ||
98 | { | ||
99 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating configuration no. %u \n", cur); | ||
100 | if (create_cfg_template != NULL) | ||
101 | GNUNET_asprintf (&cur_file,"%04u-%s",cur, create_cfg_template); | ||
102 | else | ||
103 | GNUNET_asprintf (&cur_file,"%04u%s",cur, ".conf"); | ||
104 | |||
105 | |||
106 | GNUNET_asprintf (&cur_service_home, "%s-%04u%c",service_home, cur, DIR_SEPARATOR); | ||
107 | GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","SERVICEHOME", cur_service_home); | ||
108 | GNUNET_CONFIGURATION_set_value_string (cfg_tmpl,"PATHS","DEFAULTCONFIG", cur_file); | ||
109 | GNUNET_free (cur_service_home); | ||
110 | |||
111 | cfg_new = GNUNET_TESTING_create_cfg(cfg_tmpl, cur, &port, &upnum, NULL, &fdnum); | ||
112 | |||
113 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing configuration no. %u to file `%s' \n", cur, cur_file); | ||
114 | if (GNUNET_OK != GNUNET_CONFIGURATION_write(cfg_new, cur_file)) | ||
115 | { | ||
116 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write configuration no. %u \n", cur); | ||
117 | fail = GNUNET_YES; | ||
118 | } | ||
119 | |||
120 | GNUNET_CONFIGURATION_destroy (cfg_new); | ||
121 | GNUNET_free (cur_file); | ||
122 | if (fail == GNUNET_YES) | ||
123 | break; | ||
124 | cur ++; | ||
125 | } | ||
126 | |||
127 | GNUNET_CONFIGURATION_destroy(cfg_tmpl); | ||
128 | GNUNET_free (service_home); | ||
129 | if (fail == GNUNET_NO) | ||
130 | return 0; | ||
131 | else | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | static int | ||
136 | create_hostkeys (const unsigned int no) | ||
137 | { | ||
138 | struct GNUNET_DISK_FileHandle *fd; | ||
139 | int cur = 0; | ||
140 | uint64_t fs; | ||
141 | uint64_t total_hostkeys; | ||
142 | char *hostkey_data; | ||
143 | char *hostkey_src_file; | ||
144 | char *hostkey_dest_file; | ||
145 | |||
146 | /* prepare hostkeys */ | ||
147 | if (create_hostkey_file == NULL) | ||
148 | hostkey_src_file = "../../contrib/testing_hostkeys.dat"; | ||
149 | else | ||
150 | { | ||
151 | hostkey_src_file = create_hostkey_file; | ||
152 | } | ||
153 | |||
154 | if (GNUNET_YES != GNUNET_DISK_file_test (hostkey_src_file)) | ||
155 | { | ||
156 | if (create_hostkey_file == NULL) | ||
157 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file, specify hostkey file with -H!\n")); | ||
158 | else | ||
159 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Specified hostkey file `%s' not found!\n"), create_hostkey_file); | ||
160 | return 1; | ||
161 | } | ||
162 | else | ||
163 | { | ||
164 | /* Check hostkey file size, read entire thing into memory */ | ||
165 | fd = GNUNET_DISK_file_open (hostkey_src_file, GNUNET_DISK_OPEN_READ, | ||
166 | GNUNET_DISK_PERM_NONE); | ||
167 | if (NULL == fd) | ||
168 | { | ||
169 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkey_src_file); | ||
170 | return 1; | ||
171 | } | ||
172 | |||
173 | if (GNUNET_OK != GNUNET_DISK_file_size (hostkey_src_file, &fs, GNUNET_YES, GNUNET_YES)) | ||
174 | fs = 0; | ||
175 | |||
176 | if (0 != (fs % HOSTKEYFILESIZE)) | ||
177 | { | ||
178 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
179 | "File size %llu seems incorrect for hostkeys...\n", fs); | ||
180 | } | ||
181 | else | ||
182 | { | ||
183 | total_hostkeys = fs / HOSTKEYFILESIZE; | ||
184 | hostkey_data = GNUNET_malloc_large (fs); | ||
185 | GNUNET_assert (fs == GNUNET_DISK_file_read (fd, hostkey_data, fs)); | ||
186 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
187 | "Read %llu hostkeys from file\n", total_hostkeys); | ||
188 | } | ||
189 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); | ||
190 | } | ||
191 | |||
192 | while (cur < no) | ||
193 | { | ||
194 | GNUNET_asprintf (&hostkey_dest_file, "%04u-hostkey",cur); | ||
195 | GNUNET_assert (GNUNET_OK == | ||
196 | GNUNET_DISK_directory_create_for_file (hostkey_dest_file)); | ||
197 | fd = GNUNET_DISK_file_open (hostkey_dest_file, | ||
198 | GNUNET_DISK_OPEN_READWRITE | | ||
199 | GNUNET_DISK_OPEN_CREATE, | ||
200 | GNUNET_DISK_PERM_USER_READ | | ||
201 | GNUNET_DISK_PERM_USER_WRITE); | ||
202 | GNUNET_assert (fd != NULL); | ||
203 | GNUNET_assert (HOSTKEYFILESIZE == | ||
204 | GNUNET_DISK_file_write (fd, &hostkey_data[cur * HOSTKEYFILESIZE], HOSTKEYFILESIZE)); | ||
205 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); | ||
206 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", | ||
207 | "Wrote hostkey to file: `%s' \n", hostkey_dest_file); | ||
208 | GNUNET_free (hostkey_dest_file); | ||
209 | cur ++; | ||
210 | } | ||
211 | |||
212 | GNUNET_free (hostkey_data); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * Main function that will be run by the scheduler. | ||
219 | * | ||
220 | * @param cls closure | ||
221 | * @param args remaining command-line arguments | ||
222 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
223 | * @param cfg configuration | ||
224 | */ | ||
225 | static void | ||
226 | run (void *cls, char *const *args, const char *cfgfile, | ||
227 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
228 | { | ||
229 | /* main code here */ | ||
230 | if (create_cfg == GNUNET_YES) | ||
231 | { | ||
232 | if (create_no > 0) | ||
233 | { | ||
234 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u configuration files based on template `%s'\n", create_no, create_cfg_template); | ||
235 | ret = create_unique_cfgs (create_cfg_template, create_no); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); | ||
240 | ret = 1; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (create_hostkey == GNUNET_YES) | ||
245 | { | ||
246 | if (create_no > 0) | ||
247 | { | ||
248 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating %u hostkeys \n", create_no); | ||
249 | ret = create_hostkeys (create_no); | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Missing arguments! \n"); | ||
254 | ret = 1; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | GNUNET_free_non_null (create_cfg_template); | ||
259 | } | ||
260 | |||
261 | |||
262 | /** | ||
263 | * The main function. | ||
264 | * | ||
265 | * @param argc number of arguments from the command line | ||
266 | * @param argv command line arguments | ||
267 | * @return 0 ok, 1 on error | ||
268 | */ | ||
269 | int | ||
270 | main (int argc, char *const *argv) | ||
271 | { | ||
272 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
273 | {'C', "cfg", NULL, gettext_noop ("create unique configuration files"), | ||
274 | GNUNET_NO, &GNUNET_GETOPT_set_one, &create_cfg}, | ||
275 | {'k', "key", NULL, gettext_noop ("create hostkey files from pre-computed hostkey list"), | ||
276 | GNUNET_NO, &GNUNET_GETOPT_set_one, &create_hostkey}, | ||
277 | {'H', "hostkeys", NULL, gettext_noop ("host key file"), | ||
278 | GNUNET_YES, &GNUNET_GETOPT_set_string, &create_hostkey_file}, | ||
279 | {'n', "number", NULL, gettext_noop ("number of unique configuration files or hostkeys to create"), | ||
280 | GNUNET_YES, &GNUNET_GETOPT_set_uint, &create_no}, | ||
281 | {'t', "template", NULL, gettext_noop ("configuration template"), | ||
282 | GNUNET_YES, &GNUNET_GETOPT_set_string, &create_cfg_template}, | ||
283 | GNUNET_GETOPT_OPTION_END | ||
284 | }; | ||
285 | return (GNUNET_OK == | ||
286 | GNUNET_PROGRAM_run (argc, argv, "gnunet-testing", | ||
287 | gettext_noop ("Command line tool to access the testing library"), options, &run, | ||
288 | NULL)) ? ret : 1; | ||
289 | } | ||
290 | |||
291 | /* end of gnunet-testing.c */ | ||
diff --git a/src/testing/helper.c b/src/testing/helper.c deleted file mode 100644 index ebb37ebe5..000000000 --- a/src/testing/helper.c +++ /dev/null | |||
@@ -1,75 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2012 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file testing/helper.c | ||
23 | * @brief helper functions for testing | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_testing_lib.h" | ||
29 | |||
30 | |||
31 | |||
32 | |||
33 | /** | ||
34 | * Obtain the peer identity of the peer with the given configuration | ||
35 | * handle. This function reads the private key of the peer, obtains | ||
36 | * the public key and hashes it. | ||
37 | * | ||
38 | * @param cfg configuration of the peer | ||
39 | * @param pid where to store the peer identity | ||
40 | * @return GNUNET_OK on success, GNUNET_SYSERR on failure | ||
41 | */ | ||
42 | int | ||
43 | GNUNET_TESTING_get_peer_identity (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
44 | struct GNUNET_PeerIdentity *pid) | ||
45 | { | ||
46 | char *keyfile; | ||
47 | struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; | ||
48 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; | ||
49 | |||
50 | if (GNUNET_OK != | ||
51 | GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", | ||
52 | &keyfile)) | ||
53 | { | ||
54 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
55 | _ | ||
56 | ("Peer is lacking HOSTKEY configuration setting.\n")); | ||
57 | return GNUNET_SYSERR; | ||
58 | } | ||
59 | my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | ||
60 | GNUNET_free (keyfile); | ||
61 | if (my_private_key == NULL) | ||
62 | { | ||
63 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
64 | _("Could not access hostkey.\n")); | ||
65 | return GNUNET_SYSERR; | ||
66 | } | ||
67 | GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); | ||
68 | GNUNET_CRYPTO_rsa_key_free (my_private_key); | ||
69 | GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), | ||
70 | &pid->hashPubKey); | ||
71 | return GNUNET_OK; | ||
72 | } | ||
73 | |||
74 | |||
75 | /* end of helper.c */ | ||
diff --git a/src/testing/test_testing.c b/src/testing/test_testing.c deleted file mode 100644 index 3e2cd65ee..000000000 --- a/src/testing/test_testing.c +++ /dev/null | |||
@@ -1,126 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing.c | ||
22 | * @brief testcase for testing.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | |||
27 | #define VERBOSE GNUNET_YES | ||
28 | |||
29 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
30 | |||
31 | static int ok; | ||
32 | |||
33 | static void | ||
34 | end_cb (void *cls, const char *emsg) | ||
35 | { | ||
36 | if (emsg != NULL) | ||
37 | { | ||
38 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); | ||
39 | ok = 1; | ||
40 | } | ||
41 | else | ||
42 | { | ||
43 | #if VERBOSE | ||
44 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon terminated, will now exit.\n"); | ||
45 | #endif | ||
46 | ok = 0; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | |||
51 | |||
52 | void | ||
53 | do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
54 | { | ||
55 | struct GNUNET_TESTING_Daemon *d = cls; | ||
56 | |||
57 | GNUNET_TESTING_daemon_stop (d, TIMEOUT, &end_cb, NULL, GNUNET_YES, GNUNET_NO); | ||
58 | } | ||
59 | |||
60 | |||
61 | static void | ||
62 | my_cb (void *cls, const struct GNUNET_PeerIdentity *id, | ||
63 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
64 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
65 | { | ||
66 | GNUNET_assert (id != NULL); | ||
67 | #if VERBOSE | ||
68 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
69 | "Daemon `%s' started, will now stop it.\n", GNUNET_i2s (id)); | ||
70 | #endif | ||
71 | GNUNET_SCHEDULER_add_now (&do_shutdown, d); | ||
72 | } | ||
73 | |||
74 | |||
75 | static void | ||
76 | run (void *cls, char *const *args, const char *cfgfile, | ||
77 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
78 | { | ||
79 | struct GNUNET_TESTING_Daemon *d; | ||
80 | |||
81 | ok = 1; | ||
82 | #if VERBOSE | ||
83 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); | ||
84 | #endif | ||
85 | d = GNUNET_TESTING_daemon_start (cfg, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, | ||
86 | NULL, NULL, &my_cb, NULL); | ||
87 | GNUNET_assert (d != NULL); | ||
88 | } | ||
89 | |||
90 | static int | ||
91 | check () | ||
92 | { | ||
93 | char *const argv[] = { "test-testing", | ||
94 | "-c", | ||
95 | "test_testing_data.conf", | ||
96 | #if VERBOSE | ||
97 | "-L", "DEBUG", | ||
98 | #endif | ||
99 | NULL | ||
100 | }; | ||
101 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
102 | GNUNET_GETOPT_OPTION_END | ||
103 | }; | ||
104 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
105 | "test-testing", "nohelp", options, &run, &ok); | ||
106 | return ok; | ||
107 | } | ||
108 | |||
109 | int | ||
110 | main (int argc, char *argv[]) | ||
111 | { | ||
112 | int ret; | ||
113 | |||
114 | GNUNET_log_setup ("test-testing", | ||
115 | #if VERBOSE | ||
116 | "DEBUG", | ||
117 | #else | ||
118 | "WARNING", | ||
119 | #endif | ||
120 | NULL); | ||
121 | ret = check (); | ||
122 | |||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | /* end of test_testing.c */ | ||
diff --git a/src/testing/test_testing_2dtorus.c b/src/testing/test_testing_2dtorus.c deleted file mode 100644 index 00a66d65c..000000000 --- a/src/testing/test_testing_2dtorus.c +++ /dev/null | |||
@@ -1,372 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_2dtorus.c | ||
22 | * | ||
23 | * @brief Test for creating a 2dtorus. | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_testing_lib.h" | ||
27 | |||
28 | #define VERBOSE GNUNET_YES | ||
29 | #define REMOVE_DIR GNUNET_YES | ||
30 | |||
31 | /** | ||
32 | * How long until we give up on connecting the peers? | ||
33 | */ | ||
34 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500) | ||
35 | |||
36 | /** | ||
37 | * Time to wait for stuff that should be rather fast | ||
38 | */ | ||
39 | #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
40 | |||
41 | |||
42 | /** | ||
43 | * How many events have happened | ||
44 | */ | ||
45 | static int ok; | ||
46 | |||
47 | /** | ||
48 | * Be verbose | ||
49 | */ | ||
50 | static int verbose; | ||
51 | |||
52 | /** | ||
53 | * Total number of peers in the test. | ||
54 | */ | ||
55 | static unsigned long long num_peers; | ||
56 | |||
57 | /** | ||
58 | * Global configuration file | ||
59 | */ | ||
60 | static struct GNUNET_CONFIGURATION_Handle *testing_cfg; | ||
61 | |||
62 | /** | ||
63 | * Total number of currently running peers. | ||
64 | */ | ||
65 | static unsigned long long peers_running; | ||
66 | |||
67 | /** | ||
68 | * Total number of successful connections in the whole network. | ||
69 | */ | ||
70 | static unsigned int total_connections; | ||
71 | |||
72 | /** | ||
73 | * Total number of counted topo connections | ||
74 | */ | ||
75 | static unsigned int topo_connections; | ||
76 | |||
77 | /** | ||
78 | * Total number of failed connections in the whole network. | ||
79 | */ | ||
80 | static unsigned int failed_connections; | ||
81 | |||
82 | /** | ||
83 | * The currently running peer group. | ||
84 | */ | ||
85 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
86 | |||
87 | /** | ||
88 | * Task called to disconnect peers | ||
89 | */ | ||
90 | static GNUNET_SCHEDULER_TaskIdentifier disconnect_task; | ||
91 | |||
92 | /** | ||
93 | * Task called to shutdown test. | ||
94 | */ | ||
95 | static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle; | ||
96 | |||
97 | |||
98 | /** | ||
99 | * Check whether peers successfully shut down. | ||
100 | */ | ||
101 | static void | ||
102 | shutdown_callback (void *cls, const char *emsg) | ||
103 | { | ||
104 | if (emsg != NULL) | ||
105 | { | ||
106 | #if VERBOSE | ||
107 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n"); | ||
108 | #endif | ||
109 | ok--; | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | #if VERBOSE | ||
114 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
115 | "test: All peers successfully shut down!\n"); | ||
116 | #endif | ||
117 | } | ||
118 | } | ||
119 | |||
120 | |||
121 | static void | ||
122 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
123 | { | ||
124 | #if VERBOSE | ||
125 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n"); | ||
126 | #endif | ||
127 | |||
128 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
129 | GNUNET_CONFIGURATION_destroy (testing_cfg); | ||
130 | } | ||
131 | |||
132 | |||
133 | static void | ||
134 | disconnect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
135 | { | ||
136 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: disconnecting peers\n"); | ||
137 | |||
138 | if (GNUNET_SCHEDULER_NO_TASK != shutdown_handle) | ||
139 | { | ||
140 | GNUNET_SCHEDULER_cancel (shutdown_handle); | ||
141 | shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Prototype of a callback function indicating that two peers | ||
148 | * are currently connected. | ||
149 | * | ||
150 | * @param cls closure | ||
151 | * @param first peer id for first daemon | ||
152 | * @param second peer id for the second daemon | ||
153 | * @param distance distance between the connected peers | ||
154 | * @param emsg error message (NULL on success) | ||
155 | */ | ||
156 | void | ||
157 | topo_cb (void *cls, const struct GNUNET_PeerIdentity *first, | ||
158 | const struct GNUNET_PeerIdentity *second, const char *emsg) | ||
159 | { | ||
160 | topo_connections++; | ||
161 | if (NULL != emsg) | ||
162 | { | ||
163 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: Error by topo %u: %s\n", | ||
164 | topo_connections, emsg); | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | if (first == NULL || second == NULL) | ||
169 | { | ||
170 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u NULL\n", | ||
171 | topo_connections); | ||
172 | if (disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
173 | { | ||
174 | GNUNET_SCHEDULER_cancel (disconnect_task); | ||
175 | GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); | ||
176 | } | ||
177 | return; | ||
178 | } | ||
179 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Connection %u ok\n", | ||
180 | topo_connections); | ||
181 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (first)); | ||
182 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: %s\n", GNUNET_i2s (second)); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * peergroup_ready: start test when all peers are connected | ||
189 | * @param cls closure | ||
190 | * @param emsg error message | ||
191 | */ | ||
192 | static void | ||
193 | peergroup_ready (void *cls, const char *emsg) | ||
194 | { | ||
195 | if (emsg != NULL) | ||
196 | { | ||
197 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
198 | "test: Peergroup callback called with error, aborting test!\n"); | ||
199 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Error from testing: `%s'\n", | ||
200 | emsg); | ||
201 | ok--; | ||
202 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
203 | return; | ||
204 | } | ||
205 | #if VERBOSE | ||
206 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
207 | "************************************************************\n"); | ||
208 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
209 | "test: Peer Group started successfully!\n"); | ||
210 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Have %u connections\n", | ||
211 | total_connections); | ||
212 | #endif | ||
213 | |||
214 | peers_running = GNUNET_TESTING_daemons_running (pg); | ||
215 | if (0 < failed_connections) | ||
216 | { | ||
217 | ok = GNUNET_SYSERR; | ||
218 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "test: %u connections have FAILED!\n", | ||
219 | failed_connections); | ||
220 | disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_peers, NULL); | ||
221 | |||
222 | } | ||
223 | else | ||
224 | { | ||
225 | GNUNET_TESTING_get_topology (pg, &topo_cb, NULL); | ||
226 | disconnect_task = | ||
227 | GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &disconnect_peers, NULL); | ||
228 | ok = GNUNET_OK; | ||
229 | } | ||
230 | |||
231 | } | ||
232 | |||
233 | |||
234 | /** | ||
235 | * Function that will be called whenever two daemons are connected by | ||
236 | * the testing library. | ||
237 | * | ||
238 | * @param cls closure | ||
239 | * @param first peer id for first daemon | ||
240 | * @param second peer id for the second daemon | ||
241 | * @param distance distance between the connected peers | ||
242 | * @param first_cfg config for the first daemon | ||
243 | * @param second_cfg config for the second daemon | ||
244 | * @param first_daemon handle for the first daemon | ||
245 | * @param second_daemon handle for the second daemon | ||
246 | * @param emsg error message (NULL on success) | ||
247 | */ | ||
248 | static void | ||
249 | connect_cb (void *cls, const struct GNUNET_PeerIdentity *first, | ||
250 | const struct GNUNET_PeerIdentity *second, uint32_t distance, | ||
251 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
252 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
253 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
254 | struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg) | ||
255 | { | ||
256 | if (emsg == NULL) | ||
257 | { | ||
258 | total_connections++; | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 | failed_connections++; | ||
263 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
264 | "test: Problem with new connection (%s)\n", emsg); | ||
265 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (first)); | ||
266 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: (%s)\n", GNUNET_i2s (second)); | ||
267 | } | ||
268 | |||
269 | } | ||
270 | |||
271 | |||
272 | /** | ||
273 | * run: load configuration options and schedule test to run (start peergroup) | ||
274 | * @param cls closure | ||
275 | * @param args argv | ||
276 | * @param cfgfile configuration file name (can be NULL) | ||
277 | * @param cfg configuration handle | ||
278 | */ | ||
279 | static void | ||
280 | run (void *cls, char *const *args, const char *cfgfile, | ||
281 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
282 | { | ||
283 | struct GNUNET_TESTING_Host *hosts; | ||
284 | |||
285 | ok = GNUNET_NO; | ||
286 | total_connections = 0; | ||
287 | failed_connections = 0; | ||
288 | testing_cfg = GNUNET_CONFIGURATION_dup (cfg); | ||
289 | |||
290 | GNUNET_log_setup ("test_testing_2dtorus", | ||
291 | #if VERBOSE | ||
292 | "DEBUG", | ||
293 | #else | ||
294 | "WARNING", | ||
295 | #endif | ||
296 | NULL); | ||
297 | |||
298 | #if VERBOSE | ||
299 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n"); | ||
300 | GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", | ||
301 | "use_progressbars", "YES"); | ||
302 | #endif | ||
303 | |||
304 | if (GNUNET_OK != | ||
305 | GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing", | ||
306 | "num_peers", &num_peers)) | ||
307 | { | ||
308 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
309 | "Option TESTING:NUM_PEERS is required!\n"); | ||
310 | return; | ||
311 | } | ||
312 | |||
313 | hosts = GNUNET_TESTING_hosts_load (testing_cfg); | ||
314 | |||
315 | pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT, | ||
316 | &connect_cb, &peergroup_ready, NULL, | ||
317 | hosts); | ||
318 | GNUNET_assert (pg != NULL); | ||
319 | shutdown_handle = | ||
320 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
321 | &shutdown_task, NULL); | ||
322 | } | ||
323 | |||
324 | |||
325 | /** | ||
326 | * test_testing_2dtorus command line options | ||
327 | */ | ||
328 | static struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
329 | {'V', "verbose", NULL, | ||
330 | gettext_noop ("be verbose (print progress information)"), | ||
331 | 0, &GNUNET_GETOPT_set_one, &verbose}, | ||
332 | GNUNET_GETOPT_OPTION_END | ||
333 | }; | ||
334 | |||
335 | |||
336 | /** | ||
337 | * Main: start test | ||
338 | */ | ||
339 | int | ||
340 | main (int argc, char *argv[]) | ||
341 | { | ||
342 | char *const argv2[] = { | ||
343 | argv[0], | ||
344 | "-c", | ||
345 | "test_testing_2dtorus.conf", | ||
346 | #if VERBOSE | ||
347 | "-L", | ||
348 | "DEBUG", | ||
349 | #endif | ||
350 | NULL | ||
351 | }; | ||
352 | |||
353 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Start\n"); | ||
354 | |||
355 | |||
356 | GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2, | ||
357 | "test_testing_2dtorus", | ||
358 | gettext_noop ("Test testing 2d torus."), options, &run, | ||
359 | NULL); | ||
360 | #if REMOVE_DIR | ||
361 | GNUNET_DISK_directory_remove ("/tmp/test_testing_2dtorus"); | ||
362 | #endif | ||
363 | if (GNUNET_OK != ok) | ||
364 | { | ||
365 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "test: FAILED!\n"); | ||
366 | return 1; | ||
367 | } | ||
368 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n"); | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | /* end of test_testing_2dtorus.c */ | ||
diff --git a/src/testing/test_testing_2dtorus.conf b/src/testing/test_testing_2dtorus.conf deleted file mode 100644 index 54bb7c5a7..000000000 --- a/src/testing/test_testing_2dtorus.conf +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | SERVICEHOME = /tmp/test_testing_2dtorus/ | ||
4 | DEFAULTCONFIG = test_testing_2dtorus.conf | ||
5 | |||
6 | [arm] | ||
7 | PORT = 10010 | ||
8 | DEFAULTSERVICES = core | ||
9 | #DEBUG = YES | ||
10 | |||
11 | [statistics] | ||
12 | AUTOSTART = YES | ||
13 | PORT = 10000 | ||
14 | |||
15 | [dht] | ||
16 | DEBUG = NO | ||
17 | AUTOSTART = YES | ||
18 | ACCEPT_FROM6 = ::1; | ||
19 | ACCEPT_FROM = 127.0.0.1; | ||
20 | HOSTNAME = localhost | ||
21 | PORT = 10001 | ||
22 | |||
23 | [nse] | ||
24 | WORKBITS = 0 | ||
25 | |||
26 | [dns] | ||
27 | AUTOSTART = NO | ||
28 | PORT = 10011 | ||
29 | |||
30 | [transport] | ||
31 | PORT = 10002 | ||
32 | AUTOSTART = YES | ||
33 | PLUGINS = tcp | ||
34 | |||
35 | [nat] | ||
36 | DISABLEV6 = YES | ||
37 | BINDTO = 127.0.0.1 | ||
38 | ENABLE_UPNP = NO | ||
39 | BEHIND_NAT = NO | ||
40 | ALLOW_NAT = NO | ||
41 | INTERNAL_ADDRESS = 127.0.0.1 | ||
42 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
43 | |||
44 | [ats] | ||
45 | WAN_QUOTA_IN = 1 GB | ||
46 | WAN_QUOTA_OUT = 1 GB | ||
47 | |||
48 | [core] | ||
49 | AUTOSTART = YES | ||
50 | PORT = 10003 | ||
51 | |||
52 | [peerinfo] | ||
53 | AUTOSTART = YES | ||
54 | PORT = 10004 | ||
55 | |||
56 | [testing] | ||
57 | NUM_PEERS = 16 | ||
58 | WEAKRANDOM = YES | ||
59 | TOPOLOGY = 2D_TORUS | ||
60 | CONNECT_TOPOLOGY = 2D_TORUS | ||
61 | #TOPOLOGY_FILE = small.dat | ||
62 | CONNECT_TOPOLOGY = 2D_TORUS | ||
63 | #CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM | ||
64 | #CONNECT_TOPOLOGY_OPTION_MODIFIER = 25 | ||
65 | #PERCENTAGE = 3 | ||
66 | #PROBABILITY = .1 | ||
67 | F2F = NO | ||
68 | CONNECT_TIMEOUT = 600 s | ||
69 | CONNECT_ATTEMPTS = 2 | ||
70 | DEBUG = YES | ||
71 | HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat | ||
72 | MAX_CONCURRENT_SSH = 10 | ||
73 | USE_PROGRESSBARS = YES | ||
74 | PEERGROUP_TIMEOUT = 2400 s | ||
75 | TOPOLOGY_OUTPUT_FILE = testing_topo_initial | ||
76 | MAX_OUTSTANDING_CONNECTIONS = 75 | ||
77 | #SINGLE_PEERINFO_PER_HOST = YES | ||
78 | #NUM_PEERINFO_PER_HOST = 10 | ||
79 | #SINGLE_STATISTICS_PER_HOST = YES | ||
80 | #NUM_STATISTICS_PER_HOST = 10 | ||
81 | DELETE_FILES = YES | ||
diff --git a/src/testing/test_testing_connect.c b/src/testing/test_testing_connect.c deleted file mode 100644 index c69c20326..000000000 --- a/src/testing/test_testing_connect.c +++ /dev/null | |||
@@ -1,197 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_connect.c | ||
22 | * @brief testcase for functions to connect two peers in testing.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | |||
27 | #define VERBOSE GNUNET_NO | ||
28 | |||
29 | /** | ||
30 | * How long until we give up on connecting the peers? | ||
31 | */ | ||
32 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
33 | |||
34 | #define CONNECT_ATTEMPTS 3 | ||
35 | |||
36 | static int ok; | ||
37 | |||
38 | static struct GNUNET_TESTING_Daemon *d1; | ||
39 | |||
40 | static struct GNUNET_TESTING_Daemon *d2; | ||
41 | |||
42 | static struct GNUNET_CONFIGURATION_Handle *c1; | ||
43 | |||
44 | static struct GNUNET_CONFIGURATION_Handle *c2; | ||
45 | |||
46 | static struct GNUNET_TESTING_ConnectContext *cc; | ||
47 | |||
48 | static void | ||
49 | end2_cb (void *cls, const char *emsg) | ||
50 | { | ||
51 | |||
52 | if (emsg != NULL) | ||
53 | { | ||
54 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); | ||
55 | ok = 1; | ||
56 | } | ||
57 | else | ||
58 | { | ||
59 | #if VERBOSE | ||
60 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
61 | "Both daemons terminated, will now exit.\n"); | ||
62 | #endif | ||
63 | ok = 0; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static void | ||
68 | end1_cb (void *cls, const char *emsg) | ||
69 | { | ||
70 | if (emsg != NULL) | ||
71 | { | ||
72 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", | ||
73 | emsg); | ||
74 | ok = 1; | ||
75 | } | ||
76 | else | ||
77 | { | ||
78 | ok = 0; | ||
79 | } | ||
80 | |||
81 | GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, GNUNET_YES, | ||
82 | GNUNET_NO); | ||
83 | d2 = NULL; | ||
84 | } | ||
85 | |||
86 | static void | ||
87 | finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
88 | { | ||
89 | GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, GNUNET_YES, | ||
90 | GNUNET_NO); | ||
91 | d1 = NULL; | ||
92 | } | ||
93 | |||
94 | static void | ||
95 | my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, | ||
96 | const struct GNUNET_PeerIdentity *second, | ||
97 | unsigned int distance, | ||
98 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
99 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
100 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
101 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
102 | const char *emsg) | ||
103 | { | ||
104 | cc = NULL; | ||
105 | GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
106 | } | ||
107 | |||
108 | |||
109 | static void | ||
110 | my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, | ||
111 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
112 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
113 | { | ||
114 | GNUNET_assert (id != NULL); | ||
115 | #if VERBOSE | ||
116 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", | ||
117 | GNUNET_i2s (id)); | ||
118 | #endif | ||
119 | cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, | ||
120 | GNUNET_YES, &my_connect_complete, NULL); | ||
121 | } | ||
122 | |||
123 | |||
124 | static void | ||
125 | my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, | ||
126 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
127 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
128 | { | ||
129 | GNUNET_assert (id != NULL); | ||
130 | #if VERBOSE | ||
131 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", | ||
132 | GNUNET_i2s (id)); | ||
133 | #endif | ||
134 | d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, | ||
135 | NULL, NULL, &my_cb2, NULL); | ||
136 | GNUNET_assert (d2 != NULL); | ||
137 | |||
138 | } | ||
139 | |||
140 | |||
141 | static void | ||
142 | run (void *cls, char *const *args, const char *cfgfile, | ||
143 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
144 | { | ||
145 | ok = 1; | ||
146 | #if VERBOSE | ||
147 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); | ||
148 | #endif | ||
149 | c1 = GNUNET_CONFIGURATION_create (); | ||
150 | GNUNET_assert (GNUNET_OK == | ||
151 | GNUNET_CONFIGURATION_load (c1, | ||
152 | "test_testing_connect_peer1.conf")); | ||
153 | c2 = GNUNET_CONFIGURATION_create (); | ||
154 | GNUNET_assert (GNUNET_OK == | ||
155 | GNUNET_CONFIGURATION_load (c2, | ||
156 | "test_testing_connect_peer2.conf")); | ||
157 | d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, | ||
158 | NULL, NULL, &my_cb1, NULL); | ||
159 | GNUNET_assert (d1 != NULL); | ||
160 | } | ||
161 | |||
162 | static int | ||
163 | check () | ||
164 | { | ||
165 | char *const argv[] = { "test-testing", | ||
166 | "-c", | ||
167 | "test_testing_data.conf", | ||
168 | #if VERBOSE | ||
169 | "-L", "DEBUG", | ||
170 | #endif | ||
171 | NULL | ||
172 | }; | ||
173 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
174 | GNUNET_GETOPT_OPTION_END | ||
175 | }; | ||
176 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
177 | "test-testing-connect", "nohelp", options, &run, &ok); | ||
178 | return ok; | ||
179 | } | ||
180 | |||
181 | int | ||
182 | main (int argc, char *argv[]) | ||
183 | { | ||
184 | int ret; | ||
185 | |||
186 | GNUNET_log_setup ("test-testing-connect", | ||
187 | #if VERBOSE | ||
188 | "DEBUG", | ||
189 | #else | ||
190 | "WARNING", | ||
191 | #endif | ||
192 | NULL); | ||
193 | ret = check (); | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | /* end of test_testing_connect.c */ | ||
diff --git a/src/testing/test_testing_connect_peer1.conf b/src/testing/test_testing_connect_peer1.conf deleted file mode 100644 index cccda5e2a..000000000 --- a/src/testing/test_testing_connect_peer1.conf +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | SERVICEHOME = /tmp/test-gnunet-testing-connect-peer1/ | ||
4 | DEFAULTCONFIG = test_testing_connect_peer1.conf | ||
5 | |||
6 | [transport-tcp] | ||
7 | PORT = 12568 | ||
8 | |||
9 | [arm] | ||
10 | PORT = 12566 | ||
11 | DEFAULTSERVICES = core | ||
12 | UNIXPATH = /tmp/gnunet-p1-service-arm.sock | ||
13 | |||
14 | [statistics] | ||
15 | PORT = 12567 | ||
16 | UNIXPATH = /tmp/gnunet-p1-service-statistics.sock | ||
17 | |||
18 | [resolver] | ||
19 | PORT = 12564 | ||
20 | UNIXPATH = /tmp/gnunet-p1-service-resolver.sock | ||
21 | |||
22 | [peerinfo] | ||
23 | PORT = 12569 | ||
24 | UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock | ||
25 | |||
26 | [transport] | ||
27 | PORT = 12565 | ||
28 | UNIXPATH = /tmp/gnunet-p1-service-transport.sock | ||
29 | |||
30 | [core] | ||
31 | PORT = 12570 | ||
32 | UNIXPATH = /tmp/gnunet-p1-service-core.sock | ||
33 | |||
34 | [ats] | ||
35 | PORT = 12571 | ||
36 | UNIXPATH = /tmp/gnunet-p1-service-ats.sock | ||
37 | |||
diff --git a/src/testing/test_testing_connect_peer2.conf b/src/testing/test_testing_connect_peer2.conf deleted file mode 100644 index 08ec55113..000000000 --- a/src/testing/test_testing_connect_peer2.conf +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | SERVICEHOME = /tmp/test-gnunet-testing-connect-peer2/ | ||
4 | DEFAULTCONFIG = test_testing_connect_peer2.conf | ||
5 | |||
6 | [transport-tcp] | ||
7 | PORT = 22568 | ||
8 | |||
9 | [arm] | ||
10 | PORT = 22566 | ||
11 | DEFAULTSERVICES = core | ||
12 | UNIXPATH = /tmp/gnunet-p2-service-arm.sock | ||
13 | |||
14 | [statistics] | ||
15 | PORT = 22567 | ||
16 | UNIXPATH = /tmp/gnunet-p2-service-statistics.sock | ||
17 | |||
18 | [resolver] | ||
19 | PORT = 22564 | ||
20 | UNIXPATH = /tmp/gnunet-p2-service-resolver.sock | ||
21 | |||
22 | [peerinfo] | ||
23 | PORT = 22569 | ||
24 | UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock | ||
25 | |||
26 | [transport] | ||
27 | PORT = 22565 | ||
28 | UNIXPATH = /tmp/gnunet-p2-service-transport.sock | ||
29 | |||
30 | [core] | ||
31 | PORT = 22570 | ||
32 | UNIXPATH = /tmp/gnunet-p2-service-core.sock | ||
33 | |||
34 | [ats] | ||
35 | PORT = 22571 | ||
36 | UNIXPATH = /tmp/gnunet-p2-service-ats.sock | ||
37 | |||
diff --git a/src/testing/test_testing_data.conf b/src/testing/test_testing_data.conf deleted file mode 100644 index c46cb0d42..000000000 --- a/src/testing/test_testing_data.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data.conf | ||
4 | |||
5 | [arm] | ||
6 | DEFAULTSERVICES = core | ||
7 | |||
diff --git a/src/testing/test_testing_data_remote.conf b/src/testing/test_testing_data_remote.conf deleted file mode 100644 index d58666f31..000000000 --- a/src/testing/test_testing_data_remote.conf +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_remote.conf | ||
4 | |||
5 | [TESTING] | ||
6 | CONTROL_HOST = 127.0.0.1 | ||
7 | HOSTFILE = remote_hosts.txt | ||
8 | MAX_OUTSTANDING_SSH = 5 | ||
9 | |||
10 | [statistics] | ||
11 | AUTOSTART = NO | ||
12 | |||
diff --git a/src/testing/test_testing_data_topology_2d_torus.conf b/src/testing/test_testing_data_topology_2d_torus.conf deleted file mode 100644 index cbdaceb5a..000000000 --- a/src/testing/test_testing_data_topology_2d_torus.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_2d_torus.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 13 | ||
7 | TOPOLOGY = 2D_TORUS | ||
diff --git a/src/testing/test_testing_data_topology_blacklist.conf b/src/testing/test_testing_data_topology_blacklist.conf deleted file mode 100644 index 36e378d42..000000000 --- a/src/testing/test_testing_data_topology_blacklist.conf +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_blacklist.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 4 | ||
7 | TOPOLOGY = CLIQUE | ||
8 | BLACKLIST_TOPOLOGY = RING | ||
9 | BLACKLIST_TRANSPORTS = tcp udp http | ||
10 | |||
11 | [transport-udp] | ||
12 | PORT = 2568 | ||
13 | |||
diff --git a/src/testing/test_testing_data_topology_churn.conf b/src/testing/test_testing_data_topology_churn.conf deleted file mode 100644 index b3371658d..000000000 --- a/src/testing/test_testing_data_topology_churn.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_churn.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 12 | ||
7 | |||
8 | [arm] | ||
9 | DEFAULTSERVICES = peerinfo transport core | ||
10 | |||
diff --git a/src/testing/test_testing_data_topology_clique.conf b/src/testing/test_testing_data_topology_clique.conf deleted file mode 100644 index 69cecb7e9..000000000 --- a/src/testing/test_testing_data_topology_clique.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | CONNECT_TIMEOUT = 180 s | ||
7 | CONNECT_ATTEMPTS = 14 | ||
8 | NUM_PEERS = 4 | ||
9 | TOPOLOGY = CLIQUE | ||
10 | SETTLE_TIME = 0 | ||
diff --git a/src/testing/test_testing_data_topology_clique_dfs.conf b/src/testing/test_testing_data_topology_clique_dfs.conf deleted file mode 100644 index c7abeae5e..000000000 --- a/src/testing/test_testing_data_topology_clique_dfs.conf +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 7 | ||
7 | TOPOLOGY = CLIQUE | ||
8 | CONNECT_TOPOLOGY_OPTION = CONNECT_DFS | ||
9 | CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 | ||
10 | |||
11 | [arm] | ||
12 | DEFAULTSERVICES = peerinfo transport core | ||
13 | |||
diff --git a/src/testing/test_testing_data_topology_clique_minimum.conf b/src/testing/test_testing_data_topology_clique_minimum.conf deleted file mode 100644 index ef95cb1fd..000000000 --- a/src/testing/test_testing_data_topology_clique_minimum.conf +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 20 | ||
7 | TOPOLOGY = CLIQUE | ||
8 | CONNECT_TOPOLOGY_OPTION = CONNECT_MINIMUM | ||
9 | CONNECT_TOPOLOGY_OPTION_MODIFIER = 2.0 | ||
10 | |||
diff --git a/src/testing/test_testing_data_topology_clique_random.conf b/src/testing/test_testing_data_topology_clique_random.conf deleted file mode 100644 index cd44b65f0..000000000 --- a/src/testing/test_testing_data_topology_clique_random.conf +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 20 | ||
7 | TOPOLOGY = CLIQUE | ||
8 | CONNECT_TOPOLOGY_OPTION = CONNECT_RANDOM_SUBSET | ||
9 | CONNECT_TOPOLOGY_OPTION_MODIFIER = .15 | ||
10 | |||
11 | [statistics] | ||
12 | AUTOSTART = NO | ||
13 | |||
14 | [resolver] | ||
15 | AUTOSTART = NO | ||
16 | |||
diff --git a/src/testing/test_testing_data_topology_erdos_renyi.conf b/src/testing/test_testing_data_topology_erdos_renyi.conf deleted file mode 100644 index 8e1741352..000000000 --- a/src/testing/test_testing_data_topology_erdos_renyi.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | TOPOLOGY = ERDOS_RENYI | ||
7 | |||
diff --git a/src/testing/test_testing_data_topology_internat.conf b/src/testing/test_testing_data_topology_internat.conf deleted file mode 100644 index af3f62f39..000000000 --- a/src/testing/test_testing_data_topology_internat.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | TOPOLOGY = INTERNAT | ||
7 | |||
diff --git a/src/testing/test_testing_data_topology_none.conf b/src/testing/test_testing_data_topology_none.conf deleted file mode 100644 index dbee5d0b9..000000000 --- a/src/testing/test_testing_data_topology_none.conf +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 1000 | ||
7 | TOPOLOGY = NONE | ||
8 | F2F = NO | ||
9 | BLACKLIST_TOPOLOGY = NONE | ||
10 | CONNECT_TOPOLOGY = RING | ||
11 | |||
12 | [arm] | ||
13 | PORT = 0 | ||
14 | |||
15 | [statistics] | ||
16 | AUTOSTART = NO | ||
17 | PORT = 0 | ||
18 | |||
19 | [resolver] | ||
20 | AUTOSTART = NO | ||
21 | PORT = 0 | ||
22 | |||
23 | [peerinfo] | ||
24 | PORT = 0 | ||
25 | |||
26 | [transport] | ||
27 | PORT = 0 | ||
28 | |||
29 | [core] | ||
30 | PORT = 0 | ||
31 | |||
32 | [topology] | ||
33 | PORT = 0 | ||
34 | |||
35 | [hostlist] | ||
36 | PORT = 0 | ||
37 | |||
diff --git a/src/testing/test_testing_data_topology_ring.conf b/src/testing/test_testing_data_topology_ring.conf deleted file mode 100644 index 6159030f4..000000000 --- a/src/testing/test_testing_data_topology_ring.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | TOPOLOGY = RING | ||
7 | |||
diff --git a/src/testing/test_testing_data_topology_scale_free.conf b/src/testing/test_testing_data_topology_scale_free.conf deleted file mode 100644 index 7690eac29..000000000 --- a/src/testing/test_testing_data_topology_scale_free.conf +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_scale_free.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 50 | ||
7 | TOPOLOGY = SCALE_FREE | ||
8 | |||
9 | [arm] | ||
10 | DEFAULTSERVICES = peerinfo transport core | ||
11 | |||
diff --git a/src/testing/test_testing_data_topology_small_world_ring.conf b/src/testing/test_testing_data_topology_small_world_ring.conf deleted file mode 100644 index 01931df6d..000000000 --- a/src/testing/test_testing_data_topology_small_world_ring.conf +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | NUM_PEERS = 25 | ||
7 | TOPOLOGY = SMALL_WORLD_RING | ||
8 | |||
diff --git a/src/testing/test_testing_data_topology_small_world_torus.conf b/src/testing/test_testing_data_topology_small_world_torus.conf deleted file mode 100644 index 7c35454de..000000000 --- a/src/testing/test_testing_data_topology_small_world_torus.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | TOPOLOGY = SMALL_WORLD | ||
7 | |||
diff --git a/src/testing/test_testing_data_topology_stability.conf b/src/testing/test_testing_data_topology_stability.conf deleted file mode 100644 index 1bfcd1bde..000000000 --- a/src/testing/test_testing_data_topology_stability.conf +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_data_topology_clique.conf | ||
4 | |||
5 | [TESTING] | ||
6 | SETTLE_TIME = 600 s | ||
7 | NUM_PEERS = 2 | ||
8 | TOPOLOGY = CLIQUE | ||
9 | |||
diff --git a/src/testing/test_testing_defaults.conf b/src/testing/test_testing_defaults.conf deleted file mode 100644 index ba7e269a6..000000000 --- a/src/testing/test_testing_defaults.conf +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | [PATHS] | ||
2 | SERVICEHOME = /tmp/test-gnunet-testing/ | ||
3 | DEFAULTCONFIG = test_testing_defaults.conf | ||
4 | |||
5 | [resolver] | ||
6 | PORT = 2564 | ||
7 | |||
8 | [transport] | ||
9 | PORT = 2565 | ||
10 | PLUGINS = tcp | ||
11 | |||
12 | [arm] | ||
13 | PORT = 2566 | ||
14 | DEFAULTSERVICES = | ||
15 | |||
16 | [statistics] | ||
17 | PORT = 2567 | ||
18 | |||
19 | [transport-tcp] | ||
20 | PORT = 2568 | ||
21 | BINDTO = 127.0.0.1 | ||
22 | |||
23 | [peerinfo] | ||
24 | PORT = 2569 | ||
25 | |||
26 | [core] | ||
27 | PORT = 2570 | ||
28 | |||
29 | [testing] | ||
30 | NUM_PEERS = 5 | ||
31 | WEAKRANDOM = YES | ||
32 | F2F = YES | ||
33 | HOSTKEYSFILE = ../../contrib/testing_hostkeys.dat | ||
34 | |||
35 | [dht] | ||
36 | AUTOSTART = NO | ||
37 | |||
38 | [nat] | ||
39 | DISABLEV6 = YES | ||
40 | ENABLE_UPNP = NO | ||
41 | BEHIND_NAT = NO | ||
42 | ALLOW_NAT = NO | ||
43 | INTERNAL_ADDRESS = 127.0.0.1 | ||
44 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
45 | USE_LOCALADDR = NO | ||
46 | |||
47 | [dns] | ||
48 | AUTOSTART = NO | ||
49 | |||
50 | [nse] | ||
51 | AUTOSTART = NO | ||
52 | |||
53 | [mesh] | ||
54 | AUTOSTART = NO | ||
55 | |||
56 | [datastore] | ||
57 | AUTOSTART = NO | ||
58 | |||
59 | [fs] | ||
60 | AUTOSTART = NO | ||
61 | |||
62 | [dv] | ||
63 | AUTOSTART = NO | ||
64 | |||
65 | [chat] | ||
66 | AUTOSTART = NO | ||
67 | |||
68 | [vpn] | ||
69 | AUTOSTART = NO | ||
70 | |||
71 | [gns] | ||
72 | AUTOSTART = NO | ||
73 | |||
74 | [namestore] | ||
75 | AUTOSTART = NO | ||
76 | |||
77 | [lockmanager] | ||
78 | AUTOSTART = NO | ||
diff --git a/src/testing/test_testing_group.c b/src/testing/test_testing_group.c deleted file mode 100644 index f5df45b19..000000000 --- a/src/testing/test_testing_group.c +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_group.c | ||
22 | * @brief testcase for functions to connect peers in testing.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | |||
27 | #define VERBOSE GNUNET_NO | ||
28 | |||
29 | #define NUM_PEERS 4 | ||
30 | |||
31 | /** | ||
32 | * How long until we give up on connecting the peers? | ||
33 | */ | ||
34 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
35 | |||
36 | static int ok; | ||
37 | |||
38 | static int peers_left; | ||
39 | |||
40 | static int failed_peers; | ||
41 | |||
42 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
43 | |||
44 | /** | ||
45 | * Check whether peers successfully shut down. | ||
46 | */ | ||
47 | void | ||
48 | shutdown_callback (void *cls, const char *emsg) | ||
49 | { | ||
50 | if (emsg != NULL) | ||
51 | { | ||
52 | #if VERBOSE | ||
53 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); | ||
54 | #endif | ||
55 | if (ok == 0) | ||
56 | ok = 666; | ||
57 | } | ||
58 | else | ||
59 | { | ||
60 | #if VERBOSE | ||
61 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); | ||
62 | #endif | ||
63 | } | ||
64 | } | ||
65 | |||
66 | |||
67 | static void | ||
68 | my_cb (void *cls, const struct GNUNET_PeerIdentity *id, | ||
69 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
70 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
71 | { | ||
72 | if (id == NULL) | ||
73 | { | ||
74 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
75 | "Start callback called with error (too long starting peers), aborting test!\n"); | ||
76 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); | ||
77 | failed_peers++; | ||
78 | if (failed_peers == peers_left) | ||
79 | { | ||
80 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
81 | "Too many peers failed, ending test!\n"); | ||
82 | ok = 1; | ||
83 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
84 | } | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | peers_left--; | ||
89 | if (peers_left == 0) | ||
90 | { | ||
91 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
92 | "All peers started successfully, ending test!\n"); | ||
93 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
94 | ok = 0; | ||
95 | } | ||
96 | else if (failed_peers == peers_left) | ||
97 | { | ||
98 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
99 | "Too many peers failed, ending test!\n"); | ||
100 | ok = 1; | ||
101 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | static void | ||
107 | run (void *cls, char *const *args, const char *cfgfile, | ||
108 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
109 | { | ||
110 | ok = 1; | ||
111 | #if VERBOSE | ||
112 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); | ||
113 | #endif | ||
114 | peers_left = NUM_PEERS; | ||
115 | pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ | ||
116 | peers_left, /* Number of outstanding connections */ | ||
117 | peers_left, /* Number of parallel ssh connections, or peers being started at once */ | ||
118 | TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, | ||
119 | NULL, NULL); | ||
120 | GNUNET_assert (pg != NULL); | ||
121 | } | ||
122 | |||
123 | static int | ||
124 | check () | ||
125 | { | ||
126 | char *const argv[] = { "test-testing", | ||
127 | "-c", | ||
128 | "test_testing_data.conf", | ||
129 | #if VERBOSE | ||
130 | "-L", "DEBUG", | ||
131 | #endif | ||
132 | NULL | ||
133 | }; | ||
134 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
135 | GNUNET_GETOPT_OPTION_END | ||
136 | }; | ||
137 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
138 | "test-testing-group", "nohelp", options, &run, &ok); | ||
139 | return ok; | ||
140 | } | ||
141 | |||
142 | int | ||
143 | main (int argc, char *argv[]) | ||
144 | { | ||
145 | int ret; | ||
146 | |||
147 | GNUNET_log_setup ("test-testing-group", | ||
148 | #if VERBOSE | ||
149 | "DEBUG", | ||
150 | #else | ||
151 | "WARNING", | ||
152 | #endif | ||
153 | NULL); | ||
154 | ret = check (); | ||
155 | /** | ||
156 | * Still need to remove the base testing directory here, | ||
157 | * because group starts will create subdirectories under this | ||
158 | * main dir. However, we no longer need to sleep, as the | ||
159 | * shutdown sequence won't return until everything is cleaned | ||
160 | * up. | ||
161 | */ | ||
162 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | /* end of test_testing_group.c */ | ||
diff --git a/src/testing/test_testing_group_remote.c b/src/testing/test_testing_group_remote.c deleted file mode 100644 index b06655ca4..000000000 --- a/src/testing/test_testing_group_remote.c +++ /dev/null | |||
@@ -1,263 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_group_remote.c | ||
22 | * @brief testcase for testing remote and local starting and connecting | ||
23 | * of hosts from the testing library. The test_testing_data_remote.conf | ||
24 | * file should be modified if this testcase is intended to be used. | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_testing_lib.h" | ||
28 | |||
29 | #define VERBOSE GNUNET_YES | ||
30 | |||
31 | |||
32 | /** | ||
33 | * How long until we give up on connecting the peers? | ||
34 | */ | ||
35 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
36 | |||
37 | #define DEFAULT_NUM_PEERS 8; | ||
38 | |||
39 | static int ok; | ||
40 | |||
41 | static int peers_left; | ||
42 | |||
43 | static int peers_failed; | ||
44 | |||
45 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
46 | |||
47 | static unsigned long long num_peers; | ||
48 | |||
49 | |||
50 | /** | ||
51 | * Check whether peers successfully shut down. | ||
52 | */ | ||
53 | void | ||
54 | shutdown_callback (void *cls, const char *emsg) | ||
55 | { | ||
56 | if (emsg != NULL) | ||
57 | { | ||
58 | #if VERBOSE | ||
59 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
60 | "Shutdown of peers failed (error %s)!\n", emsg); | ||
61 | #endif | ||
62 | if (ok == 0) | ||
63 | ok = 666; | ||
64 | } | ||
65 | else | ||
66 | { | ||
67 | #if VERBOSE | ||
68 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); | ||
69 | #endif | ||
70 | } | ||
71 | } | ||
72 | |||
73 | |||
74 | static void | ||
75 | my_cb (void *cls, const struct GNUNET_PeerIdentity *id, | ||
76 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
77 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
78 | { | ||
79 | if (emsg != NULL) | ||
80 | { | ||
81 | peers_failed++; | ||
82 | } | ||
83 | |||
84 | peers_left--; | ||
85 | if (peers_left == 0) | ||
86 | { | ||
87 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
88 | ok = 0; | ||
89 | } | ||
90 | else if (peers_failed == peers_left) | ||
91 | { | ||
92 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
93 | "Too many peers failed, ending test!\n"); | ||
94 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | |||
99 | static void | ||
100 | run (void *cls, char *const *args, const char *cfgfile, | ||
101 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
102 | { | ||
103 | struct GNUNET_TESTING_Host *hosts; | ||
104 | struct GNUNET_TESTING_Host *hostpos; | ||
105 | struct GNUNET_TESTING_Host *temphost; | ||
106 | char *hostfile; | ||
107 | struct stat frstat; | ||
108 | char *buf; | ||
109 | char *data; | ||
110 | int count; | ||
111 | int ret; | ||
112 | |||
113 | ok = 1; | ||
114 | #if VERBOSE | ||
115 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); | ||
116 | #endif | ||
117 | |||
118 | if (GNUNET_SYSERR == | ||
119 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", | ||
120 | &num_peers)) | ||
121 | num_peers = DEFAULT_NUM_PEERS; | ||
122 | |||
123 | GNUNET_assert (num_peers > 0 && num_peers < (unsigned long long) -1); | ||
124 | if (GNUNET_OK != | ||
125 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", | ||
126 | &hostfile)) | ||
127 | hostfile = NULL; | ||
128 | |||
129 | hosts = NULL; | ||
130 | data = NULL; | ||
131 | if (hostfile != NULL) | ||
132 | { | ||
133 | if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) | ||
134 | GNUNET_DISK_fn_write (hostfile, NULL, 0, | ||
135 | GNUNET_DISK_PERM_USER_READ | | ||
136 | GNUNET_DISK_PERM_USER_WRITE); | ||
137 | if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) | ||
138 | { | ||
139 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
140 | "Could not open file specified for host list, ending test!"); | ||
141 | ok = 1119; | ||
142 | GNUNET_free (hostfile); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | data = GNUNET_malloc_large (frstat.st_size); | ||
147 | GNUNET_assert (data != NULL); | ||
148 | if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) | ||
149 | { | ||
150 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
151 | "Could not read file %s specified for host list, ending test!", | ||
152 | hostfile); | ||
153 | GNUNET_free (hostfile); | ||
154 | GNUNET_free (data); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | GNUNET_free_non_null (hostfile); | ||
159 | |||
160 | buf = data; | ||
161 | count = 0; | ||
162 | while (count < frstat.st_size) | ||
163 | { | ||
164 | count++; | ||
165 | if (count >= frstat.st_size) | ||
166 | break; | ||
167 | |||
168 | /* if (((data[count] == '\n') || (data[count] == '\0')) && (buf != &data[count])) */ | ||
169 | if (((data[count] == '\n')) && (buf != &data[count])) | ||
170 | { | ||
171 | data[count] = '\0'; | ||
172 | temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); | ||
173 | ret = | ||
174 | SSCANF (buf, "%a[a-zA-Z0-9]@%a[a-zA-Z0-9.]:%hd", | ||
175 | &temphost->username, &temphost->hostname, &temphost->port); | ||
176 | if (3 == ret) | ||
177 | { | ||
178 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
179 | "Successfully read host %s, port %d and user %s from file\n", | ||
180 | temphost->hostname, temphost->port, temphost->username); | ||
181 | } | ||
182 | else | ||
183 | { | ||
184 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
185 | "Error reading line `%s' in hostfile\n", buf); | ||
186 | GNUNET_free (temphost); | ||
187 | buf = &data[count + 1]; | ||
188 | continue; | ||
189 | } | ||
190 | /* temphost->hostname = buf; */ | ||
191 | temphost->next = hosts; | ||
192 | hosts = temphost; | ||
193 | buf = &data[count + 1]; | ||
194 | } | ||
195 | else if ((data[count] == '\n') || (data[count] == '\0')) | ||
196 | buf = &data[count + 1]; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | peers_left = num_peers; | ||
201 | pg = GNUNET_TESTING_daemons_start (cfg, peers_left, /* Total number of peers */ | ||
202 | peers_left, /* Number of outstanding connections */ | ||
203 | peers_left, /* Number of parallel ssh connections, or peers being started at once */ | ||
204 | TIMEOUT, NULL, NULL, &my_cb, NULL, NULL, | ||
205 | NULL, hosts); | ||
206 | hostpos = hosts; | ||
207 | while (hostpos != NULL) | ||
208 | { | ||
209 | temphost = hostpos->next; | ||
210 | GNUNET_free (hostpos->hostname); | ||
211 | GNUNET_free (hostpos->username); | ||
212 | GNUNET_free (hostpos); | ||
213 | hostpos = temphost; | ||
214 | } | ||
215 | GNUNET_free_non_null (data); | ||
216 | GNUNET_assert (pg != NULL); | ||
217 | |||
218 | } | ||
219 | |||
220 | static int | ||
221 | check () | ||
222 | { | ||
223 | char *const argv[] = { "test-testing", | ||
224 | "-c", | ||
225 | "test_testing_data_remote.conf", | ||
226 | #if VERBOSE | ||
227 | "-L", "DEBUG", | ||
228 | #endif | ||
229 | NULL | ||
230 | }; | ||
231 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
232 | GNUNET_GETOPT_OPTION_END | ||
233 | }; | ||
234 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
235 | "test-testing-group", "nohelp", options, &run, &ok); | ||
236 | return ok; | ||
237 | } | ||
238 | |||
239 | int | ||
240 | main (int argc, char *argv[]) | ||
241 | { | ||
242 | int ret; | ||
243 | |||
244 | GNUNET_log_setup ("test-testing-group", | ||
245 | #if VERBOSE | ||
246 | "DEBUG", | ||
247 | #else | ||
248 | "WARNING", | ||
249 | #endif | ||
250 | NULL); | ||
251 | ret = check (); | ||
252 | /** | ||
253 | * Still need to remove the base testing directory here, | ||
254 | * because group starts will create subdirectories under this | ||
255 | * main dir. However, we no longer need to sleep, as the | ||
256 | * shutdown sequence won't return until everything is cleaned | ||
257 | * up. | ||
258 | */ | ||
259 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); | ||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | /* end of test_testing_group.c */ | ||
diff --git a/src/testing/test_testing_large_topology.c b/src/testing/test_testing_large_topology.c deleted file mode 100644 index cd80db195..000000000 --- a/src/testing/test_testing_large_topology.c +++ /dev/null | |||
@@ -1,1197 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_topology.c | ||
22 | * @brief base testcase for testing all the topologies provided | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | #include "gnunet_core_service.h" | ||
27 | #include "gnunet_os_lib.h" | ||
28 | |||
29 | #define VERBOSE GNUNET_YES | ||
30 | |||
31 | #define DELAY_FOR_LOGGING GNUNET_NO | ||
32 | |||
33 | #define SECONDS_PER_PEER_START 120 | ||
34 | |||
35 | #define DEFAULT_NUM_PEERS 4 | ||
36 | |||
37 | #define MAX_OUTSTANDING_CONNECTIONS 100 | ||
38 | |||
39 | static float fail_percentage = 0.05; | ||
40 | |||
41 | static int ok; | ||
42 | |||
43 | struct GNUNET_TIME_Relative connect_timeout; | ||
44 | |||
45 | static unsigned long long connect_attempts; | ||
46 | |||
47 | static unsigned long long num_peers; | ||
48 | |||
49 | static unsigned int topology_connections; | ||
50 | |||
51 | static unsigned int total_connections; | ||
52 | |||
53 | static unsigned int failed_connections; | ||
54 | |||
55 | static unsigned int total_server_connections; | ||
56 | |||
57 | static unsigned int total_messages_received; | ||
58 | |||
59 | static unsigned int expected_messages; | ||
60 | |||
61 | static unsigned int expected_connections; | ||
62 | |||
63 | static unsigned long long peers_left; | ||
64 | |||
65 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
66 | |||
67 | const struct GNUNET_CONFIGURATION_Handle *main_cfg; | ||
68 | |||
69 | GNUNET_SCHEDULER_TaskIdentifier die_task; | ||
70 | |||
71 | static char *dotOutFileName; | ||
72 | |||
73 | static struct GNUNET_TIME_Relative settle_time; | ||
74 | |||
75 | static FILE *dotOutFile; | ||
76 | |||
77 | static char *topology_string; | ||
78 | |||
79 | static char *blacklist_transports; | ||
80 | |||
81 | static int transmit_ready_scheduled; | ||
82 | |||
83 | static int transmit_ready_failed; | ||
84 | |||
85 | static int transmit_ready_called; | ||
86 | |||
87 | struct GNUNET_TIME_Relative test_timeout; | ||
88 | |||
89 | struct GNUNET_TIME_Relative timeout; | ||
90 | |||
91 | static unsigned int modnum; | ||
92 | |||
93 | static unsigned int dotnum; | ||
94 | |||
95 | static enum GNUNET_TESTING_Topology topology; | ||
96 | |||
97 | static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ | ||
98 | |||
99 | static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ | ||
100 | |||
101 | static enum GNUNET_TESTING_TopologyOption connect_topology_option = | ||
102 | GNUNET_TESTING_TOPOLOGY_OPTION_ALL; | ||
103 | |||
104 | static double connect_topology_option_modifier = 0.0; | ||
105 | |||
106 | static char *test_directory; | ||
107 | |||
108 | #define MTYPE 12345 | ||
109 | |||
110 | GNUNET_NETWORK_STRUCT_BEGIN | ||
111 | |||
112 | struct GNUNET_TestMessage | ||
113 | { | ||
114 | /** | ||
115 | * Header of the message | ||
116 | */ | ||
117 | struct GNUNET_MessageHeader header; | ||
118 | |||
119 | /** | ||
120 | * Unique identifier for this message. | ||
121 | */ | ||
122 | uint32_t uid; | ||
123 | }; | ||
124 | GNUNET_NETWORK_STRUCT_END | ||
125 | |||
126 | struct TestMessageContext | ||
127 | { | ||
128 | /* This is a linked list */ | ||
129 | struct TestMessageContext *next; | ||
130 | |||
131 | /* Handle to the sending peer core */ | ||
132 | struct GNUNET_CORE_Handle *peer1handle; | ||
133 | |||
134 | /* Handle to the receiving peer core */ | ||
135 | struct GNUNET_CORE_Handle *peer2handle; | ||
136 | |||
137 | /* Handle to the sending peer daemon */ | ||
138 | struct GNUNET_TESTING_Daemon *peer1; | ||
139 | |||
140 | /* Handle to the receiving peer daemon */ | ||
141 | struct GNUNET_TESTING_Daemon *peer2; | ||
142 | |||
143 | /* Identifier for this message, so we don't disconnect other peers! */ | ||
144 | uint32_t uid; | ||
145 | |||
146 | /* Has peer1 been notified already of a connection to peer2? */ | ||
147 | int peer1notified; | ||
148 | |||
149 | /* Has the core of peer2 been connected already? */ | ||
150 | int peer2connected; | ||
151 | |||
152 | /* Task for disconnecting cores, allow task to be cancelled on shutdown */ | ||
153 | GNUNET_SCHEDULER_TaskIdentifier disconnect_task; | ||
154 | |||
155 | }; | ||
156 | |||
157 | static struct TestMessageContext *test_messages; | ||
158 | |||
159 | /** | ||
160 | * Check whether peers successfully shut down. | ||
161 | */ | ||
162 | void | ||
163 | shutdown_callback (void *cls, const char *emsg) | ||
164 | { | ||
165 | if (emsg != NULL) | ||
166 | { | ||
167 | #if VERBOSE | ||
168 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); | ||
169 | #endif | ||
170 | if (ok == 0) | ||
171 | ok = 666; | ||
172 | } | ||
173 | else | ||
174 | { | ||
175 | #if VERBOSE | ||
176 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); | ||
177 | #endif | ||
178 | } | ||
179 | } | ||
180 | |||
181 | #if DELAY_FOR_LOGGING | ||
182 | static void | ||
183 | gather_log_data () | ||
184 | { | ||
185 | char *peer_number; | ||
186 | char *connect_number; | ||
187 | struct GNUNET_OS_Process *mem_process; | ||
188 | |||
189 | GNUNET_asprintf (&peer_number, "%llu", num_peers); | ||
190 | GNUNET_asprintf (&connect_number, "%llu", expected_connections); | ||
191 | mem_process = | ||
192 | GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", | ||
193 | "totals.txt", peer_number, connect_number, NULL); | ||
194 | GNUNET_OS_process_wait (mem_process); | ||
195 | GNUNET_OS_process_destroy (mem_process); | ||
196 | mem_process = NULL; | ||
197 | } | ||
198 | |||
199 | #endif | ||
200 | |||
201 | static void | ||
202 | finish_testing () | ||
203 | { | ||
204 | GNUNET_assert (pg != NULL); | ||
205 | struct TestMessageContext *pos; | ||
206 | struct TestMessageContext *free_pos; | ||
207 | |||
208 | #if VERBOSE | ||
209 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
210 | "Called finish testing, stopping daemons.\n"); | ||
211 | #endif | ||
212 | |||
213 | pos = test_messages; | ||
214 | while (pos != NULL) | ||
215 | { | ||
216 | if (pos->peer1handle != NULL) | ||
217 | { | ||
218 | GNUNET_CORE_disconnect (pos->peer1handle); | ||
219 | pos->peer1handle = NULL; | ||
220 | } | ||
221 | if (pos->peer2handle != NULL) | ||
222 | { | ||
223 | GNUNET_CORE_disconnect (pos->peer2handle); | ||
224 | pos->peer2handle = NULL; | ||
225 | } | ||
226 | free_pos = pos; | ||
227 | pos = pos->next; | ||
228 | if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
229 | { | ||
230 | GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); | ||
231 | } | ||
232 | GNUNET_free (free_pos); | ||
233 | } | ||
234 | #if VERBOSE | ||
235 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
236 | "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", | ||
237 | transmit_ready_scheduled, transmit_ready_failed, | ||
238 | transmit_ready_called); | ||
239 | #endif | ||
240 | |||
241 | #if VERBOSE | ||
242 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); | ||
243 | #endif | ||
244 | GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL); | ||
245 | |||
246 | if (dotOutFile != NULL) | ||
247 | { | ||
248 | FPRINTF (dotOutFile, "%s", "}"); | ||
249 | FCLOSE (dotOutFile); | ||
250 | } | ||
251 | |||
252 | ok = 0; | ||
253 | } | ||
254 | |||
255 | |||
256 | static void | ||
257 | disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
258 | { | ||
259 | struct TestMessageContext *pos = cls; | ||
260 | |||
261 | /* Disconnect from the respective cores */ | ||
262 | #if VERBOSE > 1 | ||
263 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", | ||
264 | GNUNET_i2s (&pos->peer1->id)); | ||
265 | #endif | ||
266 | if (pos->peer1handle != NULL) | ||
267 | GNUNET_CORE_disconnect (pos->peer1handle); | ||
268 | #if VERBOSE > 1 | ||
269 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", | ||
270 | GNUNET_i2s (&pos->peer2->id)); | ||
271 | #endif | ||
272 | if (pos->peer2handle != NULL) | ||
273 | GNUNET_CORE_disconnect (pos->peer2handle); | ||
274 | /* Set handles to NULL so test case can be ended properly */ | ||
275 | pos->peer1handle = NULL; | ||
276 | pos->peer2handle = NULL; | ||
277 | pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
278 | /* Decrement total connections so new can be established */ | ||
279 | total_server_connections -= 2; | ||
280 | } | ||
281 | |||
282 | |||
283 | static void | ||
284 | topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, | ||
285 | const struct GNUNET_PeerIdentity *second, const char *emsg) | ||
286 | { | ||
287 | FILE *outfile = cls; | ||
288 | |||
289 | if (first != NULL) | ||
290 | { | ||
291 | if (outfile != NULL) | ||
292 | { | ||
293 | FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); | ||
294 | FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); | ||
295 | } | ||
296 | topology_connections++; | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | FPRINTF (stderr, | ||
301 | "Finished iterating over topology, %d total connections!\n", | ||
302 | topology_connections); | ||
303 | if (outfile != NULL) | ||
304 | { | ||
305 | FPRINTF (outfile, "%s", "}\n"); | ||
306 | FCLOSE (outfile); | ||
307 | GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | static int | ||
313 | process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
314 | const struct GNUNET_MessageHeader *message, | ||
315 | const struct GNUNET_ATS_Information *atsi) | ||
316 | { | ||
317 | char *dotOutFileNameFinished; | ||
318 | FILE *dotOutFileFinished; | ||
319 | struct TestMessageContext *pos = cls; | ||
320 | struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; | ||
321 | |||
322 | if (pos->uid != ntohl (msg->uid)) | ||
323 | return GNUNET_OK; | ||
324 | |||
325 | #if VERBOSE | ||
326 | if ((total_messages_received) % modnum == 0) | ||
327 | { | ||
328 | if (total_messages_received == 0) | ||
329 | FPRINTF (stdout, "%s", "0%%"); | ||
330 | else | ||
331 | FPRINTF (stdout, "%d%%", | ||
332 | (int) (((float) total_messages_received / expected_messages) * | ||
333 | 100)); | ||
334 | |||
335 | } | ||
336 | else if (total_messages_received % dotnum == 0) | ||
337 | { | ||
338 | FPRINTF (stdout, "%s", "."); | ||
339 | } | ||
340 | fflush (stdout); | ||
341 | #endif | ||
342 | |||
343 | total_messages_received++; | ||
344 | |||
345 | #if VERBOSE > 1 | ||
346 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
347 | "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), | ||
348 | ntohs (message->type)); | ||
349 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
350 | "Total messages received %d, expected %d.\n", | ||
351 | total_messages_received, expected_messages); | ||
352 | #endif | ||
353 | |||
354 | if (total_messages_received == expected_messages) | ||
355 | { | ||
356 | #if VERBOSE | ||
357 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
358 | #endif | ||
359 | GNUNET_SCHEDULER_cancel (die_task); | ||
360 | GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); | ||
361 | dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); | ||
362 | GNUNET_free (dotOutFileNameFinished); | ||
363 | if (dotOutFileFinished != NULL) | ||
364 | { | ||
365 | FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); | ||
366 | } | ||
367 | topology_connections = 0; | ||
368 | GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); | ||
369 | //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); | ||
374 | } | ||
375 | |||
376 | return GNUNET_OK; | ||
377 | } | ||
378 | |||
379 | static void | ||
380 | end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
381 | { | ||
382 | char *msg = cls; | ||
383 | |||
384 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
385 | "End badly was called (%s)... stopping daemons.\n", msg); | ||
386 | struct TestMessageContext *pos; | ||
387 | struct TestMessageContext *free_pos; | ||
388 | |||
389 | pos = test_messages; | ||
390 | while (pos != NULL) | ||
391 | { | ||
392 | if (pos->peer1handle != NULL) | ||
393 | { | ||
394 | GNUNET_CORE_disconnect (pos->peer1handle); | ||
395 | pos->peer1handle = NULL; | ||
396 | } | ||
397 | if (pos->peer2handle != NULL) | ||
398 | { | ||
399 | GNUNET_CORE_disconnect (pos->peer2handle); | ||
400 | pos->peer2handle = NULL; | ||
401 | } | ||
402 | free_pos = pos; | ||
403 | pos = pos->next; | ||
404 | GNUNET_free (free_pos); | ||
405 | } | ||
406 | |||
407 | #if VERBOSE | ||
408 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
409 | "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", | ||
410 | transmit_ready_scheduled, transmit_ready_failed, | ||
411 | transmit_ready_called); | ||
412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
413 | "Total messages received %d, expected %d.\n", | ||
414 | total_messages_received, expected_messages); | ||
415 | #endif | ||
416 | |||
417 | if (pg != NULL) | ||
418 | { | ||
419 | GNUNET_TESTING_daemons_stop (pg, timeout, &shutdown_callback, NULL); | ||
420 | ok = 7331; /* Opposite of leet */ | ||
421 | } | ||
422 | else | ||
423 | ok = 401; /* Never got peers started */ | ||
424 | |||
425 | if (dotOutFile != NULL) | ||
426 | { | ||
427 | FPRINTF (dotOutFile, "%s", "}"); | ||
428 | FCLOSE (dotOutFile); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static size_t | ||
433 | transmit_ready (void *cls, size_t size, void *buf) | ||
434 | { | ||
435 | struct GNUNET_TestMessage *m; | ||
436 | struct TestMessageContext *pos = cls; | ||
437 | |||
438 | GNUNET_assert (buf != NULL); | ||
439 | m = (struct GNUNET_TestMessage *) buf; | ||
440 | m->header.type = htons (MTYPE); | ||
441 | m->header.size = htons (sizeof (struct GNUNET_TestMessage)); | ||
442 | m->uid = htonl (pos->uid); | ||
443 | transmit_ready_called++; | ||
444 | #if VERBOSE > 1 | ||
445 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
446 | "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", | ||
447 | GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, | ||
448 | transmit_ready_called); | ||
449 | #endif | ||
450 | return sizeof (struct GNUNET_TestMessage); | ||
451 | } | ||
452 | |||
453 | |||
454 | static struct GNUNET_CORE_MessageHandler no_handlers[] = { | ||
455 | {NULL, 0, 0} | ||
456 | }; | ||
457 | |||
458 | static struct GNUNET_CORE_MessageHandler handlers[] = { | ||
459 | {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, | ||
460 | {NULL, 0, 0} | ||
461 | }; | ||
462 | |||
463 | static void | ||
464 | init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, | ||
465 | const struct GNUNET_PeerIdentity *my_identity) | ||
466 | { | ||
467 | struct TestMessageContext *pos = cls; | ||
468 | |||
469 | total_server_connections++; | ||
470 | |||
471 | pos->peer2connected = GNUNET_YES; | ||
472 | if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ | ||
473 | { | ||
474 | #if VERBOSE > 1 | ||
475 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
476 | "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", | ||
477 | GNUNET_i2s (my_identity), | ||
478 | GNUNET_h2s (&pos->peer1->id.hashPubKey)); | ||
479 | #endif | ||
480 | if (NULL == | ||
481 | GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout, | ||
482 | &pos->peer2->id, | ||
483 | sizeof (struct GNUNET_TestMessage), | ||
484 | &transmit_ready, pos)) | ||
485 | { | ||
486 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
487 | "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", | ||
488 | GNUNET_i2s (&pos->peer2->id)); | ||
489 | transmit_ready_failed++; | ||
490 | } | ||
491 | else | ||
492 | { | ||
493 | transmit_ready_scheduled++; | ||
494 | } | ||
495 | } | ||
496 | } | ||
497 | |||
498 | /** | ||
499 | * Method called whenever a given peer connects. | ||
500 | * | ||
501 | * @param cls closure | ||
502 | * @param peer peer identity this notification is about | ||
503 | * @param atsi performance data for the connection | ||
504 | */ | ||
505 | static void | ||
506 | connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
507 | const struct GNUNET_ATS_Information *atsi) | ||
508 | { | ||
509 | struct TestMessageContext *pos = cls; | ||
510 | |||
511 | if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) | ||
512 | { | ||
513 | pos->peer1notified = GNUNET_YES; | ||
514 | #if VERBOSE > 1 | ||
515 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
516 | "Peer `%s' notified of connection to peer `%s'\n", | ||
517 | GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); | ||
518 | #endif | ||
519 | } | ||
520 | else | ||
521 | return; | ||
522 | |||
523 | if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ | ||
524 | { | ||
525 | #if VERBOSE > 1 | ||
526 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
527 | "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", | ||
528 | GNUNET_i2s (&pos->peer2->id), | ||
529 | GNUNET_h2s (&pos->peer1->id.hashPubKey)); | ||
530 | #endif | ||
531 | if (NULL == | ||
532 | GNUNET_CORE_notify_transmit_ready (pos->peer1handle, 0, timeout, | ||
533 | &pos->peer2->id, | ||
534 | sizeof (struct GNUNET_TestMessage), | ||
535 | &transmit_ready, pos)) | ||
536 | { | ||
537 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
538 | "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", | ||
539 | GNUNET_i2s (&pos->peer2->id)); | ||
540 | transmit_ready_failed++; | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | transmit_ready_scheduled++; | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | |||
549 | static void | ||
550 | init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, | ||
551 | const struct GNUNET_PeerIdentity *my_identity) | ||
552 | { | ||
553 | struct TestMessageContext *pos = cls; | ||
554 | |||
555 | total_server_connections++; | ||
556 | |||
557 | #if VERBOSE > 1 | ||
558 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
559 | "Core connection to `%4s' established, setting up handles\n", | ||
560 | GNUNET_i2s (my_identity)); | ||
561 | #endif | ||
562 | |||
563 | /* | ||
564 | * Connect to the receiving peer | ||
565 | */ | ||
566 | pos->peer2handle = | ||
567 | GNUNET_CORE_connect (pos->peer2->cfg, pos, &init_notify_peer2, NULL, | ||
568 | NULL, NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, | ||
569 | handlers); | ||
570 | |||
571 | } | ||
572 | |||
573 | |||
574 | static void | ||
575 | send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
576 | { | ||
577 | struct TestMessageContext *pos = cls; | ||
578 | |||
579 | if ((pos == test_messages) && (settle_time.rel_value > 0)) | ||
580 | { | ||
581 | topology_connections = 0; | ||
582 | GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); | ||
583 | } | ||
584 | if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) | ||
585 | return; | ||
586 | |||
587 | if (die_task == GNUNET_SCHEDULER_NO_TASK) | ||
588 | { | ||
589 | die_task = | ||
590 | GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, | ||
591 | "from send test messages (timeout)"); | ||
592 | } | ||
593 | |||
594 | if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) | ||
595 | { | ||
596 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
597 | (GNUNET_TIME_UNIT_SECONDS, 1), | ||
598 | &send_test_messages, pos); | ||
599 | return; /* Otherwise we'll double schedule messages here! */ | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * Connect to the sending peer | ||
604 | */ | ||
605 | pos->peer1handle = | ||
606 | GNUNET_CORE_connect (pos->peer1->cfg, pos, &init_notify_peer1, | ||
607 | &connect_notify_peers, NULL, NULL, NULL, GNUNET_NO, | ||
608 | NULL, GNUNET_NO, no_handlers); | ||
609 | |||
610 | GNUNET_assert (pos->peer1handle != NULL); | ||
611 | |||
612 | if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) | ||
613 | { | ||
614 | GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
619 | (GNUNET_TIME_UNIT_SECONDS, 1), | ||
620 | &send_test_messages, pos->next); | ||
621 | } | ||
622 | } | ||
623 | |||
624 | |||
625 | void | ||
626 | topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, | ||
627 | const struct GNUNET_PeerIdentity *second, uint32_t distance, | ||
628 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
629 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
630 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
631 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
632 | const char *emsg) | ||
633 | { | ||
634 | struct TestMessageContext *temp_context; | ||
635 | |||
636 | if (emsg == NULL) | ||
637 | { | ||
638 | #if VERBOSE | ||
639 | if ((total_connections) % modnum == 0) | ||
640 | { | ||
641 | if (total_connections == 0) | ||
642 | FPRINTF (stdout, "%s", "0%%"); | ||
643 | else | ||
644 | FPRINTF (stdout, "%d%%", | ||
645 | (int) (((float) total_connections / expected_connections) * | ||
646 | 100)); | ||
647 | |||
648 | } | ||
649 | else if (total_connections % dotnum == 0) | ||
650 | { | ||
651 | FPRINTF (stdout, "%s", "."); | ||
652 | } | ||
653 | fflush (stdout); | ||
654 | #endif | ||
655 | total_connections++; | ||
656 | #if VERBOSE > 1 | ||
657 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", | ||
658 | first_daemon->shortname, second_daemon->shortname); | ||
659 | #endif | ||
660 | temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); | ||
661 | temp_context->peer1 = first_daemon; | ||
662 | temp_context->peer2 = second_daemon; | ||
663 | temp_context->next = test_messages; | ||
664 | temp_context->uid = total_connections; | ||
665 | temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
666 | test_messages = temp_context; | ||
667 | |||
668 | expected_messages++; | ||
669 | if (dotOutFile != NULL) | ||
670 | FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, | ||
671 | second_daemon->shortname); | ||
672 | } | ||
673 | #if VERBOSE | ||
674 | else | ||
675 | { | ||
676 | failed_connections++; | ||
677 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
678 | "Failed to connect peer %s to peer %s with error :\n%s\n", | ||
679 | first_daemon->shortname, second_daemon->shortname, emsg); | ||
680 | } | ||
681 | #endif | ||
682 | |||
683 | if (total_connections == expected_connections) | ||
684 | { | ||
685 | #if VERBOSE | ||
686 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
687 | #endif | ||
688 | #if VERBOSE | ||
689 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
690 | "Created %d total connections, which is our target number! Calling send messages.\n", | ||
691 | total_connections); | ||
692 | #endif | ||
693 | modnum = expected_messages / 4; | ||
694 | dotnum = (expected_messages / 50) + 1; | ||
695 | GNUNET_SCHEDULER_cancel (die_task); | ||
696 | die_task = GNUNET_SCHEDULER_NO_TASK; | ||
697 | #if DELAY_FOR_LOGGING | ||
698 | FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); | ||
699 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
700 | (GNUNET_TIME_UNIT_SECONDS, 10), | ||
701 | &send_test_messages, test_messages); | ||
702 | gather_log_data (); | ||
703 | #else | ||
704 | if (settle_time.rel_value > 0) | ||
705 | { | ||
706 | GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); | ||
707 | } | ||
708 | GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, | ||
709 | test_messages); | ||
710 | #endif | ||
711 | #if VERBOSE | ||
712 | FPRINTF (stdout, "%s", "Test message progress: ["); | ||
713 | #endif | ||
714 | |||
715 | } | ||
716 | else if (total_connections + failed_connections == expected_connections) | ||
717 | { | ||
718 | if (failed_connections < | ||
719 | (unsigned int) (fail_percentage * total_connections)) | ||
720 | { | ||
721 | GNUNET_SCHEDULER_cancel (die_task); | ||
722 | die_task = GNUNET_SCHEDULER_NO_TASK; | ||
723 | GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); | ||
724 | } | ||
725 | else | ||
726 | { | ||
727 | GNUNET_SCHEDULER_cancel (die_task); | ||
728 | die_task = | ||
729 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
730 | "from topology_callback (too many failed connections)"); | ||
731 | } | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | #if VERBOSE > 1 | ||
736 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
737 | "Have %d total connections, %d failed connections, Want %d (at least %d)\n", | ||
738 | total_connections, failed_connections, expected_connections, | ||
739 | expected_connections - | ||
740 | (unsigned int) (fail_percentage * expected_connections)); | ||
741 | #endif | ||
742 | } | ||
743 | } | ||
744 | |||
745 | static void | ||
746 | topology_creation_finished (void *cls, const char *emsg) | ||
747 | { | ||
748 | #if VERBOSE | ||
749 | if (emsg == NULL) | ||
750 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
751 | "All topology connections created successfully!\n"); | ||
752 | #endif | ||
753 | } | ||
754 | |||
755 | static void | ||
756 | connect_topology () | ||
757 | { | ||
758 | expected_connections = -1; | ||
759 | if ((pg != NULL) && (peers_left == 0)) | ||
760 | { | ||
761 | expected_connections = | ||
762 | GNUNET_TESTING_connect_topology (pg, connection_topology, | ||
763 | connect_topology_option, | ||
764 | connect_topology_option_modifier, | ||
765 | connect_timeout, connect_attempts, | ||
766 | &topology_creation_finished, NULL); | ||
767 | #if VERBOSE > 1 | ||
768 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", | ||
769 | expected_connections); | ||
770 | #endif | ||
771 | } | ||
772 | |||
773 | GNUNET_SCHEDULER_cancel (die_task); | ||
774 | if (expected_connections == GNUNET_SYSERR) | ||
775 | { | ||
776 | die_task = | ||
777 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
778 | "from connect topology (bad return)"); | ||
779 | } | ||
780 | |||
781 | die_task = | ||
782 | GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, | ||
783 | "from connect topology (timeout)"); | ||
784 | modnum = expected_connections / 4; | ||
785 | dotnum = (expected_connections / 50) + 1; | ||
786 | #if VERBOSE | ||
787 | FPRINTF (stdout, "%s", "Peer connection progress: ["); | ||
788 | #endif | ||
789 | } | ||
790 | |||
791 | static void | ||
792 | create_topology () | ||
793 | { | ||
794 | peers_left = num_peers; /* Reset counter */ | ||
795 | if (GNUNET_TESTING_create_topology | ||
796 | (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) | ||
797 | { | ||
798 | #if VERBOSE | ||
799 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
800 | "Topology set up, now starting peers!\n"); | ||
801 | FPRINTF (stdout, "%s", "Daemon start progress ["); | ||
802 | #endif | ||
803 | GNUNET_TESTING_daemons_continue_startup (pg); | ||
804 | } | ||
805 | else | ||
806 | { | ||
807 | GNUNET_SCHEDULER_cancel (die_task); | ||
808 | die_task = | ||
809 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
810 | "from create topology (bad return)"); | ||
811 | } | ||
812 | GNUNET_SCHEDULER_cancel (die_task); | ||
813 | die_task = | ||
814 | GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, | ||
815 | "from continue startup (timeout)"); | ||
816 | } | ||
817 | |||
818 | |||
819 | static void | ||
820 | peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
821 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
822 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
823 | { | ||
824 | if (emsg != NULL) | ||
825 | { | ||
826 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
827 | "Failed to start daemon with error: `%s'\n", emsg); | ||
828 | return; | ||
829 | } | ||
830 | GNUNET_assert (id != NULL); | ||
831 | #if VERBOSE > 1 | ||
832 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", | ||
833 | (num_peers - peers_left) + 1, num_peers); | ||
834 | #endif | ||
835 | #if VERBOSE | ||
836 | if ((num_peers - peers_left) % modnum == 0) | ||
837 | { | ||
838 | if (num_peers - peers_left == 0) | ||
839 | FPRINTF (stdout, "%s", "0%%"); | ||
840 | else | ||
841 | FPRINTF (stdout, "%d%%", | ||
842 | (int) (((float) (num_peers - peers_left) / num_peers) * 100)); | ||
843 | |||
844 | } | ||
845 | else if ((num_peers - peers_left) % dotnum == 0) | ||
846 | { | ||
847 | FPRINTF (stdout, "%s", "."); | ||
848 | } | ||
849 | fflush (stdout); | ||
850 | #endif | ||
851 | peers_left--; | ||
852 | if (peers_left == 0) | ||
853 | { | ||
854 | #if VERBOSE | ||
855 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
856 | #endif | ||
857 | #if VERBOSE | ||
858 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
859 | "All %d daemons started, now connecting peers!\n", num_peers); | ||
860 | #endif | ||
861 | GNUNET_SCHEDULER_cancel (die_task); | ||
862 | /* Set up task in case topology creation doesn't finish | ||
863 | * within a reasonable amount of time */ | ||
864 | die_task = | ||
865 | GNUNET_SCHEDULER_add_delayed (timeout, &end_badly, | ||
866 | "from peers_started_callback"); | ||
867 | #if DELAY_FOR_LOGGING | ||
868 | FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); | ||
869 | gather_log_data (); | ||
870 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
871 | (GNUNET_TIME_UNIT_SECONDS, 10), | ||
872 | &connect_topology, NULL); | ||
873 | #else | ||
874 | connect_topology (); | ||
875 | #endif | ||
876 | ok = 0; | ||
877 | } | ||
878 | } | ||
879 | |||
880 | /** | ||
881 | * Callback indicating that the hostkey was created for a peer. | ||
882 | * | ||
883 | * @param cls NULL | ||
884 | * @param id the peer identity | ||
885 | * @param d the daemon handle (pretty useless at this point, remove?) | ||
886 | * @param emsg non-null on failure | ||
887 | */ | ||
888 | void | ||
889 | hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
890 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
891 | { | ||
892 | if (emsg != NULL) | ||
893 | { | ||
894 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
895 | "Hostkey callback received error: %s\n", emsg); | ||
896 | } | ||
897 | |||
898 | #if VERBOSE > 1 | ||
899 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
900 | "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, | ||
901 | num_peers, GNUNET_i2s (id)); | ||
902 | #endif | ||
903 | |||
904 | #if VERBOSE | ||
905 | if ((num_peers - peers_left) % modnum == 0) | ||
906 | { | ||
907 | if (num_peers - peers_left == 0) | ||
908 | FPRINTF (stdout, "%s", "0%%"); | ||
909 | else | ||
910 | FPRINTF (stdout, "%d%%", | ||
911 | (int) (((float) (num_peers - peers_left) / num_peers) * 100)); | ||
912 | |||
913 | } | ||
914 | else if ((num_peers - peers_left) % dotnum == 0) | ||
915 | { | ||
916 | FPRINTF (stdout, "%s", "."); | ||
917 | } | ||
918 | fflush (stdout); | ||
919 | #endif | ||
920 | peers_left--; | ||
921 | if (peers_left == 0) | ||
922 | { | ||
923 | #if VERBOSE | ||
924 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
925 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
926 | "All %d hostkeys created, now creating topology!\n", num_peers); | ||
927 | #endif | ||
928 | GNUNET_SCHEDULER_cancel (die_task); | ||
929 | /* Set up task in case topology creation doesn't finish | ||
930 | * within a reasonable amount of time */ | ||
931 | die_task = | ||
932 | GNUNET_SCHEDULER_add_delayed (test_timeout, &end_badly, | ||
933 | "from create_topology"); | ||
934 | GNUNET_SCHEDULER_add_now (&create_topology, NULL); | ||
935 | ok = 0; | ||
936 | } | ||
937 | } | ||
938 | |||
939 | static void | ||
940 | run (void *cls, char *const *args, const char *cfgfile, | ||
941 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
942 | { | ||
943 | char *topology_str; | ||
944 | char *connect_topology_str; | ||
945 | char *blacklist_topology_str; | ||
946 | char *connect_topology_option_str; | ||
947 | char *connect_topology_option_modifier_string; | ||
948 | unsigned long long temp_settle; | ||
949 | |||
950 | ok = 1; | ||
951 | |||
952 | dotOutFile = FOPEN (dotOutFileName, "w"); | ||
953 | if (dotOutFile != NULL) | ||
954 | { | ||
955 | FPRINTF (dotOutFile, "%s", "strict graph G {\n"); | ||
956 | } | ||
957 | |||
958 | #if VERBOSE | ||
959 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
960 | "Starting daemons based on config file %s\n", cfgfile); | ||
961 | #endif | ||
962 | |||
963 | if (GNUNET_YES != | ||
964 | GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", | ||
965 | &test_directory)) | ||
966 | { | ||
967 | ok = 404; | ||
968 | return; | ||
969 | } | ||
970 | |||
971 | if ((GNUNET_YES == | ||
972 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", | ||
973 | &topology_str)) && | ||
974 | (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) | ||
975 | { | ||
976 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
977 | "Invalid topology `%s' given for section %s option %s\n", | ||
978 | topology_str, "TESTING", "TOPOLOGY"); | ||
979 | topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ | ||
980 | } | ||
981 | |||
982 | if ((GNUNET_YES == | ||
983 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
984 | "connect_topology", | ||
985 | &connect_topology_str)) && | ||
986 | (GNUNET_NO == | ||
987 | GNUNET_TESTING_topology_get (&connection_topology, | ||
988 | connect_topology_str))) | ||
989 | { | ||
990 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
991 | "Invalid connect topology `%s' given for section %s option %s\n", | ||
992 | connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); | ||
993 | } | ||
994 | GNUNET_free_non_null (connect_topology_str); | ||
995 | if ((GNUNET_YES == | ||
996 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
997 | "connect_topology_option", | ||
998 | &connect_topology_option_str)) && | ||
999 | (GNUNET_NO == | ||
1000 | GNUNET_TESTING_topology_option_get (&connect_topology_option, | ||
1001 | connect_topology_option_str))) | ||
1002 | { | ||
1003 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1004 | "Invalid connect topology option `%s' given for section %s option %s\n", | ||
1005 | connect_topology_option_str, "TESTING", | ||
1006 | "CONNECT_TOPOLOGY_OPTION"); | ||
1007 | connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ | ||
1008 | } | ||
1009 | GNUNET_free_non_null (connect_topology_option_str); | ||
1010 | if (GNUNET_YES == | ||
1011 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1012 | "connect_topology_option_modifier", | ||
1013 | &connect_topology_option_modifier_string)) | ||
1014 | { | ||
1015 | if (SSCANF | ||
1016 | (connect_topology_option_modifier_string, "%lf", | ||
1017 | &connect_topology_option_modifier) != 1) | ||
1018 | { | ||
1019 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1020 | _ | ||
1021 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
1022 | connect_topology_option_modifier_string, | ||
1023 | "connect_topology_option_modifier", "TESTING"); | ||
1024 | } | ||
1025 | GNUNET_free (connect_topology_option_modifier_string); | ||
1026 | } | ||
1027 | |||
1028 | if (GNUNET_YES != | ||
1029 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1030 | "blacklist_transports", | ||
1031 | &blacklist_transports)) | ||
1032 | blacklist_transports = NULL; | ||
1033 | |||
1034 | if ((GNUNET_YES == | ||
1035 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1036 | "blacklist_topology", | ||
1037 | &blacklist_topology_str)) && | ||
1038 | (GNUNET_NO == | ||
1039 | GNUNET_TESTING_topology_get (&blacklist_topology, | ||
1040 | blacklist_topology_str))) | ||
1041 | { | ||
1042 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1043 | "Invalid topology `%s' given for section %s option %s\n", | ||
1044 | topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); | ||
1045 | } | ||
1046 | GNUNET_free_non_null (topology_str); | ||
1047 | GNUNET_free_non_null (blacklist_topology_str); | ||
1048 | |||
1049 | if (GNUNET_OK != | ||
1050 | GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", | ||
1051 | &settle_time)) | ||
1052 | { | ||
1053 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
1054 | "testing", "SETTLE_TIME"); | ||
1055 | return; | ||
1056 | } | ||
1057 | if (GNUNET_SYSERR == | ||
1058 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", | ||
1059 | &num_peers)) | ||
1060 | num_peers = DEFAULT_NUM_PEERS; | ||
1061 | |||
1062 | if (GNUNET_OK != | ||
1063 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "CONNECT_TIMEOUT", | ||
1064 | &connect_timeout)) | ||
1065 | { | ||
1066 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
1067 | "testing", "CONNECT_TIMEOUT"); | ||
1068 | return; | ||
1069 | } | ||
1070 | |||
1071 | |||
1072 | if (GNUNET_OK != | ||
1073 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", | ||
1074 | &connect_attempts)) | ||
1075 | { | ||
1076 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
1077 | "testing", "connect_attempts"); | ||
1078 | return; | ||
1079 | } | ||
1080 | |||
1081 | main_cfg = cfg; | ||
1082 | |||
1083 | peers_left = num_peers; | ||
1084 | |||
1085 | /** | ||
1086 | * How long until we fail the whole testcase? | ||
1087 | */ | ||
1088 | test_timeout = | ||
1089 | GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply | ||
1090 | (GNUNET_TIME_UNIT_SECONDS, | ||
1091 | SECONDS_PER_PEER_START), num_peers * 2); | ||
1092 | |||
1093 | /** | ||
1094 | * How long until we give up on starting the peers? | ||
1095 | */ | ||
1096 | timeout = | ||
1097 | GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply | ||
1098 | (GNUNET_TIME_UNIT_SECONDS, | ||
1099 | SECONDS_PER_PEER_START), num_peers); | ||
1100 | |||
1101 | modnum = num_peers / 4; | ||
1102 | dotnum = (num_peers / 50) + 1; | ||
1103 | #if VERBOSE | ||
1104 | FPRINTF (stdout, "%s", "Hostkey generation progress: ["); | ||
1105 | #endif | ||
1106 | /* Set up a task to end testing if peer start fails */ | ||
1107 | die_task = | ||
1108 | GNUNET_SCHEDULER_add_delayed (timeout, &end_badly, | ||
1109 | "didn't generate all hostkeys within a reasonable amount of time!!!"); | ||
1110 | |||
1111 | GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); | ||
1112 | pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left / 2, | ||
1113 | peers_left, timeout, &hostkey_callback, | ||
1114 | NULL, &peers_started_callback, NULL, | ||
1115 | &topology_callback, NULL, NULL); | ||
1116 | |||
1117 | } | ||
1118 | |||
1119 | static int | ||
1120 | check () | ||
1121 | { | ||
1122 | char *binary_name; | ||
1123 | char *config_file_name; | ||
1124 | |||
1125 | GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); | ||
1126 | GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", | ||
1127 | topology_string); | ||
1128 | int ret; | ||
1129 | |||
1130 | char *const argv[] = { binary_name, | ||
1131 | "-c", | ||
1132 | config_file_name, | ||
1133 | #if VERBOSE | ||
1134 | "-L", "DEBUG", | ||
1135 | #endif | ||
1136 | NULL | ||
1137 | }; | ||
1138 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1139 | GNUNET_GETOPT_OPTION_END | ||
1140 | }; | ||
1141 | ret = | ||
1142 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
1143 | binary_name, "nohelp", options, &run, &ok); | ||
1144 | if (ret != GNUNET_OK) | ||
1145 | { | ||
1146 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1147 | "`test-testing-topology-%s': Failed with error code %d\n", | ||
1148 | topology_string, ret); | ||
1149 | } | ||
1150 | GNUNET_free (binary_name); | ||
1151 | GNUNET_free (config_file_name); | ||
1152 | return ok; | ||
1153 | } | ||
1154 | |||
1155 | int | ||
1156 | main (int argc, char *argv[]) | ||
1157 | { | ||
1158 | int ret; | ||
1159 | char *binary_start_pos; | ||
1160 | char *our_binary_name; | ||
1161 | |||
1162 | binary_start_pos = rindex (argv[0], '/'); | ||
1163 | GNUNET_assert (binary_start_pos != NULL); | ||
1164 | topology_string = strstr (binary_start_pos, "_topology"); | ||
1165 | GNUNET_assert (topology_string != NULL); | ||
1166 | topology_string++; | ||
1167 | topology_string = strstr (topology_string, "_"); | ||
1168 | GNUNET_assert (topology_string != NULL); | ||
1169 | topology_string++; | ||
1170 | |||
1171 | GNUNET_asprintf (&our_binary_name, "test-testing-large-topology_%s", | ||
1172 | topology_string); | ||
1173 | GNUNET_asprintf (&dotOutFileName, "large_topology_%s.dot", topology_string); | ||
1174 | |||
1175 | GNUNET_log_setup (our_binary_name, | ||
1176 | #if VERBOSE | ||
1177 | "DEBUG", | ||
1178 | #else | ||
1179 | "WARNING", | ||
1180 | #endif | ||
1181 | NULL); | ||
1182 | ret = check (); | ||
1183 | |||
1184 | /** | ||
1185 | * Need to remove base directory, subdirectories taken care | ||
1186 | * of by the testing framework. | ||
1187 | */ | ||
1188 | if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) | ||
1189 | { | ||
1190 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1191 | "Failed to remove testing directory %s\n", test_directory); | ||
1192 | } | ||
1193 | GNUNET_free (our_binary_name); | ||
1194 | return ret; | ||
1195 | } | ||
1196 | |||
1197 | /* end of test_testing_topology.c */ | ||
diff --git a/src/testing/test_testing_peergroup.c b/src/testing/test_testing_peergroup.c deleted file mode 100644 index 061a0ca75..000000000 --- a/src/testing/test_testing_peergroup.c +++ /dev/null | |||
@@ -1,157 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_peergroup.c | ||
22 | * @brief testcase for functions to connect peers in testing_peergroup.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | |||
27 | #define VERBOSE GNUNET_NO | ||
28 | |||
29 | #define NUM_PEERS 4 | ||
30 | |||
31 | /** | ||
32 | * How long until we give up on connecting the peers? | ||
33 | */ | ||
34 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
35 | |||
36 | static int ok; | ||
37 | |||
38 | static int peers_left; | ||
39 | |||
40 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
41 | |||
42 | /** | ||
43 | * Check whether peers successfully shut down. | ||
44 | */ | ||
45 | void | ||
46 | shutdown_callback (void *cls, const char *emsg) | ||
47 | { | ||
48 | if (emsg != NULL) | ||
49 | { | ||
50 | #if VERBOSE | ||
51 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); | ||
52 | #endif | ||
53 | if (ok == 0) | ||
54 | ok = 666; | ||
55 | } | ||
56 | else | ||
57 | { | ||
58 | #if VERBOSE | ||
59 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); | ||
60 | #endif | ||
61 | ok = 0; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | |||
66 | static void | ||
67 | my_cb (void *cls, const char *emsg) | ||
68 | { | ||
69 | if (emsg != NULL) | ||
70 | { | ||
71 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
72 | "Peergroup callback called with error, aborting test!\n"); | ||
73 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n"); | ||
74 | ok = 1; | ||
75 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
80 | "Peer Group started successfully, ending test!\n"); | ||
81 | /** | ||
82 | * If something is to actually be DONE with the testcase, it should | ||
83 | * be put in here. Usually there will be a struct declared (or global | ||
84 | * variables can be used) to keep track of the state, statistics, | ||
85 | * handles to peers, etc. The example here is the opaque "TestCaseData" | ||
86 | * struct that could be passed into a function "additional_code_for_testing" | ||
87 | * which can be used to perform actions on the peers in the peergroup. | ||
88 | * Also, the GNUNET_TESTING_daemons_stop call would need to be removed, | ||
89 | * and only called once all of the testing is complete. | ||
90 | */ | ||
91 | |||
92 | /** | ||
93 | * struct TestcaseData *state_closure; | ||
94 | * GNUNET_SCHEDULER_add_now(&additional_code_for_testing, state_closure); | ||
95 | */ | ||
96 | |||
97 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
98 | } | ||
99 | |||
100 | |||
101 | static void | ||
102 | run (void *cls, char *const *args, const char *cfgfile, | ||
103 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
104 | { | ||
105 | struct GNUNET_CONFIGURATION_Handle *testing_cfg; | ||
106 | |||
107 | ok = 1; | ||
108 | testing_cfg = GNUNET_CONFIGURATION_create (); | ||
109 | GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (testing_cfg, cfgfile)); | ||
110 | #if VERBOSE | ||
111 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n"); | ||
112 | GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing", | ||
113 | "use_progressbars", "YES"); | ||
114 | #endif | ||
115 | peers_left = NUM_PEERS; | ||
116 | pg = GNUNET_TESTING_peergroup_start (testing_cfg, peers_left, TIMEOUT, NULL, | ||
117 | &my_cb, NULL, NULL); | ||
118 | GNUNET_assert (pg != NULL); | ||
119 | } | ||
120 | |||
121 | static int | ||
122 | check () | ||
123 | { | ||
124 | char *const argv[] = { "test-testing-peergroup", | ||
125 | "-c", | ||
126 | "test_testing_peergroup_data.conf", | ||
127 | #if VERBOSE | ||
128 | "-L", "DEBUG", | ||
129 | #endif | ||
130 | NULL | ||
131 | }; | ||
132 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
133 | GNUNET_GETOPT_OPTION_END | ||
134 | }; | ||
135 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
136 | "test-testing-peergroup", "nohelp", options, &run, &ok); | ||
137 | return ok; | ||
138 | } | ||
139 | |||
140 | int | ||
141 | main (int argc, char *argv[]) | ||
142 | { | ||
143 | int ret; | ||
144 | |||
145 | GNUNET_log_setup ("test-testing-peergroup", | ||
146 | #if VERBOSE | ||
147 | "DEBUG", | ||
148 | #else | ||
149 | "WARNING", | ||
150 | #endif | ||
151 | NULL); | ||
152 | ret = check (); | ||
153 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing"); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | /* end of test_testing_peergroup.c */ | ||
diff --git a/src/testing/test_testing_peergroup_data.conf b/src/testing/test_testing_peergroup_data.conf deleted file mode 100644 index 6eadede95..000000000 --- a/src/testing/test_testing_peergroup_data.conf +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | @INLINE@ test_testing_defaults.conf | ||
2 | [PATHS] | ||
3 | DEFAULTCONFIG = test_testing_peergroup_data.conf | ||
4 | |||
5 | [TESTING] | ||
6 | CONNECT_ATTEMPTS = 2 | ||
7 | MAX_OUTSTANDING_CONNECTIONS = 20 | ||
8 | MAX_CONCURRENT_SSH = 1 | ||
9 | PEERGROUP_TIMEOUT = 300 s | ||
10 | TOPOLOGY = CLIQUE | ||
11 | PERCENTAGE = 0.5 | ||
12 | PROBABILITY = 0.5 | ||
13 | CONNECT_TOPOLOGY = CLIQUE | ||
14 | CONNECT_TOPOLOGY_OPTION = CONNECT_NONE | ||
15 | CONNECT_TOPOLOGY_OPTION_MODIFIER = 0.0 | ||
16 | BLACKLIST_TOPOLOGY = NONE | ||
17 | BLACKLIST_TRANSPORTS = tcp udp | ||
18 | USE_PROGRESSBARS = NO | ||
19 | |||
20 | [arm] | ||
21 | DEFAULTSERVICES = core | ||
22 | |||
diff --git a/src/testing/test_testing_reconnect.c b/src/testing/test_testing_reconnect.c deleted file mode 100644 index bcee38659..000000000 --- a/src/testing/test_testing_reconnect.c +++ /dev/null | |||
@@ -1,249 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_reconnect.c | ||
22 | * @brief testcase for functions to connect two peers in testing.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | |||
27 | #define VERBOSE GNUNET_YES | ||
28 | |||
29 | /** | ||
30 | * How long until we give up on connecting the peers? | ||
31 | */ | ||
32 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
33 | |||
34 | #define CONNECT_ATTEMPTS 3 | ||
35 | |||
36 | static int ok; | ||
37 | |||
38 | static struct GNUNET_TESTING_Daemon *d1; | ||
39 | |||
40 | static struct GNUNET_TESTING_Daemon *d2; | ||
41 | |||
42 | static struct GNUNET_CONFIGURATION_Handle *c1; | ||
43 | |||
44 | static struct GNUNET_CONFIGURATION_Handle *c2; | ||
45 | |||
46 | static struct GNUNET_TESTING_ConnectContext *cc; | ||
47 | |||
48 | /** | ||
49 | * How many start-connect-stop iterations should we do? | ||
50 | */ | ||
51 | #define NUM_PHASES 2 | ||
52 | |||
53 | static int phase; | ||
54 | |||
55 | /** | ||
56 | * Run the next phase of starting daemons, connecting them and | ||
57 | * stopping them again. | ||
58 | */ | ||
59 | static void | ||
60 | run_phase (void); | ||
61 | |||
62 | static void | ||
63 | end2_cb (void *cls, const char *emsg) | ||
64 | { | ||
65 | |||
66 | if (emsg != NULL) | ||
67 | { | ||
68 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Ending with error: %s\n", emsg); | ||
69 | ok = 1; | ||
70 | } | ||
71 | else | ||
72 | { | ||
73 | if (phase < NUM_PHASES) | ||
74 | { | ||
75 | FPRINTF (stderr, "%s", "."); | ||
76 | run_phase (); | ||
77 | return; | ||
78 | } | ||
79 | FPRINTF (stderr, "%s", ".\n"); | ||
80 | #if VERBOSE | ||
81 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
82 | "Both daemons terminated, will now exit.\n"); | ||
83 | #endif | ||
84 | ok = 0; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void | ||
89 | end1_cb (void *cls, const char *emsg) | ||
90 | { | ||
91 | if (emsg != NULL) | ||
92 | { | ||
93 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping daemon 1 gave: %s\n", | ||
94 | emsg); | ||
95 | ok = 1; | ||
96 | } | ||
97 | else | ||
98 | { | ||
99 | ok = 0; | ||
100 | } | ||
101 | if (d2 != NULL) | ||
102 | { | ||
103 | GNUNET_TESTING_daemon_stop (d2, TIMEOUT, &end2_cb, NULL, | ||
104 | (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, | ||
105 | GNUNET_NO); | ||
106 | d2 = NULL; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static void | ||
111 | finish_testing (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
112 | { | ||
113 | GNUNET_TESTING_daemon_stop (d1, TIMEOUT, &end1_cb, NULL, | ||
114 | (phase == NUM_PHASES) ? GNUNET_YES : GNUNET_NO, | ||
115 | GNUNET_NO); | ||
116 | d1 = NULL; | ||
117 | } | ||
118 | |||
119 | |||
120 | static void | ||
121 | my_connect_complete (void *cls, const struct GNUNET_PeerIdentity *first, | ||
122 | const struct GNUNET_PeerIdentity *second, | ||
123 | unsigned int distance, | ||
124 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
125 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
126 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
127 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
128 | const char *emsg) | ||
129 | { | ||
130 | cc = NULL; | ||
131 | #if VERBOSE | ||
132 | FPRINTF (stderr, "Peer %s ", GNUNET_i2s (first)); | ||
133 | FPRINTF (stderr, "connected to %s\n", GNUNET_i2s (second)); | ||
134 | #endif | ||
135 | GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
136 | } | ||
137 | |||
138 | |||
139 | |||
140 | |||
141 | static void | ||
142 | my_cb2 (void *cls, const struct GNUNET_PeerIdentity *id, | ||
143 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
144 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
145 | { | ||
146 | if (emsg != NULL) | ||
147 | { | ||
148 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 2 gave: %s\n", | ||
149 | emsg); | ||
150 | GNUNET_assert (0); | ||
151 | return; | ||
152 | } | ||
153 | GNUNET_assert (id != NULL); | ||
154 | #if VERBOSE | ||
155 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", | ||
156 | GNUNET_i2s (id)); | ||
157 | #endif | ||
158 | cc = GNUNET_TESTING_daemons_connect (d1, d2, TIMEOUT, CONNECT_ATTEMPTS, | ||
159 | GNUNET_YES, &my_connect_complete, NULL); | ||
160 | } | ||
161 | |||
162 | |||
163 | static void | ||
164 | my_cb1 (void *cls, const struct GNUNET_PeerIdentity *id, | ||
165 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
166 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
167 | { | ||
168 | if (emsg != NULL) | ||
169 | { | ||
170 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting daemon 1 gave: %s\n", | ||
171 | emsg); | ||
172 | GNUNET_assert (0); | ||
173 | return; | ||
174 | } | ||
175 | GNUNET_assert (id != NULL); | ||
176 | #if VERBOSE | ||
177 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Daemon `%s' started.\n", | ||
178 | GNUNET_i2s (id)); | ||
179 | #endif | ||
180 | d2 = GNUNET_TESTING_daemon_start (c2, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, | ||
181 | NULL, NULL, &my_cb2, NULL); | ||
182 | GNUNET_assert (d2 != NULL); | ||
183 | } | ||
184 | |||
185 | |||
186 | static void | ||
187 | run (void *cls, char *const *args, const char *cfgfile, | ||
188 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
189 | { | ||
190 | ok = 1; | ||
191 | #if VERBOSE | ||
192 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemon.\n"); | ||
193 | #endif | ||
194 | c1 = GNUNET_CONFIGURATION_create (); | ||
195 | GNUNET_assert (GNUNET_OK == | ||
196 | GNUNET_CONFIGURATION_load (c1, | ||
197 | "test_testing_connect_peer1.conf")); | ||
198 | c2 = GNUNET_CONFIGURATION_create (); | ||
199 | GNUNET_assert (GNUNET_OK == | ||
200 | GNUNET_CONFIGURATION_load (c2, | ||
201 | "test_testing_connect_peer2.conf")); | ||
202 | run_phase (); | ||
203 | } | ||
204 | |||
205 | static void | ||
206 | run_phase () | ||
207 | { | ||
208 | phase++; | ||
209 | d1 = GNUNET_TESTING_daemon_start (c1, TIMEOUT, GNUNET_NO, NULL, NULL, 0, NULL, | ||
210 | NULL, NULL, &my_cb1, NULL); | ||
211 | GNUNET_assert (d1 != NULL); | ||
212 | } | ||
213 | |||
214 | static int | ||
215 | check () | ||
216 | { | ||
217 | char *const argv[] = { "test-testing-reconnect", | ||
218 | "-c", | ||
219 | "test_testing_data.conf", | ||
220 | #if VERBOSE | ||
221 | "-L", "DEBUG", | ||
222 | #endif | ||
223 | NULL | ||
224 | }; | ||
225 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
226 | GNUNET_GETOPT_OPTION_END | ||
227 | }; | ||
228 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
229 | "test-testing-reconnect", "nohelp", options, &run, &ok); | ||
230 | return ok; | ||
231 | } | ||
232 | |||
233 | int | ||
234 | main (int argc, char *argv[]) | ||
235 | { | ||
236 | int ret; | ||
237 | |||
238 | GNUNET_log_setup ("test-testing-reconnect", | ||
239 | #if VERBOSE | ||
240 | "DEBUG", | ||
241 | #else | ||
242 | "WARNING", | ||
243 | #endif | ||
244 | NULL); | ||
245 | ret = check (); | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | /* end of test_testing_reconnect.c */ | ||
diff --git a/src/testing/test_testing_topology.c b/src/testing/test_testing_topology.c deleted file mode 100644 index 94cbc0df6..000000000 --- a/src/testing/test_testing_topology.c +++ /dev/null | |||
@@ -1,1220 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_topology.c | ||
22 | * @brief base testcase for testing all the topologies provided | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | #include "gnunet_core_service.h" | ||
27 | #include "gnunet_os_lib.h" | ||
28 | |||
29 | |||
30 | #define PROGRESS_BARS GNUNET_YES | ||
31 | |||
32 | #define DELAY_FOR_LOGGING GNUNET_NO | ||
33 | |||
34 | /** | ||
35 | * How long until we fail the whole testcase? | ||
36 | */ | ||
37 | #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 240) | ||
38 | |||
39 | /** | ||
40 | * How long until we give up on starting the peers? | ||
41 | */ | ||
42 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 500) | ||
43 | |||
44 | #define SECONDS_PER_PEER_START 120 | ||
45 | |||
46 | #define DEFAULT_NUM_PEERS 4 | ||
47 | |||
48 | #define MAX_OUTSTANDING_CONNECTIONS 100 | ||
49 | |||
50 | static float fail_percentage = 0.05; | ||
51 | |||
52 | static int ok; | ||
53 | |||
54 | static unsigned long long num_peers; | ||
55 | |||
56 | struct GNUNET_TIME_Relative connect_timeout; | ||
57 | |||
58 | static unsigned long long connect_attempts; | ||
59 | |||
60 | static unsigned int topology_connections; | ||
61 | |||
62 | static unsigned int total_connections; | ||
63 | |||
64 | static unsigned int failed_connections; | ||
65 | |||
66 | static unsigned int total_server_connections; | ||
67 | |||
68 | static unsigned int total_messages_received; | ||
69 | |||
70 | static unsigned int expected_messages; | ||
71 | |||
72 | static unsigned int expected_connections; | ||
73 | |||
74 | static unsigned long long peers_left; | ||
75 | |||
76 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
77 | |||
78 | const struct GNUNET_CONFIGURATION_Handle *main_cfg; | ||
79 | |||
80 | GNUNET_SCHEDULER_TaskIdentifier die_task; | ||
81 | |||
82 | static char *dotOutFileName; | ||
83 | |||
84 | static struct GNUNET_TIME_Relative settle_time; | ||
85 | |||
86 | static FILE *dotOutFile; | ||
87 | |||
88 | static char *topology_string; | ||
89 | |||
90 | static char *blacklist_transports; | ||
91 | |||
92 | static int transmit_ready_scheduled; | ||
93 | |||
94 | static int transmit_ready_failed; | ||
95 | |||
96 | static int transmit_ready_called; | ||
97 | |||
98 | static unsigned int modnum; | ||
99 | |||
100 | static unsigned int dotnum; | ||
101 | |||
102 | static enum GNUNET_TESTING_Topology topology; | ||
103 | |||
104 | static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* Don't do any blacklisting */ | ||
105 | |||
106 | static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ | ||
107 | |||
108 | static enum GNUNET_TESTING_TopologyOption connect_topology_option = | ||
109 | GNUNET_TESTING_TOPOLOGY_OPTION_ALL; | ||
110 | |||
111 | static double connect_topology_option_modifier = 0.0; | ||
112 | |||
113 | static char *test_directory; | ||
114 | |||
115 | #define MTYPE 12345 | ||
116 | |||
117 | GNUNET_NETWORK_STRUCT_BEGIN | ||
118 | |||
119 | struct GNUNET_TestMessage | ||
120 | { | ||
121 | /** | ||
122 | * Header of the message | ||
123 | */ | ||
124 | struct GNUNET_MessageHeader header; | ||
125 | |||
126 | /** | ||
127 | * Unique identifier for this message. | ||
128 | */ | ||
129 | uint32_t uid; | ||
130 | }; | ||
131 | GNUNET_NETWORK_STRUCT_END | ||
132 | |||
133 | struct TestMessageContext | ||
134 | { | ||
135 | /* This is a linked list */ | ||
136 | struct TestMessageContext *next; | ||
137 | |||
138 | /* Handle to the sending peer core */ | ||
139 | struct GNUNET_CORE_Handle *peer1handle; | ||
140 | |||
141 | /* Handle to the receiving peer core */ | ||
142 | struct GNUNET_CORE_Handle *peer2handle; | ||
143 | |||
144 | /* Handle to the sending peer daemon */ | ||
145 | struct GNUNET_TESTING_Daemon *peer1; | ||
146 | |||
147 | /* Handle to the receiving peer daemon */ | ||
148 | struct GNUNET_TESTING_Daemon *peer2; | ||
149 | |||
150 | /* Identifier for this message, so we don't disconnect other peers! */ | ||
151 | uint32_t uid; | ||
152 | |||
153 | /* Has peer1 been notified already of a connection to peer2? */ | ||
154 | int peer1notified; | ||
155 | |||
156 | /* Has the core of peer2 been connected already? */ | ||
157 | int peer2connected; | ||
158 | |||
159 | /* Task for disconnecting cores, allow task to be cancelled on shutdown */ | ||
160 | GNUNET_SCHEDULER_TaskIdentifier disconnect_task; | ||
161 | |||
162 | }; | ||
163 | |||
164 | static struct TestMessageContext *test_messages; | ||
165 | |||
166 | /** | ||
167 | * Check whether peers successfully shut down. | ||
168 | */ | ||
169 | static void | ||
170 | shutdown_callback (void *cls, const char *emsg) | ||
171 | { | ||
172 | if (emsg != NULL) | ||
173 | { | ||
174 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Shutdown of peers failed: %s!\n", | ||
175 | emsg); | ||
176 | if (ok == 0) | ||
177 | ok = 666; | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | |||
186 | #if DELAY_FOR_LOGGING | ||
187 | static void | ||
188 | gather_log_data () | ||
189 | { | ||
190 | char *peer_number; | ||
191 | char *connect_number; | ||
192 | struct GNUNET_OS_Process *mem_process; | ||
193 | |||
194 | GNUNET_asprintf (&peer_number, "%llu", num_peers); | ||
195 | GNUNET_asprintf (&connect_number, "%llu", expected_connections); | ||
196 | mem_process = | ||
197 | GNUNET_OS_start_process (NULL, NULL, "./memsize.pl", "memsize.pl", | ||
198 | "totals.txt", peer_number, connect_number, NULL); | ||
199 | GNUNET_OS_process_wait (mem_process); | ||
200 | GNUNET_OS_process_destroy (mem_process); | ||
201 | mem_process = NULL; | ||
202 | } | ||
203 | #endif | ||
204 | |||
205 | |||
206 | static void | ||
207 | finish_testing () | ||
208 | { | ||
209 | GNUNET_assert (pg != NULL); | ||
210 | struct TestMessageContext *pos; | ||
211 | struct TestMessageContext *free_pos; | ||
212 | |||
213 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
214 | "Called finish testing, stopping daemons.\n"); | ||
215 | pos = test_messages; | ||
216 | while (pos != NULL) | ||
217 | { | ||
218 | if (pos->peer1handle != NULL) | ||
219 | { | ||
220 | GNUNET_CORE_disconnect (pos->peer1handle); | ||
221 | pos->peer1handle = NULL; | ||
222 | } | ||
223 | if (pos->peer2handle != NULL) | ||
224 | { | ||
225 | GNUNET_CORE_disconnect (pos->peer2handle); | ||
226 | pos->peer2handle = NULL; | ||
227 | } | ||
228 | free_pos = pos; | ||
229 | pos = pos->next; | ||
230 | if (free_pos->disconnect_task != GNUNET_SCHEDULER_NO_TASK) | ||
231 | { | ||
232 | GNUNET_SCHEDULER_cancel (free_pos->disconnect_task); | ||
233 | } | ||
234 | GNUNET_free (free_pos); | ||
235 | } | ||
236 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
237 | "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", | ||
238 | transmit_ready_scheduled, transmit_ready_failed, | ||
239 | transmit_ready_called); | ||
240 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); | ||
241 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
242 | |||
243 | if (dotOutFile != NULL) | ||
244 | { | ||
245 | FPRINTF (dotOutFile, "%s", "}"); | ||
246 | FCLOSE (dotOutFile); | ||
247 | } | ||
248 | ok = 0; | ||
249 | } | ||
250 | |||
251 | |||
252 | static void | ||
253 | disconnect_cores (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
254 | { | ||
255 | struct TestMessageContext *pos = cls; | ||
256 | |||
257 | /* Disconnect from the respective cores */ | ||
258 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 1 `%4s'\n", | ||
259 | GNUNET_i2s (&pos->peer1->id)); | ||
260 | if (pos->peer1handle != NULL) | ||
261 | { | ||
262 | GNUNET_CORE_disconnect (pos->peer1handle); | ||
263 | pos->peer1handle = NULL; | ||
264 | } | ||
265 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer 2 `%4s'\n", | ||
266 | GNUNET_i2s (&pos->peer2->id)); | ||
267 | if (pos->peer2handle != NULL) | ||
268 | { | ||
269 | GNUNET_CORE_disconnect (pos->peer2handle); | ||
270 | pos->peer2handle = NULL; | ||
271 | } | ||
272 | pos->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
273 | /* Decrement total connections so new can be established */ | ||
274 | total_server_connections -= 2; | ||
275 | } | ||
276 | |||
277 | #if DO_STATS | ||
278 | static void | ||
279 | stats_finished (void *cls, int result) | ||
280 | { | ||
281 | GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * Callback function to process statistic values. | ||
286 | * | ||
287 | * @param cls closure | ||
288 | * @param peer the peer the statistics belong to | ||
289 | * @param subsystem name of subsystem that created the statistic | ||
290 | * @param name the name of the datum | ||
291 | * @param value the current value | ||
292 | * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not | ||
293 | * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration | ||
294 | */ | ||
295 | static int | ||
296 | stats_print (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
297 | const char *subsystem, const char *name, uint64_t value, | ||
298 | int is_persistent) | ||
299 | { | ||
300 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s:%s:%s -- %llu\n", GNUNET_i2s (peer), | ||
301 | subsystem, name, value); | ||
302 | return GNUNET_OK; | ||
303 | } | ||
304 | #endif | ||
305 | |||
306 | |||
307 | static void | ||
308 | topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, | ||
309 | const struct GNUNET_PeerIdentity *second, const char *emsg) | ||
310 | { | ||
311 | FILE *outfile = cls; | ||
312 | |||
313 | if (first != NULL) | ||
314 | { | ||
315 | if (outfile != NULL) | ||
316 | { | ||
317 | FPRINTF (outfile, "\t\"%s\" -- ", GNUNET_i2s (first)); | ||
318 | FPRINTF (outfile, "\"%s\";\n", GNUNET_i2s (second)); | ||
319 | } | ||
320 | topology_connections++; | ||
321 | } | ||
322 | else | ||
323 | { | ||
324 | FPRINTF (stderr, | ||
325 | "Finished iterating over topology, %d total connections!\n", | ||
326 | topology_connections); | ||
327 | if (outfile != NULL) | ||
328 | { | ||
329 | FPRINTF (outfile, "%s", "}\n"); | ||
330 | FCLOSE (outfile); | ||
331 | #if DO_STATS | ||
332 | GNUNET_TESTING_get_statistics (pg, &stats_finished, &stats_print, NULL); | ||
333 | #endif | ||
334 | GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | |||
340 | static int | ||
341 | process_mtype (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
342 | const struct GNUNET_MessageHeader *message, | ||
343 | const struct GNUNET_ATS_Information *atsi, | ||
344 | unsigned int atsi_count) | ||
345 | { | ||
346 | char *dotOutFileNameFinished; | ||
347 | FILE *dotOutFileFinished; | ||
348 | struct TestMessageContext *pos = cls; | ||
349 | struct GNUNET_TestMessage *msg = (struct GNUNET_TestMessage *) message; | ||
350 | |||
351 | if (pos->uid != ntohl (msg->uid)) | ||
352 | return GNUNET_OK; | ||
353 | |||
354 | #if PROGRESS_BARS | ||
355 | if ((total_messages_received) % modnum == 0) | ||
356 | { | ||
357 | if (total_messages_received == 0) | ||
358 | FPRINTF (stdout, "%s", "0%%"); | ||
359 | else | ||
360 | FPRINTF (stdout, "%d%%", | ||
361 | (int) (((float) total_messages_received / expected_messages) * | ||
362 | 100)); | ||
363 | |||
364 | } | ||
365 | else if (total_messages_received % dotnum == 0) | ||
366 | { | ||
367 | FPRINTF (stdout, "%s", "."); | ||
368 | } | ||
369 | fflush (stdout); | ||
370 | #endif | ||
371 | |||
372 | total_messages_received++; | ||
373 | |||
374 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
375 | "Received message from `%4s', type %d.\n", GNUNET_i2s (peer), | ||
376 | ntohs (message->type)); | ||
377 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
378 | "Total messages received %d, expected %d.\n", | ||
379 | total_messages_received, expected_messages); | ||
380 | |||
381 | if (total_messages_received == expected_messages) | ||
382 | { | ||
383 | #if PROGRESS_BARS | ||
384 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
385 | #endif | ||
386 | GNUNET_SCHEDULER_cancel (die_task); | ||
387 | GNUNET_asprintf (&dotOutFileNameFinished, "%s.dot", "final_topology"); | ||
388 | dotOutFileFinished = FOPEN (dotOutFileNameFinished, "w"); | ||
389 | GNUNET_free (dotOutFileNameFinished); | ||
390 | if (dotOutFileFinished != NULL) | ||
391 | { | ||
392 | FPRINTF (dotOutFileFinished, "%s", "strict graph G {\n"); | ||
393 | } | ||
394 | topology_connections = 0; | ||
395 | GNUNET_TESTING_get_topology (pg, &topology_cb, dotOutFileFinished); | ||
396 | //GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
397 | } | ||
398 | else | ||
399 | { | ||
400 | pos->disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cores, pos); | ||
401 | } | ||
402 | |||
403 | return GNUNET_OK; | ||
404 | } | ||
405 | |||
406 | |||
407 | static void | ||
408 | end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
409 | { | ||
410 | char *msg = cls; | ||
411 | |||
412 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
413 | "Ending with error: %s\n", msg); | ||
414 | struct TestMessageContext *pos; | ||
415 | struct TestMessageContext *free_pos; | ||
416 | |||
417 | pos = test_messages; | ||
418 | while (pos != NULL) | ||
419 | { | ||
420 | if (pos->peer1handle != NULL) | ||
421 | { | ||
422 | GNUNET_CORE_disconnect (pos->peer1handle); | ||
423 | pos->peer1handle = NULL; | ||
424 | } | ||
425 | if (pos->peer2handle != NULL) | ||
426 | { | ||
427 | GNUNET_CORE_disconnect (pos->peer2handle); | ||
428 | pos->peer2handle = NULL; | ||
429 | } | ||
430 | free_pos = pos; | ||
431 | pos = pos->next; | ||
432 | GNUNET_free (free_pos); | ||
433 | } | ||
434 | |||
435 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
436 | "Transmit_ready's scheduled %d, failed %d, transmit_ready's called %d\n", | ||
437 | transmit_ready_scheduled, transmit_ready_failed, | ||
438 | transmit_ready_called); | ||
439 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
440 | "Total messages received %d, expected %d.\n", | ||
441 | total_messages_received, expected_messages); | ||
442 | |||
443 | if (pg != NULL) | ||
444 | { | ||
445 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
446 | ok = 7331; /* Opposite of leet */ | ||
447 | } | ||
448 | else | ||
449 | ok = 401; /* Never got peers started */ | ||
450 | |||
451 | if (dotOutFile != NULL) | ||
452 | { | ||
453 | FPRINTF (dotOutFile, "%s", "}"); | ||
454 | FCLOSE (dotOutFile); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | |||
459 | static size_t | ||
460 | transmit_ready (void *cls, size_t size, void *buf) | ||
461 | { | ||
462 | struct GNUNET_TestMessage *m; | ||
463 | struct TestMessageContext *pos = cls; | ||
464 | |||
465 | GNUNET_assert (buf != NULL); | ||
466 | m = (struct GNUNET_TestMessage *) buf; | ||
467 | m->header.type = htons (MTYPE); | ||
468 | m->header.size = htons (sizeof (struct GNUNET_TestMessage)); | ||
469 | m->uid = htonl (pos->uid); | ||
470 | transmit_ready_called++; | ||
471 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
472 | "transmit ready for peer %s\ntransmit_ready's scheduled %d, transmit_ready's called %d\n", | ||
473 | GNUNET_i2s (&pos->peer1->id), transmit_ready_scheduled, | ||
474 | transmit_ready_called); | ||
475 | return sizeof (struct GNUNET_TestMessage); | ||
476 | } | ||
477 | |||
478 | |||
479 | static struct GNUNET_CORE_MessageHandler no_handlers[] = { | ||
480 | {NULL, 0, 0} | ||
481 | }; | ||
482 | |||
483 | |||
484 | static struct GNUNET_CORE_MessageHandler handlers[] = { | ||
485 | {&process_mtype, MTYPE, sizeof (struct GNUNET_TestMessage)}, | ||
486 | {NULL, 0, 0} | ||
487 | }; | ||
488 | |||
489 | |||
490 | static void | ||
491 | init_notify_peer2 (void *cls, struct GNUNET_CORE_Handle *server, | ||
492 | const struct GNUNET_PeerIdentity *my_identity) | ||
493 | { | ||
494 | struct TestMessageContext *pos = cls; | ||
495 | |||
496 | total_server_connections++; | ||
497 | |||
498 | pos->peer2connected = GNUNET_YES; | ||
499 | if (pos->peer1notified == GNUNET_YES) /* Peer 1 has been notified of connection to peer 2 */ | ||
500 | { | ||
501 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
502 | "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", | ||
503 | GNUNET_i2s (my_identity), | ||
504 | GNUNET_h2s (&pos->peer1->id.hashPubKey)); | ||
505 | if (NULL == | ||
506 | GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, | ||
507 | TIMEOUT, &pos->peer2->id, | ||
508 | sizeof (struct GNUNET_TestMessage), | ||
509 | &transmit_ready, pos)) | ||
510 | { | ||
511 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
512 | "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", | ||
513 | GNUNET_i2s (&pos->peer2->id)); | ||
514 | transmit_ready_failed++; | ||
515 | } | ||
516 | else | ||
517 | { | ||
518 | transmit_ready_scheduled++; | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | |||
524 | /** | ||
525 | * Method called whenever a given peer connects. | ||
526 | * | ||
527 | * @param cls closure | ||
528 | * @param peer peer identity this notification is about | ||
529 | * @param atsi performance data for the connection | ||
530 | * @param atsi_count number of records in 'atsi' | ||
531 | */ | ||
532 | static void | ||
533 | connect_notify_peers (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
534 | const struct GNUNET_ATS_Information *atsi, | ||
535 | unsigned int atsi_count) | ||
536 | { | ||
537 | struct TestMessageContext *pos = cls; | ||
538 | |||
539 | if (0 == memcmp (peer, &pos->peer2->id, sizeof (struct GNUNET_PeerIdentity))) | ||
540 | { | ||
541 | pos->peer1notified = GNUNET_YES; | ||
542 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
543 | "Peer `%s' notified of connection to peer `%s'\n", | ||
544 | GNUNET_i2s (&pos->peer1->id), GNUNET_h2s (&peer->hashPubKey)); | ||
545 | } | ||
546 | else | ||
547 | return; | ||
548 | |||
549 | if (pos->peer2connected == GNUNET_YES) /* Already connected and notified of connection, send message! */ | ||
550 | { | ||
551 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
552 | "Scheduling message send to peer `%s' from peer `%s' (init_notify_peer2)\n", | ||
553 | GNUNET_i2s (&pos->peer2->id), | ||
554 | GNUNET_h2s (&pos->peer1->id.hashPubKey)); | ||
555 | if (NULL == | ||
556 | GNUNET_CORE_notify_transmit_ready (pos->peer1handle, GNUNET_YES, 0, | ||
557 | TIMEOUT, &pos->peer2->id, | ||
558 | sizeof (struct GNUNET_TestMessage), | ||
559 | &transmit_ready, pos)) | ||
560 | { | ||
561 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
562 | "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n", | ||
563 | GNUNET_i2s (&pos->peer2->id)); | ||
564 | transmit_ready_failed++; | ||
565 | } | ||
566 | else | ||
567 | { | ||
568 | transmit_ready_scheduled++; | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | |||
573 | |||
574 | static void | ||
575 | init_notify_peer1 (void *cls, struct GNUNET_CORE_Handle *server, | ||
576 | const struct GNUNET_PeerIdentity *my_identity) | ||
577 | { | ||
578 | struct TestMessageContext *pos = cls; | ||
579 | |||
580 | total_server_connections++; | ||
581 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
582 | "Core connection to `%4s' established, setting up handles\n", | ||
583 | GNUNET_i2s (my_identity)); | ||
584 | /* | ||
585 | * Connect to the receiving peer | ||
586 | */ | ||
587 | pos->peer2handle = | ||
588 | GNUNET_CORE_connect (pos->peer2->cfg, pos, &init_notify_peer2, NULL, | ||
589 | NULL, NULL, GNUNET_YES, NULL, GNUNET_YES, handlers); | ||
590 | |||
591 | } | ||
592 | |||
593 | |||
594 | static void | ||
595 | send_test_messages (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
596 | { | ||
597 | struct TestMessageContext *pos = cls; | ||
598 | |||
599 | if ((pos == test_messages) && (settle_time.rel_value > 0)) | ||
600 | { | ||
601 | topology_connections = 0; | ||
602 | GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); | ||
603 | } | ||
604 | if (((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) || (cls == NULL)) | ||
605 | return; | ||
606 | |||
607 | if (die_task == GNUNET_SCHEDULER_NO_TASK) | ||
608 | { | ||
609 | die_task = | ||
610 | GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, | ||
611 | "from send test messages (timeout)"); | ||
612 | } | ||
613 | |||
614 | if (total_server_connections >= MAX_OUTSTANDING_CONNECTIONS) | ||
615 | { | ||
616 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
617 | (GNUNET_TIME_UNIT_SECONDS, 1), | ||
618 | &send_test_messages, pos); | ||
619 | return; /* Otherwise we'll double schedule messages here! */ | ||
620 | } | ||
621 | |||
622 | /* | ||
623 | * Connect to the sending peer | ||
624 | */ | ||
625 | pos->peer1handle = | ||
626 | GNUNET_CORE_connect (pos->peer1->cfg, pos, &init_notify_peer1, | ||
627 | &connect_notify_peers, NULL, NULL, GNUNET_NO, NULL, | ||
628 | GNUNET_NO, no_handlers); | ||
629 | |||
630 | GNUNET_assert (pos->peer1handle != NULL); | ||
631 | |||
632 | if (total_server_connections < MAX_OUTSTANDING_CONNECTIONS) | ||
633 | { | ||
634 | GNUNET_SCHEDULER_add_now (&send_test_messages, pos->next); | ||
635 | } | ||
636 | else | ||
637 | { | ||
638 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
639 | (GNUNET_TIME_UNIT_SECONDS, 1), | ||
640 | &send_test_messages, pos->next); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | |||
645 | static void | ||
646 | topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, | ||
647 | const struct GNUNET_PeerIdentity *second, uint32_t distance, | ||
648 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
649 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
650 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
651 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
652 | const char *emsg) | ||
653 | { | ||
654 | struct TestMessageContext *temp_context; | ||
655 | |||
656 | if (emsg == NULL) | ||
657 | { | ||
658 | #if PROGRESS_BARS | ||
659 | if ((total_connections) % modnum == 0) | ||
660 | { | ||
661 | if (total_connections == 0) | ||
662 | FPRINTF (stdout, "%s", "0%%"); | ||
663 | else | ||
664 | FPRINTF (stdout, "%d%%", | ||
665 | (int) (((float) total_connections / expected_connections) * | ||
666 | 100)); | ||
667 | |||
668 | } | ||
669 | else if (total_connections % dotnum == 0) | ||
670 | { | ||
671 | FPRINTF (stdout, "%s", "."); | ||
672 | } | ||
673 | fflush (stdout); | ||
674 | #endif | ||
675 | total_connections++; | ||
676 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "connected peer %s to peer %s\n", | ||
677 | first_daemon->shortname, second_daemon->shortname); | ||
678 | temp_context = GNUNET_malloc (sizeof (struct TestMessageContext)); | ||
679 | temp_context->peer1 = first_daemon; | ||
680 | temp_context->peer2 = second_daemon; | ||
681 | temp_context->next = test_messages; | ||
682 | temp_context->uid = total_connections; | ||
683 | temp_context->disconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
684 | test_messages = temp_context; | ||
685 | |||
686 | expected_messages++; | ||
687 | if (dotOutFile != NULL) | ||
688 | FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, | ||
689 | second_daemon->shortname); | ||
690 | } | ||
691 | else | ||
692 | { | ||
693 | failed_connections++; | ||
694 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
695 | "Failed to connect peer %s to peer %s with error :\n%s\n", | ||
696 | first_daemon->shortname, second_daemon->shortname, emsg); | ||
697 | } | ||
698 | |||
699 | if (total_connections == expected_connections) | ||
700 | { | ||
701 | #if PROGRESS_BARS | ||
702 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
703 | #endif | ||
704 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
705 | "Created %d total connections, which is our target number! Calling send messages.\n", | ||
706 | total_connections); | ||
707 | modnum = expected_messages / 4; | ||
708 | dotnum = (expected_messages / 50) + 1; | ||
709 | if (modnum == 0) | ||
710 | modnum = 1; | ||
711 | if (dotnum == 0) | ||
712 | dotnum = 1; | ||
713 | GNUNET_SCHEDULER_cancel (die_task); | ||
714 | die_task = GNUNET_SCHEDULER_NO_TASK; | ||
715 | #if DELAY_FOR_LOGGING | ||
716 | FPRINTF (stdout, "%s", "Sending test messages in 10 seconds.\n"); | ||
717 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
718 | (GNUNET_TIME_UNIT_SECONDS, 10), | ||
719 | &send_test_messages, test_messages); | ||
720 | gather_log_data (); | ||
721 | #else | ||
722 | if (settle_time.rel_value > 0) | ||
723 | { | ||
724 | GNUNET_TESTING_get_topology (pg, &topology_cb, NULL); | ||
725 | } | ||
726 | GNUNET_SCHEDULER_add_delayed (settle_time, &send_test_messages, | ||
727 | test_messages); | ||
728 | #endif | ||
729 | #if PROGRESS_BARS | ||
730 | FPRINTF (stdout, "%s", "Test message progress: ["); | ||
731 | #endif | ||
732 | |||
733 | } | ||
734 | else if (total_connections + failed_connections == expected_connections) | ||
735 | { | ||
736 | if (failed_connections < | ||
737 | (unsigned int) (fail_percentage * total_connections)) | ||
738 | { | ||
739 | GNUNET_SCHEDULER_cancel (die_task); | ||
740 | die_task = GNUNET_SCHEDULER_NO_TASK; | ||
741 | GNUNET_SCHEDULER_add_now (&send_test_messages, test_messages); | ||
742 | } | ||
743 | else | ||
744 | { | ||
745 | GNUNET_SCHEDULER_cancel (die_task); | ||
746 | die_task = | ||
747 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
748 | "from topology_callback (too many failed connections)"); | ||
749 | } | ||
750 | } | ||
751 | else | ||
752 | { | ||
753 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
754 | "Have %d total connections, %d failed connections, Want %d (at least %d)\n", | ||
755 | total_connections, failed_connections, expected_connections, | ||
756 | expected_connections - | ||
757 | (unsigned int) (fail_percentage * expected_connections)); | ||
758 | } | ||
759 | } | ||
760 | |||
761 | |||
762 | static void | ||
763 | topology_creation_finished (void *cls, const char *emsg) | ||
764 | { | ||
765 | if (emsg == NULL) | ||
766 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
767 | "All topology connections created successfully!\n"); | ||
768 | } | ||
769 | |||
770 | |||
771 | static void | ||
772 | connect_topology () | ||
773 | { | ||
774 | expected_connections = -1; | ||
775 | if ((pg != NULL) && (peers_left == 0)) | ||
776 | { | ||
777 | expected_connections = | ||
778 | GNUNET_TESTING_connect_topology (pg, connection_topology, | ||
779 | connect_topology_option, | ||
780 | connect_topology_option_modifier, | ||
781 | connect_timeout, connect_attempts, | ||
782 | &topology_creation_finished, NULL); | ||
783 | #if PROGRESS_BARS | ||
784 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", | ||
785 | expected_connections); | ||
786 | #endif | ||
787 | } | ||
788 | |||
789 | GNUNET_SCHEDULER_cancel (die_task); | ||
790 | if (expected_connections < 1) | ||
791 | { | ||
792 | die_task = | ||
793 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
794 | "from connect topology (bad return)"); | ||
795 | return; | ||
796 | } | ||
797 | |||
798 | die_task = | ||
799 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
800 | (GNUNET_TIME_UNIT_SECONDS, | ||
801 | SECONDS_PER_PEER_START * num_peers), | ||
802 | &end_badly, | ||
803 | "from connect topology (timeout)"); | ||
804 | modnum = expected_connections / 4; | ||
805 | dotnum = (expected_connections / 50) + 1; | ||
806 | if (modnum == 0) | ||
807 | modnum = 1; | ||
808 | if (dotnum == 0) | ||
809 | dotnum = 1; | ||
810 | #if PROGRESS_BARS | ||
811 | FPRINTF (stdout, "%s", "Peer connection progress: ["); | ||
812 | #endif | ||
813 | } | ||
814 | |||
815 | static void | ||
816 | create_topology () | ||
817 | { | ||
818 | peers_left = num_peers; /* Reset counter */ | ||
819 | if (GNUNET_TESTING_create_topology | ||
820 | (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) | ||
821 | { | ||
822 | #if PROGRESS_BARS | ||
823 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
824 | "Topology set up, now starting peers!\n"); | ||
825 | FPRINTF (stdout, "%s", "Daemon start progress ["); | ||
826 | #endif | ||
827 | GNUNET_TESTING_daemons_continue_startup (pg); | ||
828 | } | ||
829 | else | ||
830 | { | ||
831 | GNUNET_SCHEDULER_cancel (die_task); | ||
832 | die_task = | ||
833 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
834 | "from create topology (bad return)"); | ||
835 | } | ||
836 | GNUNET_SCHEDULER_cancel (die_task); | ||
837 | die_task = | ||
838 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
839 | (GNUNET_TIME_UNIT_SECONDS, | ||
840 | SECONDS_PER_PEER_START * num_peers), | ||
841 | &end_badly, | ||
842 | "from continue startup (timeout)"); | ||
843 | } | ||
844 | |||
845 | |||
846 | static void | ||
847 | peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
848 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
849 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
850 | { | ||
851 | if (emsg != NULL) | ||
852 | { | ||
853 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
854 | "Failed to start daemon with error: `%s'\n", emsg); | ||
855 | return; | ||
856 | } | ||
857 | GNUNET_assert (id != NULL); | ||
858 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", | ||
859 | (num_peers - peers_left) + 1, num_peers); | ||
860 | #if PROGRESS_BARS | ||
861 | if ((num_peers - peers_left) % modnum == 0) | ||
862 | { | ||
863 | if (num_peers - peers_left == 0) | ||
864 | FPRINTF (stdout, "%s", "0%%"); | ||
865 | else | ||
866 | FPRINTF (stdout, "%d%%", | ||
867 | (int) (((float) (num_peers - peers_left) / num_peers) * 100)); | ||
868 | |||
869 | } | ||
870 | else if ((num_peers - peers_left) % dotnum == 0) | ||
871 | { | ||
872 | FPRINTF (stdout, "%s", "."); | ||
873 | } | ||
874 | fflush (stdout); | ||
875 | #endif | ||
876 | peers_left--; | ||
877 | if (peers_left == 0) | ||
878 | { | ||
879 | #if PROGRESS_BARS | ||
880 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
881 | #endif | ||
882 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
883 | "All %d daemons started, now connecting peers!\n", num_peers); | ||
884 | GNUNET_SCHEDULER_cancel (die_task); | ||
885 | /* Set up task in case topology creation doesn't finish | ||
886 | * within a reasonable amount of time */ | ||
887 | die_task = | ||
888 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
889 | (GNUNET_TIME_UNIT_MINUTES, 8), &end_badly, | ||
890 | "from peers_started_callback"); | ||
891 | #if DELAY_FOR_LOGGING | ||
892 | FPRINTF (stdout, "%s", "Connecting topology in 10 seconds\n"); | ||
893 | gather_log_data (); | ||
894 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
895 | (GNUNET_TIME_UNIT_SECONDS, 10), | ||
896 | &connect_topology, NULL); | ||
897 | #else | ||
898 | connect_topology (); | ||
899 | #endif | ||
900 | ok = 0; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | /** | ||
905 | * Callback indicating that the hostkey was created for a peer. | ||
906 | * | ||
907 | * @param cls NULL | ||
908 | * @param id the peer identity | ||
909 | * @param d the daemon handle (pretty useless at this point, remove?) | ||
910 | * @param emsg non-null on failure | ||
911 | */ | ||
912 | void | ||
913 | hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
914 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
915 | { | ||
916 | if (emsg != NULL) | ||
917 | { | ||
918 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
919 | "Hostkey callback received error: %s\n", emsg); | ||
920 | } | ||
921 | |||
922 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
923 | "Hostkey (%d/%d) created for peer `%s'\n", num_peers - peers_left, | ||
924 | num_peers, GNUNET_i2s (id)); | ||
925 | #if PROGRESS_BARS | ||
926 | if ((num_peers - peers_left) % modnum == 0) | ||
927 | { | ||
928 | if (num_peers - peers_left == 0) | ||
929 | FPRINTF (stdout, "%s", "0%%"); | ||
930 | else | ||
931 | FPRINTF (stdout, "%d%%", | ||
932 | (int) (((float) (num_peers - peers_left) / num_peers) * 100)); | ||
933 | |||
934 | } | ||
935 | else if ((num_peers - peers_left) % dotnum == 0) | ||
936 | { | ||
937 | FPRINTF (stdout, "%s", "."); | ||
938 | } | ||
939 | fflush (stdout); | ||
940 | #endif | ||
941 | peers_left--; | ||
942 | if (peers_left == 0) | ||
943 | { | ||
944 | #if PROGRESS_BARS | ||
945 | FPRINTF (stdout, "%s", "100%%]\n"); | ||
946 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
947 | "All %d hostkeys created, now creating topology!\n", num_peers); | ||
948 | #endif | ||
949 | GNUNET_SCHEDULER_cancel (die_task); | ||
950 | /* Set up task in case topology creation doesn't finish | ||
951 | * within a reasonable amount of time */ | ||
952 | die_task = | ||
953 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, | ||
954 | "from create_topology"); | ||
955 | GNUNET_SCHEDULER_add_now (&create_topology, NULL); | ||
956 | ok = 0; | ||
957 | } | ||
958 | } | ||
959 | |||
960 | |||
961 | static void | ||
962 | run (void *cls, char *const *args, const char *cfgfile, | ||
963 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
964 | { | ||
965 | char *topology_str; | ||
966 | char *connect_topology_str; | ||
967 | char *blacklist_topology_str; | ||
968 | char *connect_topology_option_str; | ||
969 | char *connect_topology_option_modifier_string; | ||
970 | unsigned long long max_outstanding_connections; | ||
971 | |||
972 | ok = 1; | ||
973 | |||
974 | dotOutFile = FOPEN (dotOutFileName, "w"); | ||
975 | if (dotOutFile != NULL) | ||
976 | { | ||
977 | FPRINTF (dotOutFile, "%s", "strict graph G {\n"); | ||
978 | } | ||
979 | |||
980 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
981 | "Starting daemons based on config file %s\n", cfgfile); | ||
982 | if (GNUNET_YES != | ||
983 | GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", | ||
984 | &test_directory)) | ||
985 | { | ||
986 | ok = 404; | ||
987 | return; | ||
988 | } | ||
989 | |||
990 | if ((GNUNET_YES == | ||
991 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", | ||
992 | &topology_str)) && | ||
993 | (GNUNET_NO == GNUNET_TESTING_topology_get (&topology, topology_str))) | ||
994 | { | ||
995 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
996 | "Invalid topology `%s' given for section %s option %s\n", | ||
997 | topology_str, "TESTING", "TOPOLOGY"); | ||
998 | topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ | ||
999 | } | ||
1000 | |||
1001 | if ((GNUNET_YES == | ||
1002 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1003 | "connect_topology", | ||
1004 | &connect_topology_str)) && | ||
1005 | (GNUNET_NO == | ||
1006 | GNUNET_TESTING_topology_get (&connection_topology, | ||
1007 | connect_topology_str))) | ||
1008 | { | ||
1009 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1010 | "Invalid connect topology `%s' given for section %s option %s\n", | ||
1011 | connect_topology_str, "TESTING", "CONNECT_TOPOLOGY"); | ||
1012 | } | ||
1013 | GNUNET_free_non_null (connect_topology_str); | ||
1014 | if ((GNUNET_YES == | ||
1015 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1016 | "connect_topology_option", | ||
1017 | &connect_topology_option_str)) && | ||
1018 | (GNUNET_NO == | ||
1019 | GNUNET_TESTING_topology_option_get (&connect_topology_option, | ||
1020 | connect_topology_option_str))) | ||
1021 | { | ||
1022 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1023 | "Invalid connect topology option `%s' given for section %s option %s\n", | ||
1024 | connect_topology_option_str, "TESTING", | ||
1025 | "CONNECT_TOPOLOGY_OPTION"); | ||
1026 | connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ | ||
1027 | } | ||
1028 | GNUNET_free_non_null (connect_topology_option_str); | ||
1029 | if (GNUNET_YES == | ||
1030 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1031 | "connect_topology_option_modifier", | ||
1032 | &connect_topology_option_modifier_string)) | ||
1033 | { | ||
1034 | if (SSCANF | ||
1035 | (connect_topology_option_modifier_string, "%lf", | ||
1036 | &connect_topology_option_modifier) != 1) | ||
1037 | { | ||
1038 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1039 | _ | ||
1040 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
1041 | connect_topology_option_modifier_string, | ||
1042 | "connect_topology_option_modifier", "TESTING"); | ||
1043 | } | ||
1044 | GNUNET_free (connect_topology_option_modifier_string); | ||
1045 | } | ||
1046 | |||
1047 | if (GNUNET_YES != | ||
1048 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1049 | "blacklist_transports", | ||
1050 | &blacklist_transports)) | ||
1051 | blacklist_transports = NULL; | ||
1052 | |||
1053 | if ((GNUNET_YES == | ||
1054 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
1055 | "blacklist_topology", | ||
1056 | &blacklist_topology_str)) && | ||
1057 | (GNUNET_NO == | ||
1058 | GNUNET_TESTING_topology_get (&blacklist_topology, | ||
1059 | blacklist_topology_str))) | ||
1060 | { | ||
1061 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1062 | "Invalid topology `%s' given for section %s option %s\n", | ||
1063 | topology_str, "TESTING", "BLACKLIST_TOPOLOGY"); | ||
1064 | } | ||
1065 | GNUNET_free_non_null (topology_str); | ||
1066 | GNUNET_free_non_null (blacklist_topology_str); | ||
1067 | |||
1068 | if (GNUNET_OK != | ||
1069 | GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "SETTLE_TIME", | ||
1070 | &settle_time)) | ||
1071 | { | ||
1072 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
1073 | "testing", "SETTLE_TIME"); | ||
1074 | return; | ||
1075 | } | ||
1076 | |||
1077 | if (GNUNET_OK != | ||
1078 | GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", | ||
1079 | &connect_timeout)) | ||
1080 | { | ||
1081 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
1082 | "testing", "CONNECT_TIMEOUT"); | ||
1083 | return; | ||
1084 | } | ||
1085 | |||
1086 | |||
1087 | if (GNUNET_OK != | ||
1088 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", | ||
1089 | &connect_attempts)) | ||
1090 | { | ||
1091 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
1092 | "testing", "connect_attempts"); | ||
1093 | return; | ||
1094 | } | ||
1095 | |||
1096 | if (GNUNET_OK != | ||
1097 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", | ||
1098 | "max_outstanding_connections", | ||
1099 | &max_outstanding_connections)) | ||
1100 | { | ||
1101 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
1102 | "testing", "max_outstanding_connections"); | ||
1103 | return; | ||
1104 | } | ||
1105 | |||
1106 | if (GNUNET_SYSERR == | ||
1107 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", | ||
1108 | &num_peers)) | ||
1109 | num_peers = DEFAULT_NUM_PEERS; | ||
1110 | |||
1111 | main_cfg = cfg; | ||
1112 | |||
1113 | peers_left = num_peers; | ||
1114 | modnum = num_peers / 4; | ||
1115 | dotnum = (num_peers / 50) + 1; | ||
1116 | if (modnum == 0) | ||
1117 | modnum = 1; | ||
1118 | if (dotnum == 0) | ||
1119 | dotnum = 1; | ||
1120 | #if PROGRESS_BARS | ||
1121 | FPRINTF (stdout, "%s", "Hostkey generation progress: ["); | ||
1122 | #endif | ||
1123 | /* Set up a task to end testing if peer start fails */ | ||
1124 | die_task = | ||
1125 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
1126 | (GNUNET_TIME_UNIT_SECONDS, | ||
1127 | SECONDS_PER_PEER_START * num_peers), | ||
1128 | &end_badly, | ||
1129 | "didn't generate all hostkeys within a reasonable amount of time!!!"); | ||
1130 | |||
1131 | GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); | ||
1132 | pg = GNUNET_TESTING_daemons_start (cfg, peers_left, | ||
1133 | max_outstanding_connections, peers_left, | ||
1134 | GNUNET_TIME_relative_multiply | ||
1135 | (GNUNET_TIME_UNIT_SECONDS, | ||
1136 | SECONDS_PER_PEER_START * num_peers), | ||
1137 | &hostkey_callback, NULL, | ||
1138 | &peers_started_callback, NULL, | ||
1139 | &topology_callback, NULL, NULL); | ||
1140 | |||
1141 | } | ||
1142 | |||
1143 | |||
1144 | static int | ||
1145 | check () | ||
1146 | { | ||
1147 | char *binary_name; | ||
1148 | char *config_file_name; | ||
1149 | |||
1150 | GNUNET_asprintf (&binary_name, "test-testing-topology-%s", topology_string); | ||
1151 | GNUNET_asprintf (&config_file_name, "test_testing_data_topology_%s.conf", | ||
1152 | topology_string); | ||
1153 | int ret; | ||
1154 | |||
1155 | char *const argv[] = { binary_name, | ||
1156 | "-c", | ||
1157 | config_file_name, | ||
1158 | NULL | ||
1159 | }; | ||
1160 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1161 | GNUNET_GETOPT_OPTION_END | ||
1162 | }; | ||
1163 | ret = | ||
1164 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
1165 | binary_name, "nohelp", options, &run, &ok); | ||
1166 | if (ret != GNUNET_OK) | ||
1167 | { | ||
1168 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1169 | "`test-testing-topology-%s': Failed with error code %d\n", | ||
1170 | topology_string, ret); | ||
1171 | } | ||
1172 | GNUNET_free (binary_name); | ||
1173 | GNUNET_free (config_file_name); | ||
1174 | return ok; | ||
1175 | } | ||
1176 | |||
1177 | |||
1178 | int | ||
1179 | main (int argc, char *argv[]) | ||
1180 | { | ||
1181 | int ret; | ||
1182 | char *binary_start_pos; | ||
1183 | char *our_binary_name; | ||
1184 | char *dotexe; | ||
1185 | |||
1186 | binary_start_pos = strchr (argv[0], '/'); | ||
1187 | GNUNET_assert (binary_start_pos != NULL); | ||
1188 | topology_string = strstr (binary_start_pos, "_topology"); | ||
1189 | GNUNET_assert (topology_string != NULL); | ||
1190 | topology_string++; | ||
1191 | topology_string = strstr (topology_string, "_"); | ||
1192 | GNUNET_assert (topology_string != NULL); | ||
1193 | topology_string++; | ||
1194 | topology_string = GNUNET_strdup (topology_string); | ||
1195 | if (NULL != (dotexe = strstr (topology_string, ".exe"))) | ||
1196 | dotexe[0] = '\0'; | ||
1197 | GNUNET_asprintf (&our_binary_name, "test-testing-topology_%s", | ||
1198 | topology_string); | ||
1199 | GNUNET_asprintf (&dotOutFileName, "topology_%s.dot", topology_string); | ||
1200 | |||
1201 | GNUNET_log_setup (our_binary_name, | ||
1202 | "WARNING", | ||
1203 | NULL); | ||
1204 | ret = check (); | ||
1205 | GNUNET_free (topology_string); | ||
1206 | |||
1207 | /** | ||
1208 | * Need to remove base directory, subdirectories taken care | ||
1209 | * of by the testing framework. | ||
1210 | */ | ||
1211 | if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) | ||
1212 | { | ||
1213 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1214 | "Failed to remove testing directory %s\n", test_directory); | ||
1215 | } | ||
1216 | GNUNET_free (our_binary_name); | ||
1217 | return ret; | ||
1218 | } | ||
1219 | |||
1220 | /* end of test_testing_topology.c */ | ||
diff --git a/src/testing/test_testing_topology_blacklist.c b/src/testing/test_testing_topology_blacklist.c deleted file mode 100644 index c90f48d9b..000000000 --- a/src/testing/test_testing_topology_blacklist.c +++ /dev/null | |||
@@ -1,595 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_topology_blacklist.c | ||
22 | * @brief base testcase for testing transport level blacklisting | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | #include "gnunet_core_service.h" | ||
27 | |||
28 | #define VERBOSE GNUNET_NO | ||
29 | |||
30 | /** | ||
31 | * How long until we fail the whole testcase? | ||
32 | */ | ||
33 | #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) | ||
34 | |||
35 | /** | ||
36 | * How long until we give up on starting the peers? (Must be longer than the connect timeout!) | ||
37 | */ | ||
38 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
39 | |||
40 | #define DEFAULT_NUM_PEERS 4 | ||
41 | |||
42 | #define MAX_OUTSTANDING_CONNECTIONS 300 | ||
43 | |||
44 | static int ok; | ||
45 | |||
46 | struct GNUNET_TIME_Relative connect_timeout; | ||
47 | |||
48 | static unsigned long long connect_attempts; | ||
49 | |||
50 | static unsigned long long num_peers; | ||
51 | |||
52 | static unsigned int total_connections; | ||
53 | |||
54 | static unsigned int failed_connections; | ||
55 | |||
56 | static unsigned int expected_connections; | ||
57 | |||
58 | static unsigned int expected_failed_connections; | ||
59 | |||
60 | static unsigned long long peers_left; | ||
61 | |||
62 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
63 | |||
64 | const struct GNUNET_CONFIGURATION_Handle *main_cfg; | ||
65 | |||
66 | GNUNET_SCHEDULER_TaskIdentifier die_task; | ||
67 | |||
68 | static char *dotOutFileName; | ||
69 | |||
70 | static FILE *dotOutFile; | ||
71 | |||
72 | static char *blacklist_transports; | ||
73 | |||
74 | static enum GNUNET_TESTING_Topology topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Overlay should allow all connections */ | ||
75 | |||
76 | static enum GNUNET_TESTING_Topology blacklist_topology = GNUNET_TESTING_TOPOLOGY_RING; /* Blacklist underlay into a ring */ | ||
77 | |||
78 | static enum GNUNET_TESTING_Topology connection_topology = GNUNET_TESTING_TOPOLOGY_NONE; /* NONE actually means connect all allowed peers */ | ||
79 | |||
80 | static enum GNUNET_TESTING_TopologyOption connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Try to connect all possible OVERLAY connections */ | ||
81 | |||
82 | static double connect_topology_option_modifier = 0.0; | ||
83 | |||
84 | static char *test_directory; | ||
85 | |||
86 | #define MTYPE 12345 | ||
87 | |||
88 | GNUNET_NETWORK_STRUCT_BEGIN | ||
89 | |||
90 | struct GNUNET_TestMessage | ||
91 | { | ||
92 | /** | ||
93 | * Header of the message | ||
94 | */ | ||
95 | struct GNUNET_MessageHeader header; | ||
96 | |||
97 | /** | ||
98 | * Unique identifier for this message. | ||
99 | */ | ||
100 | uint32_t uid; | ||
101 | }; | ||
102 | GNUNET_NETWORK_STRUCT_END | ||
103 | |||
104 | /** | ||
105 | * Check whether peers successfully shut down. | ||
106 | */ | ||
107 | void | ||
108 | shutdown_callback (void *cls, const char *emsg) | ||
109 | { | ||
110 | if (emsg != NULL) | ||
111 | { | ||
112 | #if VERBOSE | ||
113 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); | ||
114 | #endif | ||
115 | if (ok == 0) | ||
116 | ok = 666; | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | #if VERBOSE | ||
121 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); | ||
122 | #endif | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static void | ||
127 | finish_testing () | ||
128 | { | ||
129 | GNUNET_assert (pg != NULL); | ||
130 | |||
131 | #if VERBOSE | ||
132 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
133 | "Called finish testing, stopping daemons.\n"); | ||
134 | #endif | ||
135 | sleep (1); | ||
136 | #if VERBOSE | ||
137 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); | ||
138 | #endif | ||
139 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
140 | #if VERBOSE | ||
141 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); | ||
142 | #endif | ||
143 | if (dotOutFile != NULL) | ||
144 | { | ||
145 | FPRINTF (dotOutFile, "%s", "}"); | ||
146 | FCLOSE (dotOutFile); | ||
147 | } | ||
148 | |||
149 | ok = 0; | ||
150 | } | ||
151 | |||
152 | static void | ||
153 | end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
154 | { | ||
155 | char *msg = cls; | ||
156 | |||
157 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
158 | "End badly was called (%s)... stopping daemons.\n", msg); | ||
159 | |||
160 | if (pg != NULL) | ||
161 | { | ||
162 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
163 | ok = 7331; /* Opposite of leet */ | ||
164 | } | ||
165 | else | ||
166 | ok = 401; /* Never got peers started */ | ||
167 | |||
168 | if (dotOutFile != NULL) | ||
169 | { | ||
170 | FPRINTF (dotOutFile, "%s", "}"); | ||
171 | FCLOSE (dotOutFile); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | |||
176 | |||
177 | void | ||
178 | topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, | ||
179 | const struct GNUNET_PeerIdentity *second, uint32_t distance, | ||
180 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
181 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
182 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
183 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
184 | const char *emsg) | ||
185 | { | ||
186 | if (emsg == NULL) | ||
187 | { | ||
188 | total_connections++; | ||
189 | #if VERBOSE | ||
190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connected peer %s to peer %s\n", | ||
191 | first_daemon->shortname, second_daemon->shortname); | ||
192 | #endif | ||
193 | if (dotOutFile != NULL) | ||
194 | FPRINTF (dotOutFile, "\tn%s -- n%s;\n", first_daemon->shortname, | ||
195 | second_daemon->shortname); | ||
196 | } | ||
197 | |||
198 | else | ||
199 | { | ||
200 | failed_connections++; | ||
201 | #if VERBOSE | ||
202 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
203 | "Failed to connect peer %s to peer %s with error :\n%s\n", | ||
204 | first_daemon->shortname, second_daemon->shortname, emsg); | ||
205 | #endif | ||
206 | } | ||
207 | |||
208 | |||
209 | if (total_connections == expected_connections) | ||
210 | { | ||
211 | #if VERBOSE | ||
212 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
213 | "Created %d total connections, which is our target number (that's bad)!\n", | ||
214 | total_connections); | ||
215 | #endif | ||
216 | |||
217 | GNUNET_SCHEDULER_cancel (die_task); | ||
218 | die_task = GNUNET_SCHEDULER_NO_TASK; | ||
219 | die_task = | ||
220 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
221 | "from topology_callback (too many successful connections)"); | ||
222 | } | ||
223 | else if (total_connections + failed_connections == expected_connections) | ||
224 | { | ||
225 | if ((failed_connections == expected_failed_connections) && | ||
226 | (total_connections == | ||
227 | expected_connections - expected_failed_connections)) | ||
228 | { | ||
229 | GNUNET_SCHEDULER_cancel (die_task); | ||
230 | die_task = GNUNET_SCHEDULER_NO_TASK; | ||
231 | die_task = GNUNET_SCHEDULER_add_now (&finish_testing, NULL); | ||
232 | } | ||
233 | else | ||
234 | { | ||
235 | GNUNET_SCHEDULER_cancel (die_task); | ||
236 | die_task = | ||
237 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
238 | "from topology_callback (wrong number of failed connections)"); | ||
239 | } | ||
240 | } | ||
241 | else | ||
242 | { | ||
243 | #if VERBOSE | ||
244 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
245 | "Have %d total connections, %d failed connections, Want %d (failed) and %d (successful)\n", | ||
246 | total_connections, failed_connections, | ||
247 | expected_failed_connections, | ||
248 | expected_connections - expected_failed_connections); | ||
249 | #endif | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static void | ||
254 | connect_topology () | ||
255 | { | ||
256 | expected_connections = -1; | ||
257 | if ((pg != NULL) && (peers_left == 0)) | ||
258 | { | ||
259 | expected_connections = | ||
260 | GNUNET_TESTING_connect_topology (pg, connection_topology, | ||
261 | connect_topology_option, | ||
262 | connect_topology_option_modifier, | ||
263 | connect_timeout, connect_attempts, | ||
264 | NULL, NULL); | ||
265 | #if VERBOSE | ||
266 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", | ||
267 | expected_connections); | ||
268 | #endif | ||
269 | } | ||
270 | |||
271 | GNUNET_SCHEDULER_cancel (die_task); | ||
272 | if (expected_connections == GNUNET_SYSERR) | ||
273 | { | ||
274 | die_task = | ||
275 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
276 | "from connect topology (bad return)"); | ||
277 | } | ||
278 | |||
279 | die_task = | ||
280 | GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, | ||
281 | "from connect topology (timeout)"); | ||
282 | } | ||
283 | |||
284 | static void | ||
285 | create_topology () | ||
286 | { | ||
287 | peers_left = num_peers; /* Reset counter */ | ||
288 | if (GNUNET_TESTING_create_topology | ||
289 | (pg, topology, blacklist_topology, blacklist_transports) != GNUNET_SYSERR) | ||
290 | { | ||
291 | #if VERBOSE | ||
292 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
293 | "Topology set up, now starting peers!\n"); | ||
294 | #endif | ||
295 | GNUNET_TESTING_daemons_continue_startup (pg); | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | GNUNET_SCHEDULER_cancel (die_task); | ||
300 | die_task = | ||
301 | GNUNET_SCHEDULER_add_now (&end_badly, | ||
302 | "from create topology (bad return)"); | ||
303 | } | ||
304 | GNUNET_SCHEDULER_cancel (die_task); | ||
305 | die_task = | ||
306 | GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &end_badly, | ||
307 | "from continue startup (timeout)"); | ||
308 | } | ||
309 | |||
310 | |||
311 | static void | ||
312 | peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
313 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
314 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
315 | { | ||
316 | if (emsg != NULL) | ||
317 | { | ||
318 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
319 | "Failed to start daemon with error: `%s'\n", emsg); | ||
320 | return; | ||
321 | } | ||
322 | GNUNET_assert (id != NULL); | ||
323 | #if VERBOSE | ||
324 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", | ||
325 | (num_peers - peers_left) + 1, num_peers); | ||
326 | #endif | ||
327 | peers_left--; | ||
328 | if (peers_left == 0) | ||
329 | { | ||
330 | #if VERBOSE | ||
331 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
332 | "All %d daemons started, now creating topology!\n", num_peers); | ||
333 | #endif | ||
334 | GNUNET_SCHEDULER_cancel (die_task); | ||
335 | /* Set up task in case topology creation doesn't finish | ||
336 | * within a reasonable amount of time */ | ||
337 | die_task = | ||
338 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
339 | (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, | ||
340 | "from peers_started_callback"); | ||
341 | connect_topology (); | ||
342 | ok = 0; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | /** | ||
347 | * Callback indicating that the hostkey was created for a peer. | ||
348 | * | ||
349 | * @param cls NULL | ||
350 | * @param id the peer identity | ||
351 | * @param d the daemon handle (pretty useless at this point, remove?) | ||
352 | * @param emsg non-null on failure | ||
353 | */ | ||
354 | void | ||
355 | hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
356 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
357 | { | ||
358 | if (emsg != NULL) | ||
359 | { | ||
360 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
361 | "Hostkey callback received error: %s\n", emsg); | ||
362 | } | ||
363 | |||
364 | #if VERBOSE | ||
365 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hostkey created for peer `%s'\n", | ||
366 | GNUNET_i2s (id)); | ||
367 | #endif | ||
368 | peers_left--; | ||
369 | if (peers_left == 0) | ||
370 | { | ||
371 | #if VERBOSE | ||
372 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
373 | "All %d hostkeys created, now creating topology!\n", num_peers); | ||
374 | #endif | ||
375 | GNUNET_SCHEDULER_cancel (die_task); | ||
376 | /* Set up task in case topology creation doesn't finish | ||
377 | * within a reasonable amount of time */ | ||
378 | die_task = | ||
379 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
380 | (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, | ||
381 | "from hostkey_callback"); | ||
382 | GNUNET_SCHEDULER_add_now (&create_topology, NULL); | ||
383 | ok = 0; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | static void | ||
388 | run (void *cls, char *const *args, const char *cfgfile, | ||
389 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
390 | { | ||
391 | unsigned long long topology_num; | ||
392 | unsigned long long connect_topology_num; | ||
393 | unsigned long long blacklist_topology_num; | ||
394 | unsigned long long connect_topology_option_num; | ||
395 | char *connect_topology_option_modifier_string; | ||
396 | |||
397 | ok = 1; | ||
398 | |||
399 | dotOutFile = FOPEN (dotOutFileName, "w"); | ||
400 | if (dotOutFile != NULL) | ||
401 | { | ||
402 | FPRINTF (dotOutFile, "%s", "strict graph G {\n"); | ||
403 | } | ||
404 | |||
405 | #if VERBOSE | ||
406 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
407 | "Starting daemons based on config file %s\n", cfgfile); | ||
408 | #endif | ||
409 | |||
410 | if (GNUNET_YES != | ||
411 | GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", | ||
412 | &test_directory)) | ||
413 | { | ||
414 | ok = 404; | ||
415 | if (dotOutFile != NULL) | ||
416 | { | ||
417 | FCLOSE (dotOutFile); | ||
418 | } | ||
419 | return; | ||
420 | } | ||
421 | |||
422 | if (GNUNET_YES == | ||
423 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "topology", | ||
424 | &topology_num)) | ||
425 | topology = topology_num; | ||
426 | |||
427 | if (GNUNET_YES == | ||
428 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_topology", | ||
429 | &connect_topology_num)) | ||
430 | connection_topology = connect_topology_num; | ||
431 | |||
432 | if (GNUNET_YES == | ||
433 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", | ||
434 | "connect_topology_option", | ||
435 | &connect_topology_option_num)) | ||
436 | connect_topology_option = connect_topology_option_num; | ||
437 | |||
438 | if (GNUNET_YES == | ||
439 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
440 | "connect_topology_option_modifier", | ||
441 | &connect_topology_option_modifier_string)) | ||
442 | { | ||
443 | if (SSCANF | ||
444 | (connect_topology_option_modifier_string, "%lf", | ||
445 | &connect_topology_option_modifier) != 1) | ||
446 | { | ||
447 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
448 | _ | ||
449 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
450 | connect_topology_option_modifier_string, | ||
451 | "connect_topology_option_modifier", "TESTING"); | ||
452 | GNUNET_free (connect_topology_option_modifier_string); | ||
453 | ok = 707; | ||
454 | if (dotOutFile != NULL) | ||
455 | { | ||
456 | FCLOSE (dotOutFile); | ||
457 | } | ||
458 | return; | ||
459 | } | ||
460 | GNUNET_free (connect_topology_option_modifier_string); | ||
461 | } | ||
462 | |||
463 | if (GNUNET_OK != | ||
464 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
465 | "blacklist_transports", | ||
466 | &blacklist_transports)) | ||
467 | { | ||
468 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
469 | "No transports specified for blacklisting in blacklist testcase (this shouldn't happen!)\n"); | ||
470 | ok = 808; | ||
471 | if (dotOutFile != NULL) | ||
472 | { | ||
473 | FCLOSE (dotOutFile); | ||
474 | } | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | if (GNUNET_YES == | ||
479 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", | ||
480 | "blacklist_topology", | ||
481 | &blacklist_topology_num)) | ||
482 | blacklist_topology = blacklist_topology_num; | ||
483 | |||
484 | if (GNUNET_SYSERR == | ||
485 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", | ||
486 | &num_peers)) | ||
487 | num_peers = DEFAULT_NUM_PEERS; | ||
488 | |||
489 | if (GNUNET_OK != | ||
490 | GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", | ||
491 | &connect_timeout)) | ||
492 | { | ||
493 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
494 | "testing", "CONNECT_TIMEOUT"); | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | |||
499 | if (GNUNET_OK != | ||
500 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", | ||
501 | &connect_attempts)) | ||
502 | { | ||
503 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
504 | "testing", "connect_attempts"); | ||
505 | return; | ||
506 | } | ||
507 | |||
508 | main_cfg = cfg; | ||
509 | |||
510 | GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); | ||
511 | peers_left = num_peers; | ||
512 | |||
513 | /* For this specific test we only really want a CLIQUE topology as the | ||
514 | * overlay allowed topology, and a RING topology as the underlying connection | ||
515 | * allowed topology. So we will expect only num_peers * 2 connections to | ||
516 | * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. | ||
517 | */ | ||
518 | expected_connections = num_peers * (num_peers - 1); | ||
519 | expected_failed_connections = expected_connections - (num_peers * 2); | ||
520 | |||
521 | |||
522 | /* Set up a task to end testing if peer start fails */ | ||
523 | die_task = | ||
524 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
525 | (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, | ||
526 | "didn't start all daemons in reasonable amount of time!!!"); | ||
527 | |||
528 | pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, | ||
529 | TIMEOUT, &hostkey_callback, NULL, | ||
530 | &peers_started_callback, NULL, | ||
531 | &topology_callback, NULL, NULL); | ||
532 | |||
533 | } | ||
534 | |||
535 | static int | ||
536 | check () | ||
537 | { | ||
538 | int ret; | ||
539 | |||
540 | char *const argv[] = { "test-testing-topology-blacklist", | ||
541 | "-c", | ||
542 | "test_testing_data_topology_blacklist.conf", | ||
543 | #if VERBOSE | ||
544 | "-L", "DEBUG", | ||
545 | #endif | ||
546 | NULL | ||
547 | }; | ||
548 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
549 | GNUNET_GETOPT_OPTION_END | ||
550 | }; | ||
551 | ret = | ||
552 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
553 | "test-testing-topology-blacklist", "nohelp", options, | ||
554 | &run, &ok); | ||
555 | if (ret != GNUNET_OK) | ||
556 | { | ||
557 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
558 | "`test-testing-topology-blacklist': Failed with error code %d\n", | ||
559 | ret); | ||
560 | } | ||
561 | |||
562 | return ok; | ||
563 | } | ||
564 | |||
565 | int | ||
566 | main (int argc, char *argv[]) | ||
567 | { | ||
568 | int ret; | ||
569 | |||
570 | GNUNET_log_setup ("test_testing_topology_blacklist", | ||
571 | #if VERBOSE | ||
572 | "DEBUG", | ||
573 | #else | ||
574 | "WARNING", | ||
575 | #endif | ||
576 | NULL); | ||
577 | ret = check (); | ||
578 | |||
579 | /** | ||
580 | * Need to remove base directory, subdirectories taken care | ||
581 | * of by the testing framework. | ||
582 | */ | ||
583 | if (test_directory != NULL) | ||
584 | { | ||
585 | if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) | ||
586 | { | ||
587 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
588 | "Failed to remove testing directory %s\n", test_directory); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | /* end of test_testing_topology_blacklist.c */ | ||
diff --git a/src/testing/test_testing_topology_churn.c b/src/testing/test_testing_topology_churn.c deleted file mode 100644 index 9c0bbf27d..000000000 --- a/src/testing/test_testing_topology_churn.c +++ /dev/null | |||
@@ -1,322 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file testing/test_testing_topology_churn.c | ||
22 | * @brief base testcase for testing simple churn functionality | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_testing_lib.h" | ||
26 | #include "gnunet_core_service.h" | ||
27 | |||
28 | |||
29 | /** | ||
30 | * How long until we fail the whole testcase? | ||
31 | */ | ||
32 | #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) | ||
33 | |||
34 | /** | ||
35 | * How long until we give up on starting the peers? (Must be longer than the connect timeout!) | ||
36 | */ | ||
37 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
38 | |||
39 | #define DEFAULT_NUM_PEERS 4 | ||
40 | |||
41 | static int ok; | ||
42 | |||
43 | static unsigned long long num_peers; | ||
44 | |||
45 | static unsigned int expected_connections; | ||
46 | |||
47 | static unsigned int expected_failed_connections; | ||
48 | |||
49 | static unsigned long long peers_left; | ||
50 | |||
51 | static struct GNUNET_TESTING_PeerGroup *pg; | ||
52 | |||
53 | const struct GNUNET_CONFIGURATION_Handle *main_cfg; | ||
54 | |||
55 | GNUNET_SCHEDULER_TaskIdentifier die_task; | ||
56 | |||
57 | static char *test_directory; | ||
58 | |||
59 | #define MTYPE 12345 | ||
60 | |||
61 | GNUNET_NETWORK_STRUCT_BEGIN | ||
62 | |||
63 | struct GNUNET_TestMessage | ||
64 | { | ||
65 | /** | ||
66 | * Header of the message | ||
67 | */ | ||
68 | struct GNUNET_MessageHeader header; | ||
69 | |||
70 | /** | ||
71 | * Unique identifier for this message. | ||
72 | */ | ||
73 | uint32_t uid; | ||
74 | }; | ||
75 | GNUNET_NETWORK_STRUCT_END | ||
76 | |||
77 | /** | ||
78 | * Check whether peers successfully shut down. | ||
79 | */ | ||
80 | void | ||
81 | shutdown_callback (void *cls, const char *emsg) | ||
82 | { | ||
83 | if (emsg != NULL) | ||
84 | { | ||
85 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n"); | ||
86 | if (ok == 0) | ||
87 | ok = 666; | ||
88 | } | ||
89 | else | ||
90 | { | ||
91 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n"); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | static void | ||
96 | finish_testing () | ||
97 | { | ||
98 | GNUNET_assert (pg != NULL); | ||
99 | |||
100 | if (die_task != GNUNET_SCHEDULER_NO_TASK) | ||
101 | GNUNET_SCHEDULER_cancel (die_task); | ||
102 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
103 | "Called finish testing, stopping daemons.\n"); | ||
104 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling daemons_stop\n"); | ||
105 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
106 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "daemons_stop finished\n"); | ||
107 | ok = 0; | ||
108 | } | ||
109 | |||
110 | static void | ||
111 | end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
112 | { | ||
113 | char *msg = cls; | ||
114 | |||
115 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
116 | "End badly was called (%s)... stopping daemons.\n", msg); | ||
117 | |||
118 | if (pg != NULL) | ||
119 | { | ||
120 | GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL); | ||
121 | ok = 7331; /* Opposite of leet */ | ||
122 | } | ||
123 | else | ||
124 | ok = 401; /* Never got peers started */ | ||
125 | |||
126 | } | ||
127 | |||
128 | struct ChurnTestContext | ||
129 | { | ||
130 | GNUNET_SCHEDULER_Task next_task; | ||
131 | |||
132 | }; | ||
133 | |||
134 | static struct ChurnTestContext churn_ctx; | ||
135 | |||
136 | /** | ||
137 | * Churn callback, report on success or failure of churn operation. | ||
138 | * | ||
139 | * @param cls closure | ||
140 | * @param emsg NULL on success | ||
141 | */ | ||
142 | void | ||
143 | churn_callback (void *cls, const char *emsg) | ||
144 | { | ||
145 | if (emsg == NULL) | ||
146 | { | ||
147 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Successfully churned peers!\n", | ||
148 | emsg); | ||
149 | GNUNET_SCHEDULER_add_now (churn_ctx.next_task, NULL); | ||
150 | } | ||
151 | else | ||
152 | { | ||
153 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
154 | "Failed to churn peers with error `%s'\n", emsg); | ||
155 | GNUNET_SCHEDULER_cancel (die_task); | ||
156 | die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | |||
161 | static void | ||
162 | churn_peers_both () | ||
163 | { | ||
164 | churn_ctx.next_task = &finish_testing; | ||
165 | GNUNET_TESTING_daemons_churn (pg, NULL, 1, 1, TIMEOUT, &churn_callback, NULL); | ||
166 | } | ||
167 | |||
168 | static void | ||
169 | churn_peers_off_again () | ||
170 | { | ||
171 | churn_ctx.next_task = &churn_peers_both; | ||
172 | GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); | ||
173 | } | ||
174 | |||
175 | static void | ||
176 | churn_peers_on () | ||
177 | { | ||
178 | churn_ctx.next_task = &churn_peers_off_again; | ||
179 | GNUNET_TESTING_daemons_churn (pg, NULL, 0, 2, TIMEOUT, &churn_callback, NULL); | ||
180 | } | ||
181 | |||
182 | static void | ||
183 | churn_peers_off () | ||
184 | { | ||
185 | churn_ctx.next_task = &churn_peers_on; | ||
186 | GNUNET_TESTING_daemons_churn (pg, NULL, 2, 0, TIMEOUT, &churn_callback, NULL); | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | peers_started_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
191 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
192 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
193 | { | ||
194 | if (emsg != NULL) | ||
195 | { | ||
196 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
197 | "Failed to start daemon with error: `%s'\n", emsg); | ||
198 | return; | ||
199 | } | ||
200 | GNUNET_assert (id != NULL); | ||
201 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", | ||
202 | (num_peers - peers_left) + 1, num_peers); | ||
203 | peers_left--; | ||
204 | if (peers_left == 0) | ||
205 | { | ||
206 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
207 | "All %d daemons started, now testing churn!\n", num_peers); | ||
208 | GNUNET_SCHEDULER_cancel (die_task); | ||
209 | /* Set up task in case topology creation doesn't finish | ||
210 | * within a reasonable amount of time */ | ||
211 | die_task = | ||
212 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
213 | (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, | ||
214 | "from peers_started_callback"); | ||
215 | churn_peers_off (); | ||
216 | ok = 0; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | |||
221 | static void | ||
222 | run (void *cls, char *const *args, const char *cfgfile, | ||
223 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
224 | { | ||
225 | ok = 1; | ||
226 | |||
227 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
228 | "Starting daemons based on config file %s\n", cfgfile); | ||
229 | if (GNUNET_YES != | ||
230 | GNUNET_CONFIGURATION_get_value_string (cfg, "paths", "servicehome", | ||
231 | &test_directory)) | ||
232 | { | ||
233 | ok = 404; | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | if (GNUNET_SYSERR == | ||
238 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "num_peers", | ||
239 | &num_peers)) | ||
240 | num_peers = DEFAULT_NUM_PEERS; | ||
241 | |||
242 | main_cfg = cfg; | ||
243 | |||
244 | peers_left = num_peers; | ||
245 | GNUNET_assert (num_peers > 0 && num_peers < (unsigned int) -1); | ||
246 | |||
247 | /* For this specific test we only really want a CLIQUE topology as the | ||
248 | * overlay allowed topology, and a RING topology as the underlying connection | ||
249 | * allowed topology. So we will expect only num_peers * 2 connections to | ||
250 | * work, and (num_peers * (num_peers - 1)) - (num_peers * 2) to fail. | ||
251 | */ | ||
252 | expected_connections = num_peers * (num_peers - 1); | ||
253 | expected_failed_connections = expected_connections - (num_peers * 2); | ||
254 | |||
255 | |||
256 | /* Set up a task to end testing if peer start fails */ | ||
257 | die_task = | ||
258 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
259 | (GNUNET_TIME_UNIT_MINUTES, 5), &end_badly, | ||
260 | "didn't start all daemons in reasonable amount of time!!!"); | ||
261 | |||
262 | pg = GNUNET_TESTING_daemons_start (cfg, peers_left, peers_left, peers_left, | ||
263 | TIMEOUT, NULL, NULL, | ||
264 | &peers_started_callback, NULL, NULL, NULL, | ||
265 | NULL); | ||
266 | |||
267 | } | ||
268 | |||
269 | static int | ||
270 | check () | ||
271 | { | ||
272 | int ret; | ||
273 | |||
274 | char *const argv[] = { "test-testing-topology-churn", | ||
275 | "-c", | ||
276 | "test_testing_data_topology_churn.conf", | ||
277 | NULL | ||
278 | }; | ||
279 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
280 | GNUNET_GETOPT_OPTION_END | ||
281 | }; | ||
282 | ret = | ||
283 | GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, | ||
284 | "test-testing-topology-churn", "nohelp", options, | ||
285 | &run, &ok); | ||
286 | if (ret != GNUNET_OK) | ||
287 | { | ||
288 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
289 | "`test-testing-topology-churn': Failed with error code %d\n", | ||
290 | ret); | ||
291 | } | ||
292 | |||
293 | return ok; | ||
294 | } | ||
295 | |||
296 | int | ||
297 | main (int argc, char *argv[]) | ||
298 | { | ||
299 | int ret; | ||
300 | |||
301 | GNUNET_log_setup ("test_testing_topology_churn", | ||
302 | "WARNING", | ||
303 | NULL); | ||
304 | ret = check (); | ||
305 | |||
306 | /** | ||
307 | * Need to remove base directory, subdirectories taken care | ||
308 | * of by the testing framework. | ||
309 | */ | ||
310 | if (test_directory != NULL) | ||
311 | { | ||
312 | if (GNUNET_DISK_directory_remove (test_directory) != GNUNET_OK) | ||
313 | { | ||
314 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
315 | "Failed to remove testing directory %s\n", test_directory); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | /* end of test_testing_topology_churn.c */ | ||
diff --git a/src/testing/testing.c b/src/testing/testing.c deleted file mode 100644 index a80ad25cf..000000000 --- a/src/testing/testing.c +++ /dev/null | |||
@@ -1,2204 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2008, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file testing/testing.c | ||
23 | * @brief convenience API for writing testcases for GNUnet | ||
24 | * Many testcases need to start and stop gnunetd, | ||
25 | * and this library is supposed to make that easier | ||
26 | * for TESTCASES. Normal programs should always | ||
27 | * use functions from gnunet_{util,arm}_lib.h. This API is | ||
28 | * ONLY for writing testcases! | ||
29 | * @author Christian Grothoff | ||
30 | * | ||
31 | */ | ||
32 | #include "platform.h" | ||
33 | #include "gnunet_arm_service.h" | ||
34 | #include "gnunet_core_service.h" | ||
35 | #include "gnunet_constants.h" | ||
36 | #include "gnunet_testing_lib.h" | ||
37 | #include "gnunet_transport_service.h" | ||
38 | #include "gnunet_hello_lib.h" | ||
39 | |||
40 | /** | ||
41 | * Hack to deal with initial HELLO's being often devoid of addresses. | ||
42 | * This hack causes 'process_hello' to ignore HELLOs without addresses. | ||
43 | * The correct implementation would continue with 'process_hello' until | ||
44 | * the connection could be established... | ||
45 | */ | ||
46 | #define EMPTY_HACK GNUNET_YES | ||
47 | |||
48 | /** | ||
49 | * How long do we wait after starting gnunet-service-arm | ||
50 | * for the core service to be alive? | ||
51 | */ | ||
52 | #define ARM_START_WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120) | ||
53 | |||
54 | /** | ||
55 | * How many times are we willing to try to wait for "scp" or | ||
56 | * "gnunet-service-arm" to complete (waitpid) before giving up? | ||
57 | */ | ||
58 | #define MAX_EXEC_WAIT_RUNS 250 | ||
59 | |||
60 | static struct GNUNET_CORE_MessageHandler no_handlers[] = { {NULL, 0, 0} }; | ||
61 | |||
62 | #if EMPTY_HACK | ||
63 | static int | ||
64 | test_address (void *cls, const struct GNUNET_HELLO_Address *address, | ||
65 | struct GNUNET_TIME_Absolute expiration) | ||
66 | { | ||
67 | int *empty = cls; | ||
68 | |||
69 | *empty = GNUNET_NO; | ||
70 | return GNUNET_OK; | ||
71 | } | ||
72 | #endif | ||
73 | |||
74 | /** | ||
75 | * Receive the HELLO from one peer, give it to the other | ||
76 | * and ask them to connect. | ||
77 | * | ||
78 | * @param cls Closure (daemon whose hello is this). | ||
79 | * @param message HELLO message of peer | ||
80 | */ | ||
81 | static void | ||
82 | process_hello (void *cls, const struct GNUNET_MessageHeader *message) | ||
83 | { | ||
84 | struct GNUNET_TESTING_Daemon *daemon = cls; | ||
85 | int msize; | ||
86 | |||
87 | #if EMPTY_HACK | ||
88 | int empty; | ||
89 | |||
90 | empty = GNUNET_YES; | ||
91 | GNUNET_assert (message != NULL); | ||
92 | GNUNET_HELLO_iterate_addresses ((const struct GNUNET_HELLO_Message *) message, | ||
93 | GNUNET_NO, &test_address, &empty); | ||
94 | if (GNUNET_YES == empty) | ||
95 | { | ||
96 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
97 | "Skipping empty HELLO address of peer %s\n", | ||
98 | GNUNET_i2s (&daemon->id)); | ||
99 | return; | ||
100 | } | ||
101 | #endif | ||
102 | GNUNET_assert (daemon->phase == SP_GET_HELLO || | ||
103 | daemon->phase == SP_START_DONE); | ||
104 | daemon->cb = NULL; // FIXME: why??? (see fsm:SP_START_CORE, notify_daemon_started) | ||
105 | if (daemon->task != GNUNET_SCHEDULER_NO_TASK) /* Assertion here instead? */ | ||
106 | GNUNET_SCHEDULER_cancel (daemon->task); | ||
107 | |||
108 | if (daemon->server != NULL) | ||
109 | { | ||
110 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
111 | "Received `%s' from transport service of `%4s', disconnecting core!\n", | ||
112 | "HELLO", GNUNET_i2s (&daemon->id)); | ||
113 | GNUNET_CORE_disconnect (daemon->server); | ||
114 | daemon->server = NULL; | ||
115 | } | ||
116 | |||
117 | msize = ntohs (message->size); | ||
118 | if (msize < 1) | ||
119 | { | ||
120 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
121 | "HELLO message of peer %s is of size 0\n", | ||
122 | GNUNET_i2s (&daemon->id)); | ||
123 | return; | ||
124 | } | ||
125 | if (daemon->ghh != NULL) | ||
126 | { | ||
127 | GNUNET_TRANSPORT_get_hello_cancel (daemon->ghh); | ||
128 | daemon->ghh = NULL; | ||
129 | } | ||
130 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
131 | "Received `%s' from transport service of `%4s'\n", "HELLO", | ||
132 | GNUNET_i2s (&daemon->id)); | ||
133 | GNUNET_free_non_null (daemon->hello); | ||
134 | daemon->hello = GNUNET_malloc (msize); | ||
135 | memcpy (daemon->hello, message, msize); | ||
136 | |||
137 | if (daemon->th != NULL) | ||
138 | { | ||
139 | GNUNET_TRANSPORT_disconnect (daemon->th); | ||
140 | daemon->th = NULL; | ||
141 | } | ||
142 | daemon->phase = SP_START_DONE; | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Notify of a peer being up and running. Scheduled as a task | ||
148 | * so that variables which may need to be set are set before | ||
149 | * the connect callback can set up new operations. | ||
150 | * FIXME: what variables?????? where from???? | ||
151 | * | ||
152 | * @param cls the testing daemon | ||
153 | * @param tc task scheduler context | ||
154 | */ | ||
155 | static void | ||
156 | notify_daemon_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
157 | { | ||
158 | struct GNUNET_TESTING_Daemon *d = cls; | ||
159 | GNUNET_TESTING_NotifyDaemonRunning cb; | ||
160 | |||
161 | cb = d->cb; | ||
162 | d->cb = NULL; | ||
163 | if (NULL != cb) | ||
164 | cb (d->cb_cls, &d->id, d->cfg, d, NULL); | ||
165 | } | ||
166 | |||
167 | |||
168 | /** | ||
169 | * Finite-state machine for starting GNUnet. | ||
170 | * | ||
171 | * @param cls our "struct GNUNET_TESTING_Daemon" | ||
172 | * @param tc unused | ||
173 | */ | ||
174 | static void | ||
175 | start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
176 | { | ||
177 | struct GNUNET_TESTING_Daemon *d = cls; | ||
178 | GNUNET_TESTING_NotifyDaemonRunning cb; | ||
179 | enum GNUNET_OS_ProcessStatusType type; | ||
180 | unsigned long code; | ||
181 | char *dst; | ||
182 | int bytes_read; | ||
183 | |||
184 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %s FSM is in phase %u.\n", | ||
185 | GNUNET_i2s (&d->id), d->phase); | ||
186 | d->task = GNUNET_SCHEDULER_NO_TASK; | ||
187 | switch (d->phase) | ||
188 | { | ||
189 | case SP_COPYING: | ||
190 | /* confirm copying complete */ | ||
191 | if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) | ||
192 | { | ||
193 | if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) | ||
194 | { | ||
195 | cb = d->cb; | ||
196 | d->cb = NULL; | ||
197 | if (NULL != cb) | ||
198 | cb (d->cb_cls, NULL, d->cfg, d, | ||
199 | _ | ||
200 | ("`scp' does not seem to terminate (timeout copying config).\n")); | ||
201 | return; | ||
202 | } | ||
203 | /* wait some more */ | ||
204 | d->task = | ||
205 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
206 | d); | ||
207 | return; | ||
208 | } | ||
209 | if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) | ||
210 | { | ||
211 | cb = d->cb; | ||
212 | d->cb = NULL; | ||
213 | if (NULL != cb) | ||
214 | cb (d->cb_cls, NULL, d->cfg, d, _("`scp' did not complete cleanly.\n")); | ||
215 | return; | ||
216 | } | ||
217 | GNUNET_OS_process_destroy (d->proc_arm_copying); | ||
218 | d->proc_arm_copying = NULL; | ||
219 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
220 | "Successfully copied configuration file.\n"); | ||
221 | d->phase = SP_COPIED; | ||
222 | /* fall-through */ | ||
223 | case SP_COPIED: | ||
224 | /* Start create hostkey process if we don't already know the peer identity! */ | ||
225 | if (GNUNET_NO == d->have_hostkey) | ||
226 | { | ||
227 | GNUNET_assert (NULL == d->proc_arm_peerinfo); | ||
228 | d->pipe_stdout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_YES); | ||
229 | if (d->pipe_stdout == NULL) | ||
230 | { | ||
231 | cb = d->cb; | ||
232 | d->cb = NULL; | ||
233 | if (NULL != cb) | ||
234 | cb (d->cb_cls, NULL, d->cfg, d, | ||
235 | (NULL == | ||
236 | d->hostname) ? | ||
237 | _("Failed to create pipe for `gnunet-peerinfo' process.\n") : | ||
238 | _("Failed to create pipe for `ssh' process.\n")); | ||
239 | return; | ||
240 | } | ||
241 | if (NULL == d->hostname) | ||
242 | { | ||
243 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
244 | "Starting `%s', with command `%s %s %s %s'.\n", | ||
245 | "gnunet-peerinfo", "gnunet-peerinfo", "-c", d->cfgfile, | ||
246 | "-sq"); | ||
247 | d->proc_arm_peerinfo = | ||
248 | GNUNET_OS_start_process (GNUNET_YES, NULL, d->pipe_stdout, "gnunet-peerinfo", | ||
249 | "gnunet-peerinfo", "-c", d->cfgfile, "-sq", | ||
250 | NULL); | ||
251 | GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | if (d->username != NULL) | ||
256 | GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); | ||
257 | else | ||
258 | dst = GNUNET_strdup (d->hostname); | ||
259 | |||
260 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
261 | "Starting `%s', with command `%s %s %s %s %s %s'.\n", | ||
262 | "gnunet-peerinfo", "ssh", dst, "gnunet-peerinfo", "-c", | ||
263 | d->cfgfile, "-sq"); | ||
264 | if (d->ssh_port_str == NULL) | ||
265 | { | ||
266 | d->proc_arm_peerinfo = GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", | ||
267 | "-q", | ||
268 | dst, "gnunet-peerinfo", "-c", | ||
269 | d->cfgfile, "-sq", NULL); | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | d->proc_arm_peerinfo = | ||
274 | GNUNET_OS_start_process (GNUNET_NO, NULL, d->pipe_stdout, "ssh", "ssh", "-p", | ||
275 | d->ssh_port_str, | ||
276 | "-q", | ||
277 | dst, "gnunet-peerinfo", "-c", d->cfgfile, | ||
278 | "-sq", NULL); | ||
279 | } | ||
280 | GNUNET_DISK_pipe_close_end (d->pipe_stdout, GNUNET_DISK_PIPE_END_WRITE); | ||
281 | GNUNET_free (dst); | ||
282 | } | ||
283 | if (NULL == d->proc_arm_peerinfo) | ||
284 | { | ||
285 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
286 | _("Could not start `%s' process to create hostkey.\n"), | ||
287 | (NULL == d->hostname) ? "gnunet-peerinfo" : "ssh"); | ||
288 | cb = d->cb; | ||
289 | d->cb = NULL; | ||
290 | if (NULL != cb) | ||
291 | cb (d->cb_cls, NULL, d->cfg, d, | ||
292 | (NULL == | ||
293 | d->hostname) ? _("Failed to start `gnunet-peerinfo' process.\n") | ||
294 | : _("Failed to start `ssh' process.\n")); | ||
295 | GNUNET_DISK_pipe_close (d->pipe_stdout); | ||
296 | return; | ||
297 | } | ||
298 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
299 | "Started `%s', waiting for hostkey.\n", "gnunet-peerinfo"); | ||
300 | d->phase = SP_HOSTKEY_CREATE; | ||
301 | d->task = | ||
302 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining | ||
303 | (d->max_timeout), | ||
304 | GNUNET_DISK_pipe_handle | ||
305 | (d->pipe_stdout, | ||
306 | GNUNET_DISK_PIPE_END_READ), | ||
307 | &start_fsm, d); | ||
308 | } | ||
309 | else /* Already have a hostkey! */ | ||
310 | { | ||
311 | if (d->hostkey_callback != NULL) | ||
312 | { | ||
313 | d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); | ||
314 | d->hostkey_callback = NULL; | ||
315 | d->phase = SP_HOSTKEY_CREATED; | ||
316 | } | ||
317 | else | ||
318 | d->phase = SP_TOPOLOGY_SETUP; | ||
319 | |||
320 | /* wait some more */ | ||
321 | d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); | ||
322 | } | ||
323 | break; | ||
324 | case SP_HOSTKEY_CREATE: | ||
325 | bytes_read = | ||
326 | GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle | ||
327 | (d->pipe_stdout, GNUNET_DISK_PIPE_END_READ), | ||
328 | &d->hostkeybuf[d->hostkeybufpos], | ||
329 | sizeof (d->hostkeybuf) - d->hostkeybufpos); | ||
330 | if (bytes_read > 0) | ||
331 | d->hostkeybufpos += bytes_read; | ||
332 | |||
333 | if ((d->hostkeybufpos < 104) && (bytes_read > 0)) | ||
334 | { | ||
335 | /* keep reading */ | ||
336 | d->task = | ||
337 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining | ||
338 | (d->max_timeout), | ||
339 | GNUNET_DISK_pipe_handle | ||
340 | (d->pipe_stdout, | ||
341 | GNUNET_DISK_PIPE_END_READ), | ||
342 | &start_fsm, d); | ||
343 | return; | ||
344 | } | ||
345 | d->hostkeybuf[103] = '\0'; | ||
346 | |||
347 | if ((bytes_read < 0) || | ||
348 | (GNUNET_OK != | ||
349 | GNUNET_CRYPTO_hash_from_string (d->hostkeybuf, &d->id.hashPubKey))) | ||
350 | { | ||
351 | /* error */ | ||
352 | if (bytes_read < 0) | ||
353 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
354 | _("Error reading from gnunet-peerinfo: %s\n"), | ||
355 | STRERROR (errno)); | ||
356 | else | ||
357 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
358 | _("Malformed output from gnunet-peerinfo!\n")); | ||
359 | cb = d->cb; | ||
360 | d->cb = NULL; | ||
361 | GNUNET_DISK_pipe_close (d->pipe_stdout); | ||
362 | d->pipe_stdout = NULL; | ||
363 | (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); | ||
364 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); | ||
365 | GNUNET_OS_process_destroy (d->proc_arm_peerinfo); | ||
366 | d->proc_arm_peerinfo = NULL; | ||
367 | if (NULL != cb) | ||
368 | cb (d->cb_cls, NULL, d->cfg, d, _("Failed to get hostkey!\n")); | ||
369 | return; | ||
370 | } | ||
371 | d->shortname = GNUNET_strdup (GNUNET_i2s (&d->id)); | ||
372 | GNUNET_DISK_pipe_close (d->pipe_stdout); | ||
373 | d->pipe_stdout = NULL; | ||
374 | (void) GNUNET_OS_process_kill (d->proc_arm_peerinfo, SIGKILL); | ||
375 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (d->proc_arm_peerinfo)); | ||
376 | GNUNET_OS_process_destroy (d->proc_arm_peerinfo); | ||
377 | d->proc_arm_peerinfo = NULL; | ||
378 | d->have_hostkey = GNUNET_YES; | ||
379 | if (d->hostkey_callback != NULL) | ||
380 | { | ||
381 | d->hostkey_callback (d->hostkey_cls, &d->id, d, NULL); | ||
382 | d->hostkey_callback = NULL; | ||
383 | d->phase = SP_HOSTKEY_CREATED; | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | d->phase = SP_TOPOLOGY_SETUP; | ||
388 | } | ||
389 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully got hostkey!\n"); | ||
390 | /* Fall through */ | ||
391 | case SP_HOSTKEY_CREATED: | ||
392 | /* wait for topology finished */ | ||
393 | if ((GNUNET_YES == d->dead) || | ||
394 | (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0)) | ||
395 | { | ||
396 | cb = d->cb; | ||
397 | d->cb = NULL; | ||
398 | if (NULL != cb) | ||
399 | cb (d->cb_cls, NULL, d->cfg, d, | ||
400 | _("`Failed while waiting for topology setup!\n")); | ||
401 | return; | ||
402 | } | ||
403 | |||
404 | d->task = | ||
405 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
406 | d); | ||
407 | break; | ||
408 | case SP_TOPOLOGY_SETUP: /* Indicates topology setup has completed! */ | ||
409 | /* start GNUnet on remote host */ | ||
410 | if (NULL == d->hostname) | ||
411 | { | ||
412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
413 | "Starting `%s', with command `%s %s %s %s'.\n", | ||
414 | "gnunet-arm", "gnunet-arm", "-c", d->cfgfile, | ||
415 | "-s"); | ||
416 | d->proc_arm_start = | ||
417 | GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", "-c", | ||
418 | d->cfgfile, | ||
419 | "-s", "-q", "-T", | ||
420 | GNUNET_TIME_relative_to_string | ||
421 | (GNUNET_TIME_absolute_get_remaining | ||
422 | (d->max_timeout)), NULL); | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | if (d->username != NULL) | ||
427 | GNUNET_asprintf (&dst, "%s@%s", d->username, d->hostname); | ||
428 | else | ||
429 | dst = GNUNET_strdup (d->hostname); | ||
430 | |||
431 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
432 | "Starting `%s', with command `%s %s %s %s %s %s %s'.\n", | ||
433 | "gnunet-arm", "ssh", dst, "gnunet-arm", "-c", d->cfgfile, | ||
434 | "-s", "-q"); | ||
435 | if (d->ssh_port_str == NULL) | ||
436 | { | ||
437 | d->proc_arm_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", | ||
438 | "-q", | ||
439 | dst, "gnunet-arm", | ||
440 | "-c", d->cfgfile, "-s", "-q", "-T", | ||
441 | GNUNET_TIME_relative_to_string | ||
442 | (GNUNET_TIME_absolute_get_remaining | ||
443 | (d->max_timeout)), NULL); | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | |||
448 | d->proc_arm_start = | ||
449 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-p", | ||
450 | d->ssh_port_str, | ||
451 | "-q", | ||
452 | dst, "gnunet-arm", | ||
453 | "-c", d->cfgfile, "-s", "-q", "-T", | ||
454 | GNUNET_TIME_relative_to_string | ||
455 | (GNUNET_TIME_absolute_get_remaining | ||
456 | (d->max_timeout)), NULL); | ||
457 | } | ||
458 | GNUNET_free (dst); | ||
459 | } | ||
460 | if (NULL == d->proc_arm_start) | ||
461 | { | ||
462 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
463 | _("Could not start `%s' process to start GNUnet.\n"), | ||
464 | (NULL == d->hostname) ? "gnunet-arm" : "ssh"); | ||
465 | cb = d->cb; | ||
466 | d->cb = NULL; | ||
467 | if (NULL != cb) | ||
468 | cb (d->cb_cls, NULL, d->cfg, d, | ||
469 | (NULL == | ||
470 | d->hostname) ? _("Failed to start `gnunet-arm' process.\n") : | ||
471 | _("Failed to start `ssh' process.\n")); | ||
472 | return; | ||
473 | } | ||
474 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
475 | "Started `%s', waiting for `%s' to be up.\n", "gnunet-arm", | ||
476 | "gnunet-service-core"); | ||
477 | d->phase = SP_START_ARMING; | ||
478 | d->task = | ||
479 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
480 | d); | ||
481 | // FIXME: busy wait? | ||
482 | break; | ||
483 | case SP_START_ARMING: | ||
484 | if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_start, &type, &code)) | ||
485 | { | ||
486 | if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) | ||
487 | { | ||
488 | cb = d->cb; | ||
489 | d->cb = NULL; | ||
490 | if (NULL != cb) | ||
491 | cb (d->cb_cls, NULL, d->cfg, d, | ||
492 | (NULL == | ||
493 | d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : | ||
494 | _("`ssh' does not seem to terminate.\n")); | ||
495 | if (d->cfg != NULL) | ||
496 | { | ||
497 | GNUNET_CONFIGURATION_destroy (d->cfg); | ||
498 | d->cfg = NULL; | ||
499 | } | ||
500 | if (d->cfgfile != NULL) | ||
501 | { | ||
502 | GNUNET_free (d->cfgfile); | ||
503 | d->cfgfile = NULL; | ||
504 | } | ||
505 | GNUNET_free_non_null (d->hostname); | ||
506 | GNUNET_free_non_null (d->username); | ||
507 | GNUNET_OS_process_destroy (d->proc_arm_start); | ||
508 | d->proc_arm_start = NULL; | ||
509 | d->username = NULL; | ||
510 | d->hostname = NULL; // Quick hack to avoid crashing (testing need to be | ||
511 | d->cfg = NULL; // overhauled anyway, and the error managing is | ||
512 | // GNUNET_free (d); // FIXME (could this leak) | ||
513 | // pretty broken anyway. | ||
514 | return; | ||
515 | } | ||
516 | /* wait some more */ | ||
517 | d->task = | ||
518 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
519 | d); | ||
520 | // FIXME: busy wait? | ||
521 | return; | ||
522 | } | ||
523 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully started `%s'.\n", | ||
524 | "gnunet-arm"); | ||
525 | GNUNET_OS_process_destroy (d->proc_arm_start); | ||
526 | d->proc_arm_start = NULL; | ||
527 | d->phase = SP_START_CORE; | ||
528 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Calling CORE_connect\n"); | ||
529 | /* Fall through */ | ||
530 | case SP_START_CORE: | ||
531 | if (d->server != NULL) | ||
532 | GNUNET_CORE_disconnect (d->server); | ||
533 | |||
534 | d->th = GNUNET_TRANSPORT_connect (d->cfg, &d->id, d, NULL, NULL, NULL); | ||
535 | if (d->th == NULL) | ||
536 | { | ||
537 | if (GNUNET_YES == d->dead) | ||
538 | GNUNET_TESTING_daemon_stop (d, | ||
539 | GNUNET_TIME_absolute_get_remaining | ||
540 | (d->max_timeout), d->dead_cb, | ||
541 | d->dead_cb_cls, GNUNET_YES, GNUNET_NO); | ||
542 | else if (NULL != d->cb) | ||
543 | d->cb (d->cb_cls, &d->id, d->cfg, d, | ||
544 | _("Failed to connect to transport service!\n")); | ||
545 | return; | ||
546 | } | ||
547 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
548 | "Connected to transport service `%s', getting HELLO\n", | ||
549 | GNUNET_i2s (&d->id)); | ||
550 | d->ghh = GNUNET_TRANSPORT_get_hello (d->th, &process_hello, d); | ||
551 | /* FIXME: store task ID somewhere! */ | ||
552 | GNUNET_SCHEDULER_add_now (¬ify_daemon_started, d); | ||
553 | /*cb = d->cb; | ||
554 | * d->cb = NULL; | ||
555 | * if (NULL != cb) | ||
556 | * cb (d->cb_cls, &d->id, d->cfg, d, NULL); */ | ||
557 | d->running = GNUNET_YES; | ||
558 | d->phase = SP_GET_HELLO; | ||
559 | break; | ||
560 | case SP_GET_HELLO: | ||
561 | if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) | ||
562 | { | ||
563 | if (d->server != NULL) | ||
564 | GNUNET_CORE_disconnect (d->server); | ||
565 | if (d->th != NULL) | ||
566 | GNUNET_TRANSPORT_disconnect (d->th); | ||
567 | cb = d->cb; | ||
568 | d->cb = NULL; | ||
569 | if (NULL != cb) | ||
570 | cb (d->cb_cls, NULL, d->cfg, d, _("Unable to get HELLO for peer!\n")); | ||
571 | GNUNET_CONFIGURATION_destroy (d->cfg); | ||
572 | GNUNET_free (d->cfgfile); | ||
573 | GNUNET_free_non_null (d->hostname); | ||
574 | GNUNET_free_non_null (d->username); | ||
575 | GNUNET_free (d); | ||
576 | return; | ||
577 | } | ||
578 | if (d->hello != NULL) | ||
579 | return; | ||
580 | GNUNET_assert (d->task == GNUNET_SCHEDULER_NO_TASK); | ||
581 | d->task = | ||
582 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
583 | (GNUNET_CONSTANTS_SERVICE_RETRY, 2), | ||
584 | &start_fsm, d); | ||
585 | break; | ||
586 | case SP_START_DONE: | ||
587 | GNUNET_break (0); | ||
588 | break; | ||
589 | case SP_SERVICE_START: | ||
590 | /* confirm gnunet-arm exited */ | ||
591 | if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_start, &type, &code)) | ||
592 | { | ||
593 | if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) | ||
594 | { | ||
595 | cb = d->cb; | ||
596 | d->cb = NULL; | ||
597 | if (NULL != cb) | ||
598 | cb (d->cb_cls, NULL, d->cfg, d, | ||
599 | (NULL == | ||
600 | d->hostname) ? _("`gnunet-arm' does not seem to terminate.\n") : | ||
601 | _("`ssh' does not seem to terminate.\n")); | ||
602 | return; | ||
603 | } | ||
604 | /* wait some more */ | ||
605 | d->task = | ||
606 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
607 | d); | ||
608 | return; | ||
609 | } | ||
610 | #if EXTRA_CHECKS | ||
611 | if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) | ||
612 | { | ||
613 | cb = d->cb; | ||
614 | d->cb = NULL; | ||
615 | if (NULL != cb) | ||
616 | cb (d->cb_cls, NULL, d->cfg, d, | ||
617 | (NULL == | ||
618 | d->hostname) ? | ||
619 | _ | ||
620 | ("`gnunet-arm' terminated with non-zero exit status (or timed out)!\n") | ||
621 | : _("`ssh' does not seem to terminate.\n")); | ||
622 | return; | ||
623 | } | ||
624 | #endif | ||
625 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service startup complete!\n"); | ||
626 | cb = d->cb; | ||
627 | d->cb = NULL; | ||
628 | d->phase = SP_START_DONE; | ||
629 | if (NULL != cb) | ||
630 | cb (d->cb_cls, &d->id, d->cfg, d, NULL); | ||
631 | GNUNET_OS_process_destroy (d->proc_arm_srv_start); | ||
632 | d->proc_arm_srv_start = NULL; | ||
633 | break; | ||
634 | case SP_SERVICE_SHUTDOWN_START: | ||
635 | /* confirm copying complete */ | ||
636 | if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_srv_stop, &type, &code)) | ||
637 | { | ||
638 | if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) | ||
639 | { | ||
640 | if (NULL != d->dead_cb) | ||
641 | d->dead_cb (d->dead_cb_cls, | ||
642 | _ | ||
643 | ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); | ||
644 | return; | ||
645 | } | ||
646 | /* wait some more */ | ||
647 | d->task = | ||
648 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
649 | d); | ||
650 | return; | ||
651 | } | ||
652 | #if EXTRA_CHECKS | ||
653 | if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) | ||
654 | { | ||
655 | if (NULL != d->dead_cb) | ||
656 | d->dead_cb (d->dead_cb_cls, | ||
657 | _ | ||
658 | ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); | ||
659 | return; | ||
660 | } | ||
661 | #endif | ||
662 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); | ||
663 | if (NULL != d->dead_cb) | ||
664 | d->dead_cb (d->dead_cb_cls, NULL); | ||
665 | break; | ||
666 | case SP_SHUTDOWN_START: | ||
667 | /* confirm copying complete !??? */ | ||
668 | if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_stop, &type, &code)) | ||
669 | { | ||
670 | if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) | ||
671 | { | ||
672 | if (NULL != d->dead_cb) | ||
673 | d->dead_cb (d->dead_cb_cls, | ||
674 | _ | ||
675 | ("either `gnunet-arm' or `ssh' does not seem to terminate.\n")); | ||
676 | if (d->th != NULL) | ||
677 | { | ||
678 | GNUNET_TRANSPORT_get_hello_cancel (d->ghh); | ||
679 | d->ghh = NULL; | ||
680 | GNUNET_TRANSPORT_disconnect (d->th); | ||
681 | d->th = NULL; | ||
682 | } | ||
683 | if (d->cfg != NULL) | ||
684 | { | ||
685 | GNUNET_CONFIGURATION_destroy (d->cfg); | ||
686 | d->cfg = NULL; | ||
687 | } | ||
688 | if (d->cfgfile != NULL) | ||
689 | { | ||
690 | GNUNET_free (d->cfgfile); | ||
691 | d->cfgfile = NULL; | ||
692 | } | ||
693 | GNUNET_free_non_null (d->hello); | ||
694 | GNUNET_free_non_null (d->hostname); | ||
695 | GNUNET_free_non_null (d->username); | ||
696 | GNUNET_free_non_null (d->shortname); | ||
697 | GNUNET_OS_process_destroy (d->proc_arm_stop); | ||
698 | d->proc_arm_stop = NULL; | ||
699 | GNUNET_free (d); | ||
700 | return; | ||
701 | } | ||
702 | /* wait some more */ | ||
703 | d->task = | ||
704 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
705 | d); | ||
706 | return; | ||
707 | } | ||
708 | if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) | ||
709 | { | ||
710 | if (NULL != d->dead_cb) | ||
711 | d->dead_cb (d->dead_cb_cls, | ||
712 | _ | ||
713 | ("shutdown (either `gnunet-arm' or `ssh') did not complete cleanly.\n")); | ||
714 | if (d->th != NULL) | ||
715 | { | ||
716 | GNUNET_TRANSPORT_get_hello_cancel (d->ghh); | ||
717 | d->ghh = NULL; | ||
718 | GNUNET_TRANSPORT_disconnect (d->th); | ||
719 | d->th = NULL; | ||
720 | } | ||
721 | if (d->server != NULL) | ||
722 | { | ||
723 | GNUNET_CORE_disconnect (d->server); | ||
724 | d->server = NULL; | ||
725 | } | ||
726 | GNUNET_CONFIGURATION_destroy (d->cfg); | ||
727 | d->cfg = NULL; | ||
728 | GNUNET_free (d->cfgfile); | ||
729 | GNUNET_free_non_null (d->hello); | ||
730 | GNUNET_free_non_null (d->hostname); | ||
731 | GNUNET_free_non_null (d->username); | ||
732 | GNUNET_free_non_null (d->shortname); | ||
733 | GNUNET_OS_process_destroy (d->proc_arm_stop); | ||
734 | d->proc_arm_stop = NULL; | ||
735 | GNUNET_free (d); | ||
736 | return; | ||
737 | } | ||
738 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer shutdown complete.\n"); | ||
739 | if (d->server != NULL) | ||
740 | { | ||
741 | GNUNET_CORE_disconnect (d->server); | ||
742 | d->server = NULL; | ||
743 | } | ||
744 | |||
745 | if (d->th != NULL) | ||
746 | { | ||
747 | GNUNET_TRANSPORT_get_hello_cancel (d->ghh); | ||
748 | d->ghh = NULL; | ||
749 | GNUNET_TRANSPORT_disconnect (d->th); | ||
750 | d->th = NULL; | ||
751 | } | ||
752 | |||
753 | if (NULL != d->dead_cb) | ||
754 | d->dead_cb (d->dead_cb_cls, NULL); | ||
755 | |||
756 | /* state clean up and notifications */ | ||
757 | if (d->churn == GNUNET_NO) | ||
758 | { | ||
759 | GNUNET_CONFIGURATION_destroy (d->cfg); | ||
760 | d->cfg = NULL; | ||
761 | GNUNET_free (d->cfgfile); | ||
762 | GNUNET_free_non_null (d->hostname); | ||
763 | GNUNET_free_non_null (d->username); | ||
764 | } | ||
765 | |||
766 | GNUNET_free_non_null (d->hello); | ||
767 | d->hello = NULL; | ||
768 | GNUNET_free_non_null (d->shortname); | ||
769 | GNUNET_OS_process_destroy (d->proc_arm_stop); | ||
770 | d->proc_arm_stop = NULL; | ||
771 | d->shortname = NULL; | ||
772 | if (d->churn == GNUNET_NO) | ||
773 | GNUNET_free (d); | ||
774 | |||
775 | break; | ||
776 | case SP_CONFIG_UPDATE: | ||
777 | /* confirm copying complete */ | ||
778 | if (GNUNET_OK != GNUNET_OS_process_status (d->proc_arm_copying, &type, &code)) | ||
779 | { | ||
780 | if (GNUNET_TIME_absolute_get_remaining (d->max_timeout).rel_value == 0) /* FIXME: config update should take timeout parameter! */ | ||
781 | { | ||
782 | cb = d->cb; | ||
783 | d->cb = NULL; | ||
784 | if (NULL != cb) | ||
785 | cb (d->cb_cls, NULL, d->cfg, d, | ||
786 | _("`scp' does not seem to terminate.\n")); | ||
787 | return; | ||
788 | } | ||
789 | /* wait some more */ | ||
790 | d->task = | ||
791 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
792 | d); | ||
793 | return; | ||
794 | } | ||
795 | if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) | ||
796 | { | ||
797 | if (NULL != d->update_cb) | ||
798 | d->update_cb (d->update_cb_cls, _("`scp' did not complete cleanly.\n")); | ||
799 | return; | ||
800 | } | ||
801 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
802 | "Successfully copied configuration file.\n"); | ||
803 | if (NULL != d->update_cb) | ||
804 | d->update_cb (d->update_cb_cls, NULL); | ||
805 | d->phase = SP_START_DONE; | ||
806 | break; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | /** | ||
811 | * Continues GNUnet daemon startup when user wanted to be notified | ||
812 | * once a hostkey was generated (for creating friends files, blacklists, | ||
813 | * etc.). | ||
814 | * | ||
815 | * @param daemon the daemon to finish starting | ||
816 | */ | ||
817 | void | ||
818 | GNUNET_TESTING_daemon_continue_startup (struct GNUNET_TESTING_Daemon *daemon) | ||
819 | { | ||
820 | GNUNET_assert (daemon->phase == SP_HOSTKEY_CREATED); | ||
821 | daemon->phase = SP_TOPOLOGY_SETUP; | ||
822 | } | ||
823 | |||
824 | /** | ||
825 | * Check whether the given daemon is running. | ||
826 | * | ||
827 | * @param daemon the daemon to check | ||
828 | * | ||
829 | * @return GNUNET_YES if the daemon is up, GNUNET_NO if the | ||
830 | * daemon is down, GNUNET_SYSERR on error. | ||
831 | */ | ||
832 | int | ||
833 | GNUNET_TESTING_test_daemon_running (struct GNUNET_TESTING_Daemon *daemon) | ||
834 | { | ||
835 | if (daemon == NULL) | ||
836 | return GNUNET_SYSERR; | ||
837 | |||
838 | if (daemon->running == GNUNET_YES) | ||
839 | return GNUNET_YES; | ||
840 | return GNUNET_NO; | ||
841 | } | ||
842 | |||
843 | |||
844 | /** | ||
845 | * Starts a GNUnet daemon service which has been previously stopped. | ||
846 | * | ||
847 | * @param d the daemon for which the service should be started | ||
848 | * @param service the name of the service to start | ||
849 | * @param timeout how long to wait for process for shutdown to complete | ||
850 | * @param cb function called once the service starts | ||
851 | * @param cb_cls closure for cb | ||
852 | */ | ||
853 | void | ||
854 | GNUNET_TESTING_daemon_start_stopped_service (struct GNUNET_TESTING_Daemon *d, | ||
855 | char *service, | ||
856 | struct GNUNET_TIME_Relative | ||
857 | timeout, | ||
858 | GNUNET_TESTING_NotifyDaemonRunning | ||
859 | cb, void *cb_cls) | ||
860 | { | ||
861 | char *arg; | ||
862 | |||
863 | d->cb = cb; | ||
864 | d->cb_cls = cb_cls; | ||
865 | |||
866 | GNUNET_assert (d->running == GNUNET_YES); | ||
867 | |||
868 | if (d->phase == SP_CONFIG_UPDATE) | ||
869 | { | ||
870 | GNUNET_SCHEDULER_cancel (d->task); | ||
871 | d->phase = SP_START_DONE; | ||
872 | } | ||
873 | |||
874 | if (d->churned_services == NULL) | ||
875 | { | ||
876 | d->cb (d->cb_cls, &d->id, d->cfg, d, | ||
877 | "No service has been churned off yet!!"); | ||
878 | return; | ||
879 | } | ||
880 | d->phase = SP_SERVICE_START; | ||
881 | GNUNET_free (d->churned_services); | ||
882 | d->churned_services = NULL; | ||
883 | d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
884 | /* Check if this is a local or remote process */ | ||
885 | if (NULL != d->hostname) | ||
886 | { | ||
887 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
888 | "Starting gnunet-arm with config `%s' on host `%s'.\n", | ||
889 | d->cfgfile, d->hostname); | ||
890 | if (d->username != NULL) | ||
891 | GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); | ||
892 | else | ||
893 | arg = GNUNET_strdup (d->hostname); | ||
894 | |||
895 | d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", | ||
896 | "-q", | ||
897 | arg, "gnunet-arm", | ||
898 | "-c", d->cfgfile, "-i", service, "-q", | ||
899 | "-T", | ||
900 | GNUNET_TIME_relative_to_string (timeout), | ||
901 | NULL); | ||
902 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
903 | "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q\n", | ||
904 | arg, "gnunet-arm", d->cfgfile, service); | ||
905 | GNUNET_free (arg); | ||
906 | } | ||
907 | else | ||
908 | { | ||
909 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
910 | "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); | ||
911 | d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", | ||
912 | "-c", d->cfgfile, "-i", service, "-q", | ||
913 | "-T", | ||
914 | GNUNET_TIME_relative_to_string (timeout), | ||
915 | NULL); | ||
916 | } | ||
917 | |||
918 | d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
919 | d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); | ||
920 | } | ||
921 | |||
922 | /** | ||
923 | * Starts a GNUnet daemon's service. | ||
924 | * | ||
925 | * @param d the daemon for which the service should be started | ||
926 | * @param service the name of the service to start | ||
927 | * @param timeout how long to wait for process for startup | ||
928 | * @param cb function called once gnunet-arm returns | ||
929 | * @param cb_cls closure for cb | ||
930 | */ | ||
931 | void | ||
932 | GNUNET_TESTING_daemon_start_service (struct GNUNET_TESTING_Daemon *d, | ||
933 | const char *service, | ||
934 | struct GNUNET_TIME_Relative timeout, | ||
935 | GNUNET_TESTING_NotifyDaemonRunning cb, | ||
936 | void *cb_cls) | ||
937 | { | ||
938 | char *arg; | ||
939 | |||
940 | d->cb = cb; | ||
941 | d->cb_cls = cb_cls; | ||
942 | |||
943 | GNUNET_assert (service != NULL); | ||
944 | GNUNET_assert (d->running == GNUNET_YES); | ||
945 | GNUNET_assert (d->phase == SP_START_DONE); | ||
946 | |||
947 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
948 | _("Starting service %s for peer `%4s'\n"), service, | ||
949 | GNUNET_i2s (&d->id)); | ||
950 | d->phase = SP_SERVICE_START; | ||
951 | d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
952 | /* Check if this is a local or remote process */ | ||
953 | if (NULL != d->hostname) | ||
954 | { | ||
955 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
956 | "Starting gnunet-arm with config `%s' on host `%s'.\n", | ||
957 | d->cfgfile, d->hostname); | ||
958 | if (d->username != NULL) | ||
959 | GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); | ||
960 | else | ||
961 | arg = GNUNET_strdup (d->hostname); | ||
962 | |||
963 | d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", | ||
964 | "-q", | ||
965 | arg, "gnunet-arm", | ||
966 | "-c", d->cfgfile, "-i", service, "-q", | ||
967 | "-T", | ||
968 | GNUNET_TIME_relative_to_string (timeout), | ||
969 | NULL); | ||
970 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
971 | "Starting gnunet-arm with command ssh %s gnunet-arm -c %s -i %s -q -T %s\n", | ||
972 | arg, "gnunet-arm", d->cfgfile, service, | ||
973 | GNUNET_TIME_relative_to_string (timeout)); | ||
974 | GNUNET_free (arg); | ||
975 | } | ||
976 | else | ||
977 | { | ||
978 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
979 | "Starting gnunet-arm with config `%s' locally.\n", d->cfgfile); | ||
980 | d->proc_arm_srv_start = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", | ||
981 | "-c", d->cfgfile, "-i", service, "-q", | ||
982 | "-T", | ||
983 | GNUNET_TIME_relative_to_string (timeout), | ||
984 | NULL); | ||
985 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
986 | "Starting gnunet-arm with command %s -c %s -i %s -q -T %s\n", | ||
987 | "gnunet-arm", d->cfgfile, service, | ||
988 | GNUNET_TIME_relative_to_string (timeout)); | ||
989 | } | ||
990 | |||
991 | d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
992 | d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); | ||
993 | } | ||
994 | |||
995 | /** | ||
996 | * Start a peer that has previously been stopped using the daemon_stop | ||
997 | * call (and files weren't deleted and the allow restart flag) | ||
998 | * | ||
999 | * @param daemon the daemon to start (has been previously stopped) | ||
1000 | * @param timeout how long to wait for restart | ||
1001 | * @param cb the callback for notification when the peer is running | ||
1002 | * @param cb_cls closure for the callback | ||
1003 | */ | ||
1004 | void | ||
1005 | GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, | ||
1006 | struct GNUNET_TIME_Relative timeout, | ||
1007 | GNUNET_TESTING_NotifyDaemonRunning cb, | ||
1008 | void *cb_cls) | ||
1009 | { | ||
1010 | if (daemon->running == GNUNET_YES) | ||
1011 | { | ||
1012 | cb (cb_cls, &daemon->id, daemon->cfg, daemon, | ||
1013 | "Daemon already running, can't restart!"); | ||
1014 | return; | ||
1015 | } | ||
1016 | |||
1017 | daemon->cb = cb; | ||
1018 | daemon->cb_cls = cb_cls; | ||
1019 | daemon->phase = SP_TOPOLOGY_SETUP; | ||
1020 | daemon->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1021 | /* FIXME: why add_continuation? */ | ||
1022 | GNUNET_SCHEDULER_add_continuation (&start_fsm, daemon, | ||
1023 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
1024 | } | ||
1025 | |||
1026 | /** | ||
1027 | * Starts a GNUnet daemon. GNUnet must be installed on the target | ||
1028 | * system and available in the PATH. The machine must furthermore be | ||
1029 | * reachable via "ssh" (unless the hostname is "NULL") without the | ||
1030 | * need to enter a password. | ||
1031 | * | ||
1032 | * @param cfg configuration to use | ||
1033 | * @param timeout how long to wait starting up peers | ||
1034 | * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO | ||
1035 | * to really start the peer (default) | ||
1036 | * @param hostname name of the machine where to run GNUnet | ||
1037 | * (use NULL for localhost). | ||
1038 | * @param ssh_username ssh username to use when connecting to hostname | ||
1039 | * @param sshport port to pass to ssh process when connecting to hostname | ||
1040 | * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) | ||
1041 | * @param hostkey_callback function to call once the hostkey has been | ||
1042 | * generated for this peer, but it hasn't yet been started | ||
1043 | * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) | ||
1044 | * @param hostkey_cls closure for hostkey callback | ||
1045 | * @param cb function to call once peer is up, or failed to start | ||
1046 | * @param cb_cls closure for cb | ||
1047 | * @return handle to the daemon (actual start will be completed asynchronously) | ||
1048 | */ | ||
1049 | struct GNUNET_TESTING_Daemon * | ||
1050 | GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1051 | struct GNUNET_TIME_Relative timeout, int pretend, | ||
1052 | const char *hostname, const char *ssh_username, | ||
1053 | uint16_t sshport, const char *hostkey, | ||
1054 | GNUNET_TESTING_NotifyHostkeyCreated | ||
1055 | hostkey_callback, void *hostkey_cls, | ||
1056 | GNUNET_TESTING_NotifyDaemonRunning cb, | ||
1057 | void *cb_cls) | ||
1058 | { | ||
1059 | struct GNUNET_TESTING_Daemon *ret; | ||
1060 | char *arg; | ||
1061 | char *username; | ||
1062 | char *servicehome; | ||
1063 | char *baseservicehome; | ||
1064 | char *slash; | ||
1065 | char *hostkeyfile; | ||
1066 | char *temp_file_name; | ||
1067 | struct GNUNET_DISK_FileHandle *fn; | ||
1068 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; | ||
1069 | struct GNUNET_CRYPTO_RsaPrivateKey *private_key; | ||
1070 | |||
1071 | ret = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Daemon)); | ||
1072 | ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname); | ||
1073 | if (sshport != 0) | ||
1074 | { | ||
1075 | GNUNET_asprintf (&ret->ssh_port_str, "%d", sshport); | ||
1076 | } | ||
1077 | else | ||
1078 | ret->ssh_port_str = NULL; | ||
1079 | |||
1080 | /* Find service home and base service home directories, create it if it doesn't exist */ | ||
1081 | GNUNET_assert (GNUNET_OK == | ||
1082 | GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", | ||
1083 | "SERVICEHOME", | ||
1084 | &servicehome)); | ||
1085 | |||
1086 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_create (servicehome)); | ||
1087 | GNUNET_asprintf (&temp_file_name, "%s/gnunet-testing-config", servicehome); | ||
1088 | ret->cfgfile = GNUNET_DISK_mktemp (temp_file_name); | ||
1089 | GNUNET_free (temp_file_name); | ||
1090 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1091 | "Setting up peer with configuration file `%s'.\n", ret->cfgfile); | ||
1092 | if (NULL == ret->cfgfile) | ||
1093 | { | ||
1094 | GNUNET_free_non_null (ret->ssh_port_str); | ||
1095 | GNUNET_free_non_null (ret->hostname); | ||
1096 | GNUNET_free (ret); | ||
1097 | return NULL; | ||
1098 | } | ||
1099 | ret->hostkey_callback = hostkey_callback; | ||
1100 | ret->hostkey_cls = hostkey_cls; | ||
1101 | ret->cb = cb; | ||
1102 | ret->cb_cls = cb_cls; | ||
1103 | ret->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1104 | ret->cfg = GNUNET_CONFIGURATION_dup (cfg); | ||
1105 | GNUNET_CONFIGURATION_set_value_string (ret->cfg, "PATHS", "DEFAULTCONFIG", | ||
1106 | ret->cfgfile); | ||
1107 | |||
1108 | if (hostkey != NULL) /* Get the peer identity from the hostkey */ | ||
1109 | { | ||
1110 | private_key = GNUNET_CRYPTO_rsa_decode_key (hostkey, HOSTKEYFILESIZE); | ||
1111 | GNUNET_assert (private_key != NULL); | ||
1112 | GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key); | ||
1113 | GNUNET_CRYPTO_hash (&public_key, | ||
1114 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), | ||
1115 | &ret->id.hashPubKey); | ||
1116 | ret->shortname = GNUNET_strdup (GNUNET_i2s (&ret->id)); | ||
1117 | ret->have_hostkey = GNUNET_YES; | ||
1118 | GNUNET_CRYPTO_rsa_key_free (private_key); | ||
1119 | } | ||
1120 | |||
1121 | /* Write hostkey to file, if we were given one */ | ||
1122 | hostkeyfile = NULL; | ||
1123 | if (hostkey != NULL) | ||
1124 | { | ||
1125 | GNUNET_asprintf (&hostkeyfile, "%s/.hostkey", servicehome); | ||
1126 | fn = GNUNET_DISK_file_open (hostkeyfile, | ||
1127 | GNUNET_DISK_OPEN_READWRITE | | ||
1128 | GNUNET_DISK_OPEN_CREATE, | ||
1129 | GNUNET_DISK_PERM_USER_READ | | ||
1130 | GNUNET_DISK_PERM_USER_WRITE); | ||
1131 | GNUNET_assert (fn != NULL); | ||
1132 | GNUNET_assert (HOSTKEYFILESIZE == | ||
1133 | GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE)); | ||
1134 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn)); | ||
1135 | } | ||
1136 | |||
1137 | /* write configuration to temporary file */ | ||
1138 | if (GNUNET_OK != GNUNET_CONFIGURATION_write (ret->cfg, ret->cfgfile)) | ||
1139 | { | ||
1140 | if (0 != UNLINK (ret->cfgfile)) | ||
1141 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", | ||
1142 | ret->cfgfile); | ||
1143 | GNUNET_CONFIGURATION_destroy (ret->cfg); | ||
1144 | GNUNET_free_non_null (ret->hostname); | ||
1145 | GNUNET_free (ret->cfgfile); | ||
1146 | GNUNET_free (ret); | ||
1147 | return NULL; | ||
1148 | } | ||
1149 | if (ssh_username != NULL) | ||
1150 | username = GNUNET_strdup (ssh_username); | ||
1151 | if ((ssh_username == NULL) && | ||
1152 | (GNUNET_OK != | ||
1153 | GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "USERNAME", | ||
1154 | &username))) | ||
1155 | { | ||
1156 | if (NULL != getenv ("USER")) | ||
1157 | username = GNUNET_strdup (getenv ("USER")); | ||
1158 | else | ||
1159 | username = NULL; | ||
1160 | } | ||
1161 | ret->username = username; | ||
1162 | |||
1163 | if (GNUNET_NO == pretend) /* Copy files, enter finite state machine */ | ||
1164 | { | ||
1165 | /* copy directory to remote host */ | ||
1166 | if (NULL != hostname) | ||
1167 | { | ||
1168 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1169 | "Copying configuration directory to host `%s'.\n", hostname); | ||
1170 | baseservicehome = GNUNET_strdup (servicehome); | ||
1171 | /* Remove trailing /'s */ | ||
1172 | while (baseservicehome[strlen (baseservicehome) - 1] == '/') | ||
1173 | baseservicehome[strlen (baseservicehome) - 1] = '\0'; | ||
1174 | /* Find next directory /, jump one ahead */ | ||
1175 | slash = strrchr (baseservicehome, '/'); | ||
1176 | if (slash != NULL) | ||
1177 | *(++slash) = '\0'; | ||
1178 | |||
1179 | ret->phase = SP_COPYING; | ||
1180 | if (NULL != username) | ||
1181 | GNUNET_asprintf (&arg, "%s@%s:%s", username, hostname, baseservicehome); | ||
1182 | else | ||
1183 | GNUNET_asprintf (&arg, "%s:%s", hostname, baseservicehome); | ||
1184 | GNUNET_free (baseservicehome); | ||
1185 | if (ret->ssh_port_str == NULL) | ||
1186 | { | ||
1187 | ret->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", | ||
1188 | "-q", | ||
1189 | servicehome, arg, NULL); | ||
1190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1191 | "copying directory with command scp -r %s %s\n", | ||
1192 | servicehome, arg); | ||
1193 | } | ||
1194 | else | ||
1195 | { | ||
1196 | ret->proc_arm_copying = | ||
1197 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", "-r", "-P", | ||
1198 | ret->ssh_port_str, | ||
1199 | "-q", | ||
1200 | servicehome, arg, NULL); | ||
1201 | } | ||
1202 | GNUNET_free (arg); | ||
1203 | if (NULL == ret->proc_arm_copying) | ||
1204 | { | ||
1205 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1206 | _ | ||
1207 | ("Could not start `%s' process to copy configuration directory.\n"), | ||
1208 | "scp"); | ||
1209 | if (0 != UNLINK (ret->cfgfile)) | ||
1210 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", | ||
1211 | ret->cfgfile); | ||
1212 | GNUNET_CONFIGURATION_destroy (ret->cfg); | ||
1213 | GNUNET_free_non_null (ret->hostname); | ||
1214 | GNUNET_free_non_null (ret->username); | ||
1215 | GNUNET_free (ret->cfgfile); | ||
1216 | GNUNET_free (ret); | ||
1217 | if ((hostkey != NULL) && (0 != UNLINK (hostkeyfile))) | ||
1218 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", | ||
1219 | hostkeyfile); | ||
1220 | GNUNET_free_non_null (hostkeyfile); | ||
1221 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_directory_remove (servicehome)); | ||
1222 | GNUNET_free (servicehome); | ||
1223 | return NULL; | ||
1224 | } | ||
1225 | |||
1226 | ret->task = | ||
1227 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, | ||
1228 | ret); | ||
1229 | GNUNET_free_non_null (hostkeyfile); | ||
1230 | GNUNET_free (servicehome); | ||
1231 | return ret; | ||
1232 | } | ||
1233 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1234 | "No need to copy configuration file since we are running locally.\n"); | ||
1235 | ret->phase = SP_COPIED; | ||
1236 | /* FIXME: why add_cont? */ | ||
1237 | GNUNET_SCHEDULER_add_continuation (&start_fsm, ret, | ||
1238 | GNUNET_SCHEDULER_REASON_PREREQ_DONE); | ||
1239 | } | ||
1240 | GNUNET_free_non_null (hostkeyfile); | ||
1241 | GNUNET_free (servicehome); | ||
1242 | return ret; | ||
1243 | } | ||
1244 | |||
1245 | |||
1246 | /** | ||
1247 | * Restart (stop and start) a GNUnet daemon. | ||
1248 | * | ||
1249 | * @param d the daemon that should be restarted | ||
1250 | * @param cb function called once the daemon is (re)started | ||
1251 | * @param cb_cls closure for cb | ||
1252 | */ | ||
1253 | void | ||
1254 | GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, | ||
1255 | GNUNET_TESTING_NotifyDaemonRunning cb, | ||
1256 | void *cb_cls) | ||
1257 | { | ||
1258 | char *arg; | ||
1259 | char *del_arg; | ||
1260 | |||
1261 | del_arg = NULL; | ||
1262 | if (NULL != d->cb) | ||
1263 | { | ||
1264 | d->dead = GNUNET_YES; | ||
1265 | return; | ||
1266 | } | ||
1267 | |||
1268 | d->cb = cb; | ||
1269 | d->cb_cls = cb_cls; | ||
1270 | |||
1271 | if (d->phase == SP_CONFIG_UPDATE) | ||
1272 | { | ||
1273 | GNUNET_SCHEDULER_cancel (d->task); | ||
1274 | d->phase = SP_START_DONE; | ||
1275 | } | ||
1276 | if (d->server != NULL) | ||
1277 | { | ||
1278 | GNUNET_CORE_disconnect (d->server); | ||
1279 | d->server = NULL; | ||
1280 | } | ||
1281 | |||
1282 | if (d->th != NULL) | ||
1283 | { | ||
1284 | GNUNET_TRANSPORT_get_hello_cancel (d->ghh); | ||
1285 | d->ghh = NULL; | ||
1286 | GNUNET_TRANSPORT_disconnect (d->th); | ||
1287 | d->th = NULL; | ||
1288 | } | ||
1289 | /* state clean up and notifications */ | ||
1290 | GNUNET_free_non_null (d->hello); | ||
1291 | |||
1292 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), | ||
1293 | GNUNET_i2s (&d->id)); | ||
1294 | d->phase = SP_START_ARMING; | ||
1295 | |||
1296 | /* Check if this is a local or remote process */ | ||
1297 | if (NULL != d->hostname) | ||
1298 | { | ||
1299 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1300 | "Stopping gnunet-arm with config `%s' on host `%s'.\n", | ||
1301 | d->cfgfile, d->hostname); | ||
1302 | if (d->username != NULL) | ||
1303 | GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); | ||
1304 | else | ||
1305 | arg = GNUNET_strdup (d->hostname); | ||
1306 | |||
1307 | d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", | ||
1308 | "-q", | ||
1309 | arg, "gnunet-arm", | ||
1310 | "-c", d->cfgfile, "-e", "-r", NULL); | ||
1311 | /* Use -r to restart arm and all services */ | ||
1312 | |||
1313 | GNUNET_free (arg); | ||
1314 | } | ||
1315 | else | ||
1316 | { | ||
1317 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1318 | "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); | ||
1319 | d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", | ||
1320 | "-c", d->cfgfile, "-e", "-r", NULL); | ||
1321 | } | ||
1322 | |||
1323 | GNUNET_free_non_null (del_arg); | ||
1324 | d->task = | ||
1325 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); | ||
1326 | |||
1327 | } | ||
1328 | |||
1329 | |||
1330 | /** | ||
1331 | * Stops a GNUnet daemon. | ||
1332 | * | ||
1333 | * @param d the daemon that should be stopped | ||
1334 | * @param service the name of the service to stop | ||
1335 | * @param timeout how long to wait for process for shutdown to complete | ||
1336 | * @param cb function called once the daemon was stopped | ||
1337 | * @param cb_cls closure for cb | ||
1338 | */ | ||
1339 | void | ||
1340 | GNUNET_TESTING_daemon_stop_service (struct GNUNET_TESTING_Daemon *d, | ||
1341 | const char *service, | ||
1342 | struct GNUNET_TIME_Relative timeout, | ||
1343 | GNUNET_TESTING_NotifyCompletion cb, | ||
1344 | void *cb_cls) | ||
1345 | { | ||
1346 | char *arg; | ||
1347 | |||
1348 | d->dead_cb = cb; | ||
1349 | d->dead_cb_cls = cb_cls; | ||
1350 | |||
1351 | GNUNET_assert (d->running == GNUNET_YES); | ||
1352 | |||
1353 | if (d->phase == SP_CONFIG_UPDATE) | ||
1354 | { | ||
1355 | GNUNET_SCHEDULER_cancel (d->task); | ||
1356 | d->phase = SP_START_DONE; | ||
1357 | } | ||
1358 | |||
1359 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Terminating peer `%4s'\n"), | ||
1360 | GNUNET_i2s (&d->id)); | ||
1361 | if (d->churned_services != NULL) | ||
1362 | { | ||
1363 | d->dead_cb (d->dead_cb_cls, "A service has already been turned off!!"); | ||
1364 | return; | ||
1365 | } | ||
1366 | d->phase = SP_SERVICE_SHUTDOWN_START; | ||
1367 | d->churned_services = GNUNET_strdup (service); | ||
1368 | d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1369 | /* Check if this is a local or remote process */ | ||
1370 | if (NULL != d->hostname) | ||
1371 | { | ||
1372 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1373 | "Stopping gnunet-arm with config `%s' on host `%s'.\n", | ||
1374 | d->cfgfile, d->hostname); | ||
1375 | if (d->username != NULL) | ||
1376 | GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); | ||
1377 | else | ||
1378 | arg = GNUNET_strdup (d->hostname); | ||
1379 | |||
1380 | d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", | ||
1381 | "-q", | ||
1382 | arg, "gnunet-arm", | ||
1383 | "-c", d->cfgfile, "-k", service, "-q", | ||
1384 | "-T", | ||
1385 | GNUNET_TIME_relative_to_string (timeout), | ||
1386 | NULL); | ||
1387 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1388 | "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -k %s -q\n", | ||
1389 | arg, "gnunet-arm", d->cfgfile, service); | ||
1390 | GNUNET_free (arg); | ||
1391 | } | ||
1392 | else | ||
1393 | { | ||
1394 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1395 | "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); | ||
1396 | d->proc_arm_srv_stop = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-arm", "gnunet-arm", | ||
1397 | "-c", d->cfgfile, "-k", service, "-q", | ||
1398 | "-T", | ||
1399 | GNUNET_TIME_relative_to_string (timeout), | ||
1400 | NULL); | ||
1401 | } | ||
1402 | |||
1403 | d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1404 | d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); | ||
1405 | } | ||
1406 | |||
1407 | |||
1408 | /** | ||
1409 | * Forcefully terminate a process and clean up the child. | ||
1410 | * | ||
1411 | * @param proc handle to process to kill | ||
1412 | */ | ||
1413 | static void | ||
1414 | kill_and_close_process (struct GNUNET_OS_Process *proc) | ||
1415 | { | ||
1416 | (void) GNUNET_OS_process_kill (proc, SIGKILL); | ||
1417 | GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc)); | ||
1418 | GNUNET_OS_process_destroy (proc); | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | /** | ||
1423 | * Stops a GNUnet daemon. | ||
1424 | * | ||
1425 | * @param d the daemon that should be stopped | ||
1426 | * @param timeout how long to wait for process for shutdown to complete | ||
1427 | * @param cb function called once the daemon was stopped | ||
1428 | * @param cb_cls closure for cb | ||
1429 | * @param delete_files GNUNET_YES to remove files, GNUNET_NO | ||
1430 | * to leave them | ||
1431 | * @param allow_restart GNUNET_YES to restart peer later (using this API) | ||
1432 | * GNUNET_NO to kill off and clean up for good | ||
1433 | */ | ||
1434 | void | ||
1435 | GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, | ||
1436 | struct GNUNET_TIME_Relative timeout, | ||
1437 | GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, | ||
1438 | int delete_files, int allow_restart) | ||
1439 | { | ||
1440 | char *arg; | ||
1441 | char *del_arg; | ||
1442 | |||
1443 | d->dead_cb = cb; | ||
1444 | d->dead_cb_cls = cb_cls; | ||
1445 | |||
1446 | if (NULL != d->cb) | ||
1447 | { | ||
1448 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Setting d->dead on peer `%4s'\n"), | ||
1449 | GNUNET_i2s (&d->id)); | ||
1450 | d->dead = GNUNET_YES; | ||
1451 | return; | ||
1452 | } | ||
1453 | if (NULL != d->proc_arm_start) | ||
1454 | { | ||
1455 | kill_and_close_process (d->proc_arm_start); | ||
1456 | d->proc_arm_start = NULL; | ||
1457 | } | ||
1458 | if (NULL != d->proc_arm_srv_start) | ||
1459 | { | ||
1460 | kill_and_close_process (d->proc_arm_srv_start); | ||
1461 | d->proc_arm_srv_start = NULL; | ||
1462 | } | ||
1463 | if (NULL != d->proc_arm_srv_stop) | ||
1464 | { | ||
1465 | kill_and_close_process (d->proc_arm_srv_stop); | ||
1466 | d->proc_arm_srv_stop = NULL; | ||
1467 | } | ||
1468 | if (NULL != d->proc_arm_copying) | ||
1469 | { | ||
1470 | kill_and_close_process (d->proc_arm_copying); | ||
1471 | d->proc_arm_copying = NULL; | ||
1472 | } | ||
1473 | if (NULL != d->proc_arm_peerinfo) | ||
1474 | { | ||
1475 | kill_and_close_process (d->proc_arm_peerinfo); | ||
1476 | d->proc_arm_peerinfo = NULL; | ||
1477 | } | ||
1478 | if ((d->running == GNUNET_NO) && (d->churn == GNUNET_YES)) | ||
1479 | { | ||
1480 | /* Peer has already been stopped in churn context! | ||
1481 | * Free what was left from churning! */ | ||
1482 | GNUNET_assert (d->cfg != NULL); | ||
1483 | GNUNET_CONFIGURATION_destroy (d->cfg); | ||
1484 | if (delete_files == GNUNET_YES) | ||
1485 | { | ||
1486 | if (0 != UNLINK (d->cfgfile)) | ||
1487 | { | ||
1488 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "unlink"); | ||
1489 | } | ||
1490 | } | ||
1491 | GNUNET_free (d->cfgfile); | ||
1492 | GNUNET_free_non_null (d->hostname); | ||
1493 | GNUNET_free_non_null (d->username); | ||
1494 | if (NULL != d->dead_cb) | ||
1495 | d->dead_cb (d->dead_cb_cls, NULL); | ||
1496 | /* FIXME: this should be an assert and the test below | ||
1497 | should not be required, but testing is broken... */ | ||
1498 | GNUNET_break (NULL == d->proc_arm_stop); | ||
1499 | if (NULL == d->proc_arm_stop) | ||
1500 | GNUNET_free (d); | ||
1501 | return; | ||
1502 | } | ||
1503 | |||
1504 | del_arg = NULL; | ||
1505 | if (delete_files == GNUNET_YES) | ||
1506 | { | ||
1507 | GNUNET_asprintf (&del_arg, "-d"); | ||
1508 | } | ||
1509 | |||
1510 | if (d->phase == SP_CONFIG_UPDATE) | ||
1511 | { | ||
1512 | GNUNET_SCHEDULER_cancel (d->task); | ||
1513 | d->phase = SP_START_DONE; | ||
1514 | } | ||
1515 | /** Move this call to scheduled shutdown as fix for CORE_connect calling daemon_stop? | ||
1516 | if (d->server != NULL) | ||
1517 | { | ||
1518 | GNUNET_CORE_disconnect (d->server); | ||
1519 | d->server = NULL; | ||
1520 | } | ||
1521 | */ | ||
1522 | /* shutdown ARM process (will terminate others) */ | ||
1523 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminating peer `%4s'\n" , | ||
1524 | GNUNET_i2s (&d->id)); | ||
1525 | d->phase = SP_SHUTDOWN_START; | ||
1526 | d->running = GNUNET_NO; | ||
1527 | if (allow_restart == GNUNET_YES) | ||
1528 | d->churn = GNUNET_YES; | ||
1529 | if (d->th != NULL) | ||
1530 | { | ||
1531 | GNUNET_TRANSPORT_get_hello_cancel (d->ghh); | ||
1532 | d->ghh = NULL; | ||
1533 | GNUNET_TRANSPORT_disconnect (d->th); | ||
1534 | d->th = NULL; | ||
1535 | } | ||
1536 | /* Check if this is a local or remote process */ | ||
1537 | |||
1538 | |||
1539 | if (NULL != d->hostname) | ||
1540 | { | ||
1541 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1542 | "Stopping gnunet-arm with config `%s' on host `%s'.\n", | ||
1543 | d->cfgfile, d->hostname); | ||
1544 | if (d->username != NULL) | ||
1545 | GNUNET_asprintf (&arg, "%s@%s", d->username, d->hostname); | ||
1546 | else | ||
1547 | arg = GNUNET_strdup (d->hostname); | ||
1548 | |||
1549 | d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", | ||
1550 | "-q", | ||
1551 | arg, "gnunet-arm", | ||
1552 | "-c", d->cfgfile, "-e", "-q", "-T", | ||
1553 | GNUNET_TIME_relative_to_string (timeout), | ||
1554 | del_arg, NULL); | ||
1555 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1556 | "Stopping gnunet-arm with command ssh %s gnunet-arm -c %s -e -q %s\n", | ||
1557 | arg, "gnunet-arm", d->cfgfile, del_arg); | ||
1558 | /* Use -e to end arm, and -d to remove temp files */ | ||
1559 | GNUNET_free (arg); | ||
1560 | } | ||
1561 | else | ||
1562 | { | ||
1563 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1564 | "Stopping gnunet-arm with config `%s' locally.\n", d->cfgfile); | ||
1565 | d->proc_arm_stop = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "gnunet-arm", "gnunet-arm", | ||
1566 | "-c", d->cfgfile, "-e", "-q", "-T", | ||
1567 | GNUNET_TIME_relative_to_string (timeout), | ||
1568 | del_arg, NULL); | ||
1569 | GNUNET_assert (NULL != d->proc_arm_stop); | ||
1570 | } | ||
1571 | |||
1572 | GNUNET_free_non_null (del_arg); | ||
1573 | d->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1574 | if (GNUNET_SCHEDULER_NO_TASK != d->task) | ||
1575 | GNUNET_SCHEDULER_cancel(d->task); | ||
1576 | d->task = GNUNET_SCHEDULER_add_now (&start_fsm, d); | ||
1577 | } | ||
1578 | |||
1579 | |||
1580 | /** | ||
1581 | * Changes the configuration of a GNUnet daemon. | ||
1582 | * | ||
1583 | * @param d the daemon that should be modified | ||
1584 | * @param cfg the new configuration for the daemon | ||
1585 | * @param cb function called once the configuration was changed | ||
1586 | * @param cb_cls closure for cb | ||
1587 | */ | ||
1588 | void | ||
1589 | GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, | ||
1590 | struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1591 | GNUNET_TESTING_NotifyCompletion cb, | ||
1592 | void *cb_cls) | ||
1593 | { | ||
1594 | char *arg; | ||
1595 | |||
1596 | if (d->phase != SP_START_DONE) | ||
1597 | { | ||
1598 | if (NULL != cb) | ||
1599 | cb (cb_cls, | ||
1600 | _ | ||
1601 | ("Peer not yet running, can not change configuration at this point.")); | ||
1602 | return; | ||
1603 | } | ||
1604 | |||
1605 | /* 1) write configuration to temporary file */ | ||
1606 | if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, d->cfgfile)) | ||
1607 | { | ||
1608 | if (NULL != cb) | ||
1609 | cb (cb_cls, _("Failed to write new configuration to disk.")); | ||
1610 | return; | ||
1611 | } | ||
1612 | |||
1613 | /* 2) copy file to remote host (if necessary) */ | ||
1614 | if (NULL == d->hostname) | ||
1615 | { | ||
1616 | /* signal success */ | ||
1617 | if (NULL != cb) | ||
1618 | cb (cb_cls, NULL); | ||
1619 | return; | ||
1620 | } | ||
1621 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1622 | "Copying updated configuration file to remote host `%s'.\n", | ||
1623 | d->hostname); | ||
1624 | d->phase = SP_CONFIG_UPDATE; | ||
1625 | if (NULL != d->username) | ||
1626 | GNUNET_asprintf (&arg, "%s@%s:%s", d->username, d->hostname, d->cfgfile); | ||
1627 | else | ||
1628 | GNUNET_asprintf (&arg, "%s:%s", d->hostname, d->cfgfile); | ||
1629 | d->proc_arm_copying = GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", | ||
1630 | "-q", | ||
1631 | d->cfgfile, arg, NULL); | ||
1632 | GNUNET_free (arg); | ||
1633 | if (NULL == d->proc_arm_copying) | ||
1634 | { | ||
1635 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1636 | _("Could not start `%s' process to copy configuration file.\n"), | ||
1637 | "scp"); | ||
1638 | if (NULL != cb) | ||
1639 | cb (cb_cls, _("Failed to copy new configuration to remote machine.")); | ||
1640 | d->phase = SP_START_DONE; | ||
1641 | return; | ||
1642 | } | ||
1643 | d->update_cb = cb; | ||
1644 | d->update_cb_cls = cb_cls; | ||
1645 | d->task = | ||
1646 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, &start_fsm, d); | ||
1647 | } | ||
1648 | |||
1649 | |||
1650 | /** | ||
1651 | * Data kept for each pair of peers that we try | ||
1652 | * to connect. | ||
1653 | */ | ||
1654 | struct GNUNET_TESTING_ConnectContext | ||
1655 | { | ||
1656 | /** | ||
1657 | * Testing handle to the first daemon. | ||
1658 | */ | ||
1659 | struct GNUNET_TESTING_Daemon *d1; | ||
1660 | |||
1661 | /** | ||
1662 | * Handle to core of first daemon (to check connect) | ||
1663 | */ | ||
1664 | struct GNUNET_CORE_Handle *d1core; | ||
1665 | |||
1666 | /** | ||
1667 | * Have we actually connected to the core of the first daemon yet? | ||
1668 | */ | ||
1669 | int d1core_ready; | ||
1670 | |||
1671 | /** | ||
1672 | * Testing handle to the second daemon. | ||
1673 | */ | ||
1674 | struct GNUNET_TESTING_Daemon *d2; | ||
1675 | |||
1676 | /** | ||
1677 | * Transport handle to the first daemon (to offer the HELLO of the second daemon to). | ||
1678 | */ | ||
1679 | struct GNUNET_TRANSPORT_Handle *d1th; | ||
1680 | |||
1681 | /** | ||
1682 | * Function to call once we are done (or have timed out). | ||
1683 | */ | ||
1684 | GNUNET_TESTING_NotifyConnection cb; | ||
1685 | |||
1686 | /** | ||
1687 | * Closure for "nb". | ||
1688 | */ | ||
1689 | void *cb_cls; | ||
1690 | |||
1691 | /** | ||
1692 | * The relative timeout from whence this connect attempt was | ||
1693 | * started. Allows for reconnect attempts. | ||
1694 | */ | ||
1695 | struct GNUNET_TIME_Relative relative_timeout; | ||
1696 | |||
1697 | /** | ||
1698 | * Maximum number of connect attempts, will retry connection | ||
1699 | * this number of times on failures. | ||
1700 | */ | ||
1701 | unsigned int connect_attempts; | ||
1702 | |||
1703 | /** | ||
1704 | * Hello timeout task | ||
1705 | */ | ||
1706 | GNUNET_SCHEDULER_TaskIdentifier hello_send_task; | ||
1707 | |||
1708 | /** | ||
1709 | * Connect timeout task | ||
1710 | */ | ||
1711 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
1712 | |||
1713 | /** | ||
1714 | * When should this operation be complete (or we must trigger | ||
1715 | * a timeout). | ||
1716 | */ | ||
1717 | struct GNUNET_TIME_Relative timeout_hello; | ||
1718 | |||
1719 | /** | ||
1720 | * Was the connection attempt successful? | ||
1721 | */ | ||
1722 | int connected; | ||
1723 | |||
1724 | /** | ||
1725 | * When connecting, do we need to send the HELLO? | ||
1726 | */ | ||
1727 | int send_hello; | ||
1728 | |||
1729 | /** | ||
1730 | * The distance between the two connected peers | ||
1731 | */ | ||
1732 | uint32_t distance; | ||
1733 | }; | ||
1734 | |||
1735 | |||
1736 | /** Forward declaration **/ | ||
1737 | static void | ||
1738 | reattempt_daemons_connect (void *cls, | ||
1739 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
1740 | |||
1741 | |||
1742 | /** | ||
1743 | * Notify callback about success or failure of the attempt | ||
1744 | * to connect the two peers | ||
1745 | * | ||
1746 | * @param cls our "struct GNUNET_TESTING_ConnectContext" (freed) | ||
1747 | * @param tc reason tells us if we succeeded or failed | ||
1748 | */ | ||
1749 | static void | ||
1750 | notify_connect_result (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1751 | { | ||
1752 | struct GNUNET_TESTING_ConnectContext *ctx = cls; | ||
1753 | |||
1754 | ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
1755 | if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) | ||
1756 | { | ||
1757 | GNUNET_SCHEDULER_cancel (ctx->hello_send_task); | ||
1758 | ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; | ||
1759 | } | ||
1760 | |||
1761 | if (ctx->d1th != NULL) | ||
1762 | GNUNET_TRANSPORT_disconnect (ctx->d1th); | ||
1763 | ctx->d1th = NULL; | ||
1764 | if (ctx->d1core != NULL) | ||
1765 | GNUNET_CORE_disconnect (ctx->d1core); | ||
1766 | ctx->d1core = NULL; | ||
1767 | |||
1768 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
1769 | { | ||
1770 | GNUNET_free (ctx); | ||
1771 | return; | ||
1772 | } | ||
1773 | |||
1774 | if (ctx->connected == GNUNET_YES) | ||
1775 | { | ||
1776 | if (ctx->cb != NULL) | ||
1777 | { | ||
1778 | ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, ctx->distance, | ||
1779 | ctx->d1->cfg, ctx->d2->cfg, ctx->d1, ctx->d2, NULL); | ||
1780 | } | ||
1781 | } | ||
1782 | else if (ctx->connect_attempts > 0) | ||
1783 | { | ||
1784 | ctx->d1core_ready = GNUNET_NO; | ||
1785 | ctx->timeout_task = | ||
1786 | GNUNET_SCHEDULER_add_now (&reattempt_daemons_connect, ctx); | ||
1787 | return; | ||
1788 | } | ||
1789 | else | ||
1790 | { | ||
1791 | if (ctx->cb != NULL) | ||
1792 | { | ||
1793 | ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, | ||
1794 | ctx->d2->cfg, ctx->d1, ctx->d2, _("Peers failed to connect")); | ||
1795 | } | ||
1796 | } | ||
1797 | GNUNET_free (ctx); | ||
1798 | } | ||
1799 | |||
1800 | |||
1801 | /** | ||
1802 | * Success, connection is up. Signal client our success. | ||
1803 | * | ||
1804 | * @param cls our "struct GNUNET_TESTING_ConnectContext" | ||
1805 | * @param peer identity of the peer that has connected | ||
1806 | * @param atsi performance information | ||
1807 | * @param atsi_count number of records in 'atsi' | ||
1808 | * | ||
1809 | */ | ||
1810 | static void | ||
1811 | connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
1812 | const struct GNUNET_ATS_Information *atsi, | ||
1813 | unsigned int atsi_count) | ||
1814 | { | ||
1815 | struct GNUNET_TESTING_ConnectContext *ctx = cls; | ||
1816 | |||
1817 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", | ||
1818 | ctx->d1->shortname, GNUNET_i2s (peer)); | ||
1819 | if (0 != memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity))) | ||
1820 | return; | ||
1821 | ctx->connected = GNUNET_YES; | ||
1822 | ctx->distance = 0; /* FIXME: distance */ | ||
1823 | if (ctx->hello_send_task != GNUNET_SCHEDULER_NO_TASK) | ||
1824 | { | ||
1825 | GNUNET_SCHEDULER_cancel (ctx->hello_send_task); | ||
1826 | ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; | ||
1827 | } | ||
1828 | GNUNET_SCHEDULER_cancel (ctx->timeout_task); | ||
1829 | ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); | ||
1830 | } | ||
1831 | |||
1832 | |||
1833 | static void | ||
1834 | send_hello (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1835 | { | ||
1836 | struct GNUNET_TESTING_ConnectContext *ctx = cls; | ||
1837 | struct GNUNET_MessageHeader *hello; | ||
1838 | |||
1839 | ctx->hello_send_task = GNUNET_SCHEDULER_NO_TASK; | ||
1840 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
1841 | return; | ||
1842 | if ((ctx->d1core_ready == GNUNET_YES) && (ctx->d2->hello != NULL) && | ||
1843 | (NULL != GNUNET_HELLO_get_header (ctx->d2->hello)) && | ||
1844 | (ctx->d1->phase == SP_START_DONE) && (ctx->d2->phase == SP_START_DONE)) | ||
1845 | { | ||
1846 | hello = GNUNET_HELLO_get_header (ctx->d2->hello); | ||
1847 | GNUNET_assert (hello != NULL); | ||
1848 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Offering hello of %s to %s\n", | ||
1849 | ctx->d2->shortname, ctx->d1->shortname); | ||
1850 | GNUNET_TRANSPORT_offer_hello (ctx->d1th, hello, NULL, NULL); | ||
1851 | GNUNET_assert (ctx->d1core != NULL); | ||
1852 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1853 | "Sending connect request to TRANSPORT of %s for peer %s\n", | ||
1854 | GNUNET_i2s (&ctx->d1->id), | ||
1855 | GNUNET_h2s (&ctx->d2->id.hashPubKey)); | ||
1856 | GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); | ||
1857 | ctx->timeout_hello = | ||
1858 | GNUNET_TIME_relative_add (ctx->timeout_hello, | ||
1859 | GNUNET_TIME_relative_multiply | ||
1860 | (GNUNET_TIME_UNIT_MILLISECONDS, 500)); | ||
1861 | } | ||
1862 | ctx->hello_send_task = | ||
1863 | GNUNET_SCHEDULER_add_delayed (ctx->timeout_hello, &send_hello, ctx); | ||
1864 | } | ||
1865 | |||
1866 | /** | ||
1867 | * Notify of a successful connection to the core service. | ||
1868 | * | ||
1869 | * @param cls a ConnectContext | ||
1870 | * @param server handle to the core service | ||
1871 | * @param my_identity the peer identity of this peer | ||
1872 | */ | ||
1873 | void | ||
1874 | core_init_notify (void *cls, struct GNUNET_CORE_Handle *server, | ||
1875 | const struct GNUNET_PeerIdentity *my_identity) | ||
1876 | { | ||
1877 | struct GNUNET_TESTING_ConnectContext *connect_ctx = cls; | ||
1878 | |||
1879 | connect_ctx->d1core_ready = GNUNET_YES; | ||
1880 | |||
1881 | if (connect_ctx->send_hello == GNUNET_NO) | ||
1882 | { | ||
1883 | GNUNET_TRANSPORT_try_connect (connect_ctx->d1th, &connect_ctx->d2->id); | ||
1884 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1885 | "Sending connect request to TRANSPORT of %s for peer %s\n", | ||
1886 | connect_ctx->d1->shortname, connect_ctx->d2->shortname); | ||
1887 | } | ||
1888 | } | ||
1889 | |||
1890 | |||
1891 | /** | ||
1892 | * Try to connect again some peers that failed in an earlier attempt. This will | ||
1893 | * be tried as many times as connection_attempts in the configuration file. | ||
1894 | * | ||
1895 | * @param cls Closure (connection context between the two peers). | ||
1896 | * @param tc TaskContext. | ||
1897 | */ | ||
1898 | static void | ||
1899 | reattempt_daemons_connect (void *cls, | ||
1900 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1901 | { | ||
1902 | struct GNUNET_TESTING_ConnectContext *ctx = cls; | ||
1903 | |||
1904 | ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
1905 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
1906 | return; | ||
1907 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1908 | "re-attempting connect of peer %s to peer %s\n", | ||
1909 | ctx->d1->shortname, ctx->d2->shortname); | ||
1910 | ctx->connect_attempts--; | ||
1911 | GNUNET_assert (ctx->d1core == NULL); | ||
1912 | ctx->d1core_ready = GNUNET_NO; | ||
1913 | ctx->d1core = | ||
1914 | GNUNET_CORE_connect (ctx->d1->cfg, ctx, &core_init_notify, | ||
1915 | &connect_notify, NULL, NULL, GNUNET_NO, NULL, | ||
1916 | GNUNET_NO, no_handlers); | ||
1917 | if (ctx->d1core == NULL) | ||
1918 | { | ||
1919 | if (NULL != ctx->cb) | ||
1920 | ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, | ||
1921 | ctx->d2->cfg, ctx->d1, ctx->d2, | ||
1922 | _("Failed to connect to core service of first peer!\n")); | ||
1923 | GNUNET_free (ctx); | ||
1924 | return; | ||
1925 | } | ||
1926 | |||
1927 | /* Don't know reason for initial connect failure, update the HELLO for the second peer */ | ||
1928 | if (NULL != ctx->d2->hello) | ||
1929 | { | ||
1930 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "updating %s's HELLO\n", | ||
1931 | ctx->d2->shortname); | ||
1932 | GNUNET_free (ctx->d2->hello); | ||
1933 | ctx->d2->hello = NULL; | ||
1934 | if (NULL != ctx->d2->th) | ||
1935 | { | ||
1936 | GNUNET_TRANSPORT_get_hello_cancel (ctx->d2->ghh); | ||
1937 | ctx->d2->ghh = NULL; | ||
1938 | GNUNET_TRANSPORT_disconnect (ctx->d2->th); | ||
1939 | } | ||
1940 | ctx->d2->th = | ||
1941 | GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, | ||
1942 | NULL); | ||
1943 | GNUNET_assert (ctx->d2->th != NULL); | ||
1944 | ctx->d2->ghh = | ||
1945 | GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); | ||
1946 | } | ||
1947 | else | ||
1948 | { | ||
1949 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "didn't have %s's HELLO\n", | ||
1950 | ctx->d2->shortname); | ||
1951 | } | ||
1952 | |||
1953 | if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) | ||
1954 | { | ||
1955 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1956 | "didn't have %s's HELLO, trying to get it now\n", | ||
1957 | ctx->d2->shortname); | ||
1958 | ctx->d2->th = | ||
1959 | GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, | ||
1960 | NULL); | ||
1961 | if (NULL == ctx->d2->th) | ||
1962 | { | ||
1963 | GNUNET_CORE_disconnect (ctx->d1core); | ||
1964 | GNUNET_free (ctx); | ||
1965 | if (NULL != ctx->cb) | ||
1966 | ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, | ||
1967 | ctx->d2->cfg, ctx->d1, ctx->d2, | ||
1968 | _("Failed to connect to transport service!\n")); | ||
1969 | return; | ||
1970 | } | ||
1971 | ctx->d2->ghh = | ||
1972 | GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); | ||
1973 | } | ||
1974 | else | ||
1975 | { | ||
1976 | if (NULL == ctx->d2->hello) | ||
1977 | { | ||
1978 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1979 | "didn't have %s's HELLO but th wasn't NULL, not trying!!\n", | ||
1980 | ctx->d2->shortname); | ||
1981 | } | ||
1982 | } | ||
1983 | |||
1984 | if (ctx->send_hello == GNUNET_YES) | ||
1985 | { | ||
1986 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending %s's HELLO to %s\n", | ||
1987 | ctx->d1->shortname, ctx->d2->shortname); | ||
1988 | ctx->d1th = | ||
1989 | GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, | ||
1990 | NULL, NULL); | ||
1991 | if (ctx->d1th == NULL) | ||
1992 | { | ||
1993 | GNUNET_CORE_disconnect (ctx->d1core); | ||
1994 | GNUNET_free (ctx); | ||
1995 | if (NULL != ctx->cb) | ||
1996 | ctx->cb (ctx->cb_cls, &ctx->d1->id, &ctx->d2->id, 0, ctx->d1->cfg, | ||
1997 | ctx->d2->cfg, ctx->d1, ctx->d2, | ||
1998 | _("Failed to connect to transport service!\n")); | ||
1999 | return; | ||
2000 | } | ||
2001 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); | ||
2002 | ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); | ||
2003 | } | ||
2004 | else | ||
2005 | { | ||
2006 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to reconnect %s to %s\n", | ||
2007 | ctx->d1->shortname, ctx->d2->shortname); | ||
2008 | GNUNET_TRANSPORT_try_connect (ctx->d1th, &ctx->d2->id); | ||
2009 | } | ||
2010 | ctx->timeout_task = | ||
2011 | GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, | ||
2012 | ¬ify_connect_result, ctx); | ||
2013 | } | ||
2014 | |||
2015 | /** | ||
2016 | * Iterator for currently known peers, to ensure | ||
2017 | * that we don't try to send duplicate connect | ||
2018 | * requests to core. | ||
2019 | * | ||
2020 | * @param cls our "struct GNUNET_TESTING_ConnectContext" | ||
2021 | * @param peer identity of the peer that has connected, | ||
2022 | * NULL when iteration has finished | ||
2023 | * @param atsi performance information | ||
2024 | * @param atsi_count number of records in 'atsi' | ||
2025 | * | ||
2026 | */ | ||
2027 | static void | ||
2028 | core_initial_iteration (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
2029 | const struct GNUNET_ATS_Information *atsi, | ||
2030 | unsigned int atsi_count) | ||
2031 | { | ||
2032 | struct GNUNET_TESTING_ConnectContext *ctx = cls; | ||
2033 | |||
2034 | if ((peer != NULL) && | ||
2035 | (0 == memcmp (&ctx->d2->id, peer, sizeof (struct GNUNET_PeerIdentity)))) | ||
2036 | { | ||
2037 | ctx->connected = GNUNET_YES; | ||
2038 | ctx->distance = 0; /* FIXME: distance */ | ||
2039 | return; | ||
2040 | } | ||
2041 | if (peer != NULL) | ||
2042 | return; /* ignore other peers */ | ||
2043 | /* peer == NULL: End of iteration over peers */ | ||
2044 | |||
2045 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->timeout_task); | ||
2046 | if (ctx->connected == GNUNET_YES) | ||
2047 | { | ||
2048 | ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); | ||
2049 | return; | ||
2050 | } | ||
2051 | |||
2052 | /* Peer not already connected, need to schedule connect request! */ | ||
2053 | if (ctx->d1core == NULL) | ||
2054 | { | ||
2055 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2056 | "Peers are NOT connected, connecting to core!\n"); | ||
2057 | ctx->d1core = | ||
2058 | GNUNET_CORE_connect (ctx->d1->cfg, ctx, &core_init_notify, | ||
2059 | &connect_notify, NULL, NULL, GNUNET_NO, NULL, | ||
2060 | GNUNET_NO, no_handlers); | ||
2061 | } | ||
2062 | |||
2063 | if (ctx->d1core == NULL) | ||
2064 | { | ||
2065 | ctx->timeout_task = GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); | ||
2066 | return; | ||
2067 | } | ||
2068 | |||
2069 | if ((NULL == ctx->d2->hello) && (ctx->d2->th == NULL)) /* Do not yet have the second peer's hello, set up a task to get it */ | ||
2070 | { | ||
2071 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2072 | "Don't have d2's HELLO, trying to get it!\n"); | ||
2073 | ctx->d2->th = | ||
2074 | GNUNET_TRANSPORT_connect (ctx->d2->cfg, &ctx->d2->id, NULL, NULL, NULL, | ||
2075 | NULL); | ||
2076 | if (ctx->d2->th == NULL) | ||
2077 | { | ||
2078 | GNUNET_CORE_disconnect (ctx->d1core); | ||
2079 | ctx->d1core = NULL; | ||
2080 | ctx->timeout_task = | ||
2081 | GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); | ||
2082 | return; | ||
2083 | } | ||
2084 | ctx->d2->ghh = | ||
2085 | GNUNET_TRANSPORT_get_hello (ctx->d2->th, &process_hello, ctx->d2); | ||
2086 | } | ||
2087 | |||
2088 | if (ctx->send_hello == GNUNET_YES) | ||
2089 | { | ||
2090 | ctx->d1th = | ||
2091 | GNUNET_TRANSPORT_connect (ctx->d1->cfg, &ctx->d1->id, ctx->d1, NULL, | ||
2092 | NULL, NULL); | ||
2093 | if (ctx->d1th == NULL) | ||
2094 | { | ||
2095 | GNUNET_CORE_disconnect (ctx->d1core); | ||
2096 | ctx->d1core = NULL; | ||
2097 | ctx->timeout_task = | ||
2098 | GNUNET_SCHEDULER_add_now (¬ify_connect_result, ctx); | ||
2099 | return; | ||
2100 | } | ||
2101 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == ctx->hello_send_task); | ||
2102 | ctx->hello_send_task = GNUNET_SCHEDULER_add_now (&send_hello, ctx); | ||
2103 | } | ||
2104 | |||
2105 | ctx->timeout_task = | ||
2106 | GNUNET_SCHEDULER_add_delayed (ctx->relative_timeout, | ||
2107 | ¬ify_connect_result, ctx); | ||
2108 | |||
2109 | } | ||
2110 | |||
2111 | |||
2112 | /** | ||
2113 | * Establish a connection between two GNUnet daemons. The daemons | ||
2114 | * must both be running and not be stopped until either the | ||
2115 | * 'cb' callback is called OR the connection request has been | ||
2116 | * explicitly cancelled. | ||
2117 | * | ||
2118 | * @param d1 handle for the first daemon | ||
2119 | * @param d2 handle for the second daemon | ||
2120 | * @param timeout how long is the connection attempt | ||
2121 | * allowed to take? | ||
2122 | * @param max_connect_attempts how many times should we try to reconnect | ||
2123 | * (within timeout) | ||
2124 | * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume | ||
2125 | * the HELLO has already been exchanged | ||
2126 | * @param cb function to call at the end | ||
2127 | * @param cb_cls closure for cb | ||
2128 | * @return handle to cancel the request | ||
2129 | */ | ||
2130 | struct GNUNET_TESTING_ConnectContext * | ||
2131 | GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, | ||
2132 | struct GNUNET_TESTING_Daemon *d2, | ||
2133 | struct GNUNET_TIME_Relative timeout, | ||
2134 | unsigned int max_connect_attempts, | ||
2135 | int send_hello, | ||
2136 | GNUNET_TESTING_NotifyConnection cb, | ||
2137 | void *cb_cls) | ||
2138 | { | ||
2139 | struct GNUNET_TESTING_ConnectContext *ctx; | ||
2140 | |||
2141 | if ((d1->running == GNUNET_NO) || (d2->running == GNUNET_NO)) | ||
2142 | { | ||
2143 | if (NULL != cb) | ||
2144 | cb (cb_cls, &d1->id, &d2->id, 0, d1->cfg, d2->cfg, d1, d2, | ||
2145 | _("Peers are not fully running yet, can not connect!\n")); | ||
2146 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peers are not up!\n"); | ||
2147 | return NULL; | ||
2148 | } | ||
2149 | |||
2150 | ctx = GNUNET_malloc (sizeof (struct GNUNET_TESTING_ConnectContext)); | ||
2151 | ctx->d1 = d1; | ||
2152 | ctx->d2 = d2; | ||
2153 | ctx->timeout_hello = | ||
2154 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500); | ||
2155 | ctx->relative_timeout = | ||
2156 | GNUNET_TIME_relative_divide (timeout, max_connect_attempts); | ||
2157 | ctx->cb = cb; | ||
2158 | ctx->cb_cls = cb_cls; | ||
2159 | ctx->connect_attempts = max_connect_attempts; | ||
2160 | ctx->connected = GNUNET_NO; | ||
2161 | ctx->send_hello = send_hello; | ||
2162 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to connect peer %s to peer %s\n", | ||
2163 | d1->shortname, d2->shortname); | ||
2164 | /* Core is up! Iterate over all _known_ peers first to check if we are already connected to the peer! */ | ||
2165 | GNUNET_assert (NULL != | ||
2166 | GNUNET_CORE_is_peer_connected (ctx->d1->cfg, &ctx->d2->id, | ||
2167 | &core_initial_iteration, ctx)); | ||
2168 | return ctx; | ||
2169 | } | ||
2170 | |||
2171 | |||
2172 | /** | ||
2173 | * Cancel an attempt to connect two daemons. | ||
2174 | * | ||
2175 | * @param cc connect context | ||
2176 | */ | ||
2177 | void | ||
2178 | GNUNET_TESTING_daemons_connect_cancel (struct GNUNET_TESTING_ConnectContext *cc) | ||
2179 | { | ||
2180 | if (GNUNET_SCHEDULER_NO_TASK != cc->timeout_task) | ||
2181 | { | ||
2182 | GNUNET_SCHEDULER_cancel (cc->timeout_task); | ||
2183 | cc->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
2184 | } | ||
2185 | if (GNUNET_SCHEDULER_NO_TASK != cc->hello_send_task) | ||
2186 | { | ||
2187 | GNUNET_SCHEDULER_cancel (cc->hello_send_task); | ||
2188 | cc->hello_send_task = GNUNET_SCHEDULER_NO_TASK; | ||
2189 | } | ||
2190 | if (NULL != cc->d1core) | ||
2191 | { | ||
2192 | GNUNET_CORE_disconnect (cc->d1core); | ||
2193 | cc->d1core = NULL; | ||
2194 | } | ||
2195 | if (NULL != cc->d1th) | ||
2196 | { | ||
2197 | GNUNET_TRANSPORT_disconnect (cc->d1th); | ||
2198 | cc->d1th = NULL; | ||
2199 | } | ||
2200 | GNUNET_free (cc); | ||
2201 | } | ||
2202 | |||
2203 | |||
2204 | /* end of testing.c */ | ||
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c deleted file mode 100644 index 75c0e617d..000000000 --- a/src/testing/testing_group.c +++ /dev/null | |||
@@ -1,7038 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2008, 2009 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file testing/testing_group.c | ||
23 | * @brief convenience API for writing testcases for GNUnet | ||
24 | * @author Nathan Evans | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_arm_service.h" | ||
30 | #include "gnunet_testing_lib.h" | ||
31 | #include "gnunet_core_service.h" | ||
32 | |||
33 | #define USE_START_HELPER GNUNET_YES | ||
34 | |||
35 | #define OLD 1 | ||
36 | |||
37 | /* Before connecting peers, send all of the HELLOs */ | ||
38 | #define USE_SEND_HELLOS GNUNET_NO | ||
39 | |||
40 | #define TOPOLOGY_HACK GNUNET_YES | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Lowest port used for GNUnet testing. Should be high enough to not | ||
45 | * conflict with other applications running on the hosts but be low | ||
46 | * enough to not conflict with client-ports (typically starting around | ||
47 | * 32k). | ||
48 | */ | ||
49 | #define LOW_PORT 12000 | ||
50 | |||
51 | /** | ||
52 | * Highest port used for GNUnet testing. Should be low enough to not | ||
53 | * conflict with the port range for "local" ports (client apps; see | ||
54 | * /proc/sys/net/ipv4/ip_local_port_range on Linux for example). | ||
55 | */ | ||
56 | #define HIGH_PORT 56000 | ||
57 | |||
58 | /* Maximum time to delay connect attempt */ | ||
59 | #define MAX_CONNECT_DELAY 300 | ||
60 | |||
61 | /** | ||
62 | * Which list of peers do we need to modify? | ||
63 | */ | ||
64 | enum PeerLists | ||
65 | { | ||
66 | /** Modify allowed peers */ | ||
67 | ALLOWED, | ||
68 | |||
69 | /** Modify connect peers */ | ||
70 | CONNECT, | ||
71 | |||
72 | /** Modify blacklist peers */ | ||
73 | BLACKLIST, | ||
74 | |||
75 | /** Modify workingset peers */ | ||
76 | WORKING_SET | ||
77 | }; | ||
78 | |||
79 | /** | ||
80 | * Prototype of a function called whenever two peers would be connected | ||
81 | * in a certain topology. | ||
82 | */ | ||
83 | typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct | ||
84 | GNUNET_TESTING_PeerGroup | ||
85 | * pg, | ||
86 | unsigned int first, | ||
87 | unsigned int second, | ||
88 | enum PeerLists list, | ||
89 | unsigned int check); | ||
90 | |||
91 | /** | ||
92 | * Context for handling churning a peer group | ||
93 | */ | ||
94 | struct ChurnContext | ||
95 | { | ||
96 | /** | ||
97 | * The peergroup we are dealing with. | ||
98 | */ | ||
99 | struct GNUNET_TESTING_PeerGroup *pg; | ||
100 | |||
101 | /** | ||
102 | * Name of the service to churn on/off, NULL | ||
103 | * to churn entire peer. | ||
104 | */ | ||
105 | char *service; | ||
106 | |||
107 | /** | ||
108 | * Callback used to notify of churning finished | ||
109 | */ | ||
110 | GNUNET_TESTING_NotifyCompletion cb; | ||
111 | |||
112 | /** | ||
113 | * Closure for callback | ||
114 | */ | ||
115 | void *cb_cls; | ||
116 | |||
117 | /** | ||
118 | * Number of peers that still need to be started | ||
119 | */ | ||
120 | unsigned int num_to_start; | ||
121 | |||
122 | /** | ||
123 | * Number of peers that still need to be stopped | ||
124 | */ | ||
125 | unsigned int num_to_stop; | ||
126 | |||
127 | /** | ||
128 | * Number of peers that failed to start | ||
129 | */ | ||
130 | unsigned int num_failed_start; | ||
131 | |||
132 | /** | ||
133 | * Number of peers that failed to stop | ||
134 | */ | ||
135 | unsigned int num_failed_stop; | ||
136 | }; | ||
137 | |||
138 | struct RestartContext | ||
139 | { | ||
140 | /** | ||
141 | * The group of peers being restarted | ||
142 | */ | ||
143 | struct GNUNET_TESTING_PeerGroup *peer_group; | ||
144 | |||
145 | /** | ||
146 | * How many peers have been restarted thus far | ||
147 | */ | ||
148 | unsigned int peers_restarted; | ||
149 | |||
150 | /** | ||
151 | * How many peers got an error when restarting | ||
152 | */ | ||
153 | unsigned int peers_restart_failed; | ||
154 | |||
155 | /** | ||
156 | * The function to call once all peers have been restarted | ||
157 | */ | ||
158 | GNUNET_TESTING_NotifyCompletion callback; | ||
159 | |||
160 | /** | ||
161 | * Closure for callback function | ||
162 | */ | ||
163 | void *callback_cls; | ||
164 | |||
165 | }; | ||
166 | |||
167 | struct SendHelloContext | ||
168 | { | ||
169 | /** | ||
170 | * Global handle to the peer group. | ||
171 | */ | ||
172 | struct GNUNET_TESTING_PeerGroup *pg; | ||
173 | |||
174 | /** | ||
175 | * The data about this specific peer. | ||
176 | */ | ||
177 | struct PeerData *peer; | ||
178 | |||
179 | /** | ||
180 | * The next HELLO that needs sent to this peer. | ||
181 | */ | ||
182 | struct PeerConnection *peer_pos; | ||
183 | |||
184 | /** | ||
185 | * Are we connected to CORE yet? | ||
186 | */ | ||
187 | unsigned int core_ready; | ||
188 | |||
189 | /** | ||
190 | * How many attempts should we make for failed connections? | ||
191 | */ | ||
192 | unsigned int connect_attempts; | ||
193 | |||
194 | /** | ||
195 | * Task for scheduling core connect requests to be sent. | ||
196 | */ | ||
197 | GNUNET_SCHEDULER_TaskIdentifier core_connect_task; | ||
198 | }; | ||
199 | |||
200 | struct ShutdownContext | ||
201 | { | ||
202 | struct GNUNET_TESTING_PeerGroup *pg; | ||
203 | /** | ||
204 | * Total peers to wait for | ||
205 | */ | ||
206 | unsigned int total_peers; | ||
207 | |||
208 | /** | ||
209 | * Number of peers successfully shut down | ||
210 | */ | ||
211 | unsigned int peers_down; | ||
212 | |||
213 | /** | ||
214 | * Number of peers failed to shut down | ||
215 | */ | ||
216 | unsigned int peers_failed; | ||
217 | |||
218 | /** | ||
219 | * Number of peers we have started shutting | ||
220 | * down. If too many, wait on them. | ||
221 | */ | ||
222 | unsigned int outstanding; | ||
223 | |||
224 | /** | ||
225 | * Timeout for shutdown. | ||
226 | */ | ||
227 | struct GNUNET_TIME_Relative timeout; | ||
228 | |||
229 | /** | ||
230 | * Callback to call when all peers either | ||
231 | * shutdown or failed to shutdown | ||
232 | */ | ||
233 | GNUNET_TESTING_NotifyCompletion cb; | ||
234 | |||
235 | /** | ||
236 | * Closure for cb | ||
237 | */ | ||
238 | void *cb_cls; | ||
239 | |||
240 | /** | ||
241 | * Should we delete all of the files from the peers? | ||
242 | */ | ||
243 | int delete_files; | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * Individual shutdown context for a particular peer. | ||
248 | */ | ||
249 | struct PeerShutdownContext | ||
250 | { | ||
251 | /** | ||
252 | * Pointer to the high level shutdown context. | ||
253 | */ | ||
254 | struct ShutdownContext *shutdown_ctx; | ||
255 | |||
256 | /** | ||
257 | * The daemon handle for the peer to shut down. | ||
258 | */ | ||
259 | struct GNUNET_TESTING_Daemon *daemon; | ||
260 | }; | ||
261 | |||
262 | /** | ||
263 | * Individual shutdown context for a particular peer. | ||
264 | */ | ||
265 | struct PeerRestartContext | ||
266 | { | ||
267 | /** | ||
268 | * Pointer to the high level restart context. | ||
269 | */ | ||
270 | struct ChurnRestartContext *churn_restart_ctx; | ||
271 | |||
272 | /** | ||
273 | * The daemon handle for the peer to shut down. | ||
274 | */ | ||
275 | struct GNUNET_TESTING_Daemon *daemon; | ||
276 | }; | ||
277 | |||
278 | struct ServiceStartContext | ||
279 | { | ||
280 | struct GNUNET_TESTING_PeerGroup *pg; | ||
281 | unsigned int remaining; | ||
282 | GNUNET_TESTING_NotifyCompletion cb; | ||
283 | unsigned int outstanding; | ||
284 | char *service; | ||
285 | struct GNUNET_TIME_Relative timeout; | ||
286 | void *cb_cls; | ||
287 | }; | ||
288 | |||
289 | /** | ||
290 | * Individual shutdown context for a particular peer. | ||
291 | */ | ||
292 | struct PeerServiceStartContext | ||
293 | { | ||
294 | /** | ||
295 | * Pointer to the high level start context. | ||
296 | */ | ||
297 | struct ServiceStartContext *start_ctx; | ||
298 | |||
299 | /** | ||
300 | * The daemon handle for the peer to start the service on. | ||
301 | */ | ||
302 | struct GNUNET_TESTING_Daemon *daemon; | ||
303 | }; | ||
304 | |||
305 | struct CreateTopologyContext | ||
306 | { | ||
307 | |||
308 | /** | ||
309 | * Function to call with number of connections | ||
310 | */ | ||
311 | GNUNET_TESTING_NotifyConnections cont; | ||
312 | |||
313 | /** | ||
314 | * Closure for connection notification | ||
315 | */ | ||
316 | void *cls; | ||
317 | }; | ||
318 | |||
319 | enum States | ||
320 | { | ||
321 | /** Waiting to read number of peers */ | ||
322 | NUM_PEERS, | ||
323 | |||
324 | /** Should find next peer index */ | ||
325 | PEER_INDEX, | ||
326 | |||
327 | /** Should find colon */ | ||
328 | COLON, | ||
329 | |||
330 | /** Should read other peer index, space, or endline */ | ||
331 | OTHER_PEER_INDEX | ||
332 | }; | ||
333 | |||
334 | #if OLD | ||
335 | struct PeerConnection | ||
336 | { | ||
337 | /** | ||
338 | * Doubly Linked list | ||
339 | */ | ||
340 | struct PeerConnection *prev; | ||
341 | |||
342 | /* | ||
343 | * Doubly Linked list | ||
344 | */ | ||
345 | struct PeerConnection *next; | ||
346 | |||
347 | /* | ||
348 | * Index of daemon in pg->peers | ||
349 | */ | ||
350 | uint32_t index; | ||
351 | |||
352 | }; | ||
353 | #endif | ||
354 | |||
355 | struct InternalStartContext | ||
356 | { | ||
357 | /** | ||
358 | * Pointer to peerdata | ||
359 | */ | ||
360 | struct PeerData *peer; | ||
361 | |||
362 | /** | ||
363 | * Timeout for peer startup | ||
364 | */ | ||
365 | struct GNUNET_TIME_Relative timeout; | ||
366 | |||
367 | /** | ||
368 | * Client callback for hostkey notification | ||
369 | */ | ||
370 | GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; | ||
371 | |||
372 | /** | ||
373 | * Closure for hostkey_callback | ||
374 | */ | ||
375 | void *hostkey_cls; | ||
376 | |||
377 | /** | ||
378 | * Client callback for peer start notification | ||
379 | */ | ||
380 | GNUNET_TESTING_NotifyDaemonRunning start_cb; | ||
381 | |||
382 | /** | ||
383 | * Closure for cb | ||
384 | */ | ||
385 | void *start_cb_cls; | ||
386 | |||
387 | /** | ||
388 | * Hostname, where to start the peer | ||
389 | */ | ||
390 | const char *hostname; | ||
391 | |||
392 | /** | ||
393 | * Username to use when connecting to the | ||
394 | * host via ssh. | ||
395 | */ | ||
396 | const char *username; | ||
397 | |||
398 | /** | ||
399 | * Pointer to starting memory location of a hostkey | ||
400 | */ | ||
401 | const char *hostkey; | ||
402 | |||
403 | /** | ||
404 | * Port to use for ssh. | ||
405 | */ | ||
406 | uint16_t sshport; | ||
407 | |||
408 | }; | ||
409 | |||
410 | struct ChurnRestartContext | ||
411 | { | ||
412 | /** | ||
413 | * PeerGroup that we are working with. | ||
414 | */ | ||
415 | struct GNUNET_TESTING_PeerGroup *pg; | ||
416 | |||
417 | /** | ||
418 | * Number of restarts currently in flight. | ||
419 | */ | ||
420 | unsigned int outstanding; | ||
421 | |||
422 | /** | ||
423 | * Handle to the underlying churn context. | ||
424 | */ | ||
425 | struct ChurnContext *churn_ctx; | ||
426 | |||
427 | /** | ||
428 | * How long to allow the operation to take. | ||
429 | */ | ||
430 | struct GNUNET_TIME_Relative timeout; | ||
431 | }; | ||
432 | |||
433 | struct OutstandingSSH | ||
434 | { | ||
435 | struct OutstandingSSH *next; | ||
436 | |||
437 | struct OutstandingSSH *prev; | ||
438 | |||
439 | /** | ||
440 | * Number of current ssh connections. | ||
441 | */ | ||
442 | uint32_t outstanding; | ||
443 | |||
444 | /** | ||
445 | * The hostname of this peer. | ||
446 | */ | ||
447 | const char *hostname; | ||
448 | }; | ||
449 | |||
450 | /** | ||
451 | * Data we keep per peer. | ||
452 | */ | ||
453 | struct PeerData | ||
454 | { | ||
455 | /** | ||
456 | * (Initial) configuration of the host. | ||
457 | * (initial because clients could change | ||
458 | * it and we would not know about those | ||
459 | * updates). | ||
460 | */ | ||
461 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
462 | |||
463 | /** | ||
464 | * Handle for controlling the daemon. | ||
465 | */ | ||
466 | struct GNUNET_TESTING_Daemon *daemon; | ||
467 | |||
468 | /** | ||
469 | * The peergroup this peer belongs to. | ||
470 | */ | ||
471 | struct GNUNET_TESTING_PeerGroup *pg; | ||
472 | |||
473 | #if OLD | ||
474 | /** | ||
475 | * Linked list of allowed peer connections. | ||
476 | */ | ||
477 | struct PeerConnection *allowed_peers_head; | ||
478 | |||
479 | /** | ||
480 | * Linked list of allowed peer connections. | ||
481 | */ | ||
482 | struct PeerConnection *allowed_peers_tail; | ||
483 | |||
484 | /** | ||
485 | * Linked list of blacklisted peer connections. | ||
486 | */ | ||
487 | struct PeerConnection *blacklisted_peers_head; | ||
488 | |||
489 | /** | ||
490 | * Linked list of blacklisted peer connections. | ||
491 | */ | ||
492 | struct PeerConnection *blacklisted_peers_tail; | ||
493 | |||
494 | /** | ||
495 | * Linked list of connect peer connections. | ||
496 | */ | ||
497 | struct PeerConnection *connect_peers_head; | ||
498 | |||
499 | /** | ||
500 | * Linked list of connect peer connections. | ||
501 | */ | ||
502 | struct PeerConnection *connect_peers_tail; | ||
503 | |||
504 | /** | ||
505 | * Linked list of connect peer connections. | ||
506 | */ | ||
507 | struct PeerConnection *connect_peers_working_set_head; | ||
508 | |||
509 | /** | ||
510 | * Linked list of connect peer connections. | ||
511 | */ | ||
512 | struct PeerConnection *connect_peers_working_set_tail; | ||
513 | |||
514 | #else | ||
515 | /** | ||
516 | * Hash map of allowed peer connections (F2F created topology) | ||
517 | */ | ||
518 | struct GNUNET_CONTAINER_MultiHashMap *allowed_peers; | ||
519 | |||
520 | /** | ||
521 | * Hash map of blacklisted peers | ||
522 | */ | ||
523 | struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers; | ||
524 | |||
525 | /** | ||
526 | * Hash map of peer connections | ||
527 | */ | ||
528 | struct GNUNET_CONTAINER_MultiHashMap *connect_peers; | ||
529 | |||
530 | /** | ||
531 | * Temporary hash map of peer connections | ||
532 | */ | ||
533 | struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set; | ||
534 | #endif | ||
535 | |||
536 | /** | ||
537 | * Temporary variable for topology creation, should be reset before | ||
538 | * creating any topology so the count is valid once finished. | ||
539 | */ | ||
540 | int num_connections; | ||
541 | |||
542 | /** | ||
543 | * Context to keep track of peers being started, to | ||
544 | * stagger hostkey generation and peer startup. | ||
545 | */ | ||
546 | struct InternalStartContext internal_context; | ||
547 | |||
548 | /** | ||
549 | * Task ID for the queued internal_continue_startup task | ||
550 | */ | ||
551 | GNUNET_SCHEDULER_TaskIdentifier startup_task; | ||
552 | |||
553 | }; | ||
554 | |||
555 | /** | ||
556 | * Linked list of per-host data. | ||
557 | */ | ||
558 | struct HostData | ||
559 | { | ||
560 | /** | ||
561 | * Name of the host. | ||
562 | */ | ||
563 | char *hostname; | ||
564 | |||
565 | /** | ||
566 | * SSH username to use when connecting to this host. | ||
567 | */ | ||
568 | char *username; | ||
569 | |||
570 | /** | ||
571 | * SSH port to use when connecting to this host. | ||
572 | */ | ||
573 | uint16_t sshport; | ||
574 | |||
575 | /** | ||
576 | * Lowest port that we have not yet used | ||
577 | * for GNUnet. | ||
578 | */ | ||
579 | uint16_t minport; | ||
580 | }; | ||
581 | |||
582 | struct TopologyIterateContext | ||
583 | { | ||
584 | /** | ||
585 | * The peergroup we are working with. | ||
586 | */ | ||
587 | struct GNUNET_TESTING_PeerGroup *pg; | ||
588 | |||
589 | /** | ||
590 | * Callback for notifying of two connected peers. | ||
591 | */ | ||
592 | GNUNET_TESTING_NotifyTopology topology_cb; | ||
593 | |||
594 | /** | ||
595 | * Closure for topology_cb | ||
596 | */ | ||
597 | void *cls; | ||
598 | |||
599 | /** | ||
600 | * Number of peers currently connected to. | ||
601 | */ | ||
602 | unsigned int connected; | ||
603 | |||
604 | /** | ||
605 | * Number of peers we have finished iterating. | ||
606 | */ | ||
607 | unsigned int completed; | ||
608 | |||
609 | /** | ||
610 | * Number of peers total. | ||
611 | */ | ||
612 | unsigned int total; | ||
613 | }; | ||
614 | |||
615 | struct StatsIterateContext | ||
616 | { | ||
617 | /** | ||
618 | * The peergroup that we are dealing with. | ||
619 | */ | ||
620 | struct GNUNET_TESTING_PeerGroup *pg; | ||
621 | |||
622 | /** | ||
623 | * Continuation to call once all stats information has been retrieved. | ||
624 | */ | ||
625 | GNUNET_STATISTICS_Callback cont; | ||
626 | |||
627 | /** | ||
628 | * Proc function to call on each value received. | ||
629 | */ | ||
630 | GNUNET_TESTING_STATISTICS_Iterator proc; | ||
631 | |||
632 | /** | ||
633 | * Closure for topology_cb | ||
634 | */ | ||
635 | void *cls; | ||
636 | |||
637 | /** | ||
638 | * Number of peers currently connected to. | ||
639 | */ | ||
640 | unsigned int connected; | ||
641 | |||
642 | /** | ||
643 | * Number of peers we have finished iterating. | ||
644 | */ | ||
645 | unsigned int completed; | ||
646 | |||
647 | /** | ||
648 | * Number of peers total. | ||
649 | */ | ||
650 | unsigned int total; | ||
651 | }; | ||
652 | |||
653 | struct CoreContext | ||
654 | { | ||
655 | void *iter_context; | ||
656 | struct GNUNET_TESTING_Daemon *daemon; | ||
657 | }; | ||
658 | |||
659 | struct StatsCoreContext | ||
660 | { | ||
661 | void *iter_context; | ||
662 | struct GNUNET_TESTING_Daemon *daemon; | ||
663 | /** | ||
664 | * Handle to the statistics service. | ||
665 | */ | ||
666 | struct GNUNET_STATISTICS_Handle *stats_handle; | ||
667 | |||
668 | /** | ||
669 | * Handle for getting statistics. | ||
670 | */ | ||
671 | struct GNUNET_STATISTICS_GetHandle *stats_get_handle; | ||
672 | }; | ||
673 | |||
674 | struct ConnectTopologyContext | ||
675 | { | ||
676 | /** | ||
677 | * How many connections are left to create. | ||
678 | */ | ||
679 | unsigned int remaining_connections; | ||
680 | |||
681 | /** | ||
682 | * Handle to group of peers. | ||
683 | */ | ||
684 | struct GNUNET_TESTING_PeerGroup *pg; | ||
685 | |||
686 | /** | ||
687 | * How long to try this connection before timing out. | ||
688 | */ | ||
689 | struct GNUNET_TIME_Relative connect_timeout; | ||
690 | |||
691 | /** | ||
692 | * How many times to retry connecting the two peers. | ||
693 | */ | ||
694 | unsigned int connect_attempts; | ||
695 | |||
696 | /** | ||
697 | * Temp value set for each iteration. | ||
698 | */ | ||
699 | //struct PeerData *first; | ||
700 | |||
701 | /** | ||
702 | * Notification that all peers are connected. | ||
703 | */ | ||
704 | GNUNET_TESTING_NotifyCompletion notify_connections_done; | ||
705 | |||
706 | /** | ||
707 | * Closure for notify. | ||
708 | */ | ||
709 | void *notify_cls; | ||
710 | }; | ||
711 | |||
712 | struct ConnectContext; | ||
713 | |||
714 | /** | ||
715 | * Handle to a group of GNUnet peers. | ||
716 | */ | ||
717 | struct GNUNET_TESTING_PeerGroup | ||
718 | { | ||
719 | /** | ||
720 | * Configuration template. | ||
721 | */ | ||
722 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
723 | |||
724 | struct ConnectContext *cc_head; | ||
725 | |||
726 | struct ConnectContext *cc_tail; | ||
727 | |||
728 | /** | ||
729 | * Function to call on each started daemon. | ||
730 | */ | ||
731 | //GNUNET_TESTING_NotifyDaemonRunning cb; | ||
732 | |||
733 | /** | ||
734 | * Closure for cb. | ||
735 | */ | ||
736 | //void *cb_cls; | ||
737 | |||
738 | /* | ||
739 | * Function to call on each topology connection created | ||
740 | */ | ||
741 | GNUNET_TESTING_NotifyConnection notify_connection; | ||
742 | |||
743 | /* | ||
744 | * Callback for notify_connection | ||
745 | */ | ||
746 | void *notify_connection_cls; | ||
747 | |||
748 | /** | ||
749 | * Array of information about hosts. | ||
750 | */ | ||
751 | struct HostData *hosts; | ||
752 | |||
753 | /** | ||
754 | * Number of hosts (size of HostData) | ||
755 | */ | ||
756 | unsigned int num_hosts; | ||
757 | |||
758 | /** | ||
759 | * Array of "total" peers. | ||
760 | */ | ||
761 | struct PeerData *peers; | ||
762 | |||
763 | /** | ||
764 | * Number of peers in this group. | ||
765 | */ | ||
766 | unsigned int total; | ||
767 | |||
768 | /** | ||
769 | * At what time should we fail the peer startup process? | ||
770 | */ | ||
771 | struct GNUNET_TIME_Absolute max_timeout; | ||
772 | |||
773 | /** | ||
774 | * How many peers are being started right now? | ||
775 | */ | ||
776 | unsigned int starting; | ||
777 | |||
778 | /** | ||
779 | * How many peers have already been started? | ||
780 | */ | ||
781 | unsigned int started; | ||
782 | |||
783 | /** | ||
784 | * Number of possible connections to peers | ||
785 | * at a time. | ||
786 | */ | ||
787 | unsigned int max_outstanding_connections; | ||
788 | |||
789 | /** | ||
790 | * Number of ssh connections to peers (max). | ||
791 | */ | ||
792 | unsigned int max_concurrent_ssh; | ||
793 | |||
794 | /** | ||
795 | * Number of connects we are waiting on, allows us to rate limit | ||
796 | * connect attempts. | ||
797 | */ | ||
798 | unsigned int outstanding_connects; | ||
799 | |||
800 | /** | ||
801 | * Number of HELLOs we have yet to send. | ||
802 | */ | ||
803 | unsigned int remaining_hellos; | ||
804 | |||
805 | /** | ||
806 | * How many connects have already been scheduled? | ||
807 | */ | ||
808 | unsigned int total_connects_scheduled; | ||
809 | |||
810 | /** | ||
811 | * Hostkeys loaded from a file. | ||
812 | */ | ||
813 | char *hostkey_data; | ||
814 | |||
815 | /** | ||
816 | * Head of DLL to keep track of the number of outstanding | ||
817 | * ssh connections per peer. | ||
818 | */ | ||
819 | struct OutstandingSSH *ssh_head; | ||
820 | |||
821 | /** | ||
822 | * Tail of DLL to keep track of the number of outstanding | ||
823 | * ssh connections per peer. | ||
824 | */ | ||
825 | struct OutstandingSSH *ssh_tail; | ||
826 | |||
827 | /** | ||
828 | * Stop scheduling peers connecting. | ||
829 | */ | ||
830 | unsigned int stop_connects; | ||
831 | |||
832 | /** | ||
833 | * Connection context for peer group. | ||
834 | */ | ||
835 | struct ConnectTopologyContext ct_ctx; | ||
836 | }; | ||
837 | |||
838 | struct UpdateContext | ||
839 | { | ||
840 | /** | ||
841 | * The altered configuration. | ||
842 | */ | ||
843 | struct GNUNET_CONFIGURATION_Handle *ret; | ||
844 | |||
845 | /** | ||
846 | * The original configuration to alter. | ||
847 | */ | ||
848 | const struct GNUNET_CONFIGURATION_Handle *orig; | ||
849 | |||
850 | /** | ||
851 | * The hostname that this peer will run on. | ||
852 | */ | ||
853 | const char *hostname; | ||
854 | |||
855 | /** | ||
856 | * The next possible port to assign. | ||
857 | */ | ||
858 | unsigned int nport; | ||
859 | |||
860 | /** | ||
861 | * Unique number for unix domain sockets. | ||
862 | */ | ||
863 | unsigned int upnum; | ||
864 | |||
865 | /** | ||
866 | * Unique number for this peer/host to offset | ||
867 | * things that are grouped by host. | ||
868 | */ | ||
869 | unsigned int fdnum; | ||
870 | }; | ||
871 | |||
872 | struct ConnectContext | ||
873 | { | ||
874 | |||
875 | struct ConnectContext *next; | ||
876 | |||
877 | struct ConnectContext *prev; | ||
878 | |||
879 | /** | ||
880 | * Index of peer to connect second to. | ||
881 | */ | ||
882 | uint32_t first_index; | ||
883 | |||
884 | /** | ||
885 | * Index of peer to connect first to. | ||
886 | */ | ||
887 | uint32_t second_index; | ||
888 | |||
889 | /** | ||
890 | * Task associated with the attempt to connect. | ||
891 | */ | ||
892 | GNUNET_SCHEDULER_TaskIdentifier task; | ||
893 | |||
894 | /** | ||
895 | * Context in 'testing.c', to cancel connection attempt. | ||
896 | */ | ||
897 | struct GNUNET_TESTING_ConnectContext *cc; | ||
898 | |||
899 | /** | ||
900 | * Higher level topology connection context. | ||
901 | */ | ||
902 | struct ConnectTopologyContext *ct_ctx; | ||
903 | |||
904 | /** | ||
905 | * Whether this connection has been accounted for in the schedule_connect call. | ||
906 | */ | ||
907 | int counted; | ||
908 | }; | ||
909 | |||
910 | struct UnblacklistContext | ||
911 | { | ||
912 | /** | ||
913 | * The peergroup | ||
914 | */ | ||
915 | struct GNUNET_TESTING_PeerGroup *pg; | ||
916 | |||
917 | /** | ||
918 | * uid of the first peer | ||
919 | */ | ||
920 | uint32_t first_uid; | ||
921 | }; | ||
922 | |||
923 | struct RandomContext | ||
924 | { | ||
925 | /** | ||
926 | * The peergroup | ||
927 | */ | ||
928 | struct GNUNET_TESTING_PeerGroup *pg; | ||
929 | |||
930 | /** | ||
931 | * uid of the first peer | ||
932 | */ | ||
933 | uint32_t first_uid; | ||
934 | |||
935 | /** | ||
936 | * Peer data for first peer. | ||
937 | */ | ||
938 | struct PeerData *first; | ||
939 | |||
940 | /** | ||
941 | * Random percentage to use | ||
942 | */ | ||
943 | double percentage; | ||
944 | }; | ||
945 | |||
946 | struct MinimumContext | ||
947 | { | ||
948 | /** | ||
949 | * The peergroup | ||
950 | */ | ||
951 | struct GNUNET_TESTING_PeerGroup *pg; | ||
952 | |||
953 | /** | ||
954 | * uid of the first peer | ||
955 | */ | ||
956 | uint32_t first_uid; | ||
957 | |||
958 | /** | ||
959 | * Peer data for first peer. | ||
960 | */ | ||
961 | struct PeerData *first; | ||
962 | |||
963 | /** | ||
964 | * Number of conns per peer | ||
965 | */ | ||
966 | unsigned int num_to_add; | ||
967 | |||
968 | /** | ||
969 | * Permuted array of all possible connections. Only add the Nth | ||
970 | * peer if it's in the Nth position. | ||
971 | */ | ||
972 | unsigned int *pg_array; | ||
973 | |||
974 | /** | ||
975 | * What number is the current element we are iterating over? | ||
976 | */ | ||
977 | unsigned int current; | ||
978 | }; | ||
979 | |||
980 | struct DFSContext | ||
981 | { | ||
982 | /** | ||
983 | * The peergroup | ||
984 | */ | ||
985 | struct GNUNET_TESTING_PeerGroup *pg; | ||
986 | |||
987 | /** | ||
988 | * uid of the first peer | ||
989 | */ | ||
990 | uint32_t first_uid; | ||
991 | |||
992 | /** | ||
993 | * uid of the second peer | ||
994 | */ | ||
995 | uint32_t second_uid; | ||
996 | |||
997 | /** | ||
998 | * Peer data for first peer. | ||
999 | */ | ||
1000 | struct PeerData *first; | ||
1001 | |||
1002 | /** | ||
1003 | * Which peer has been chosen as the one to add? | ||
1004 | */ | ||
1005 | unsigned int chosen; | ||
1006 | |||
1007 | /** | ||
1008 | * What number is the current element we are iterating over? | ||
1009 | */ | ||
1010 | unsigned int current; | ||
1011 | }; | ||
1012 | |||
1013 | /** | ||
1014 | * Simple struct to keep track of progress, and print a | ||
1015 | * nice little percentage meter for long running tasks. | ||
1016 | */ | ||
1017 | struct ProgressMeter | ||
1018 | { | ||
1019 | unsigned int total; | ||
1020 | |||
1021 | unsigned int modnum; | ||
1022 | |||
1023 | unsigned int dotnum; | ||
1024 | |||
1025 | unsigned int completed; | ||
1026 | |||
1027 | int print; | ||
1028 | |||
1029 | char *startup_string; | ||
1030 | }; | ||
1031 | |||
1032 | #if !OLD | ||
1033 | /** | ||
1034 | * Convert unique ID to hash code. | ||
1035 | * | ||
1036 | * @param uid unique ID to convert | ||
1037 | * @param hash set to uid (extended with zeros) | ||
1038 | */ | ||
1039 | static void | ||
1040 | hash_from_uid (uint32_t uid, GNUNET_HashCode * hash) | ||
1041 | { | ||
1042 | memset (hash, 0, sizeof (GNUNET_HashCode)); | ||
1043 | *((uint32_t *) hash) = uid; | ||
1044 | } | ||
1045 | |||
1046 | /** | ||
1047 | * Convert hash code to unique ID. | ||
1048 | * | ||
1049 | * @param uid unique ID to convert | ||
1050 | * @param hash set to uid (extended with zeros) | ||
1051 | */ | ||
1052 | static void | ||
1053 | uid_from_hash (const GNUNET_HashCode * hash, uint32_t * uid) | ||
1054 | { | ||
1055 | memcpy (uid, hash, sizeof (uint32_t)); | ||
1056 | } | ||
1057 | #endif | ||
1058 | |||
1059 | #if USE_SEND_HELLOS | ||
1060 | static struct GNUNET_CORE_MessageHandler no_handlers[] = { | ||
1061 | {NULL, 0, 0} | ||
1062 | }; | ||
1063 | #endif | ||
1064 | |||
1065 | /** | ||
1066 | * Create a meter to keep track of the progress of some task. | ||
1067 | * | ||
1068 | * @param total the total number of items to complete | ||
1069 | * @param start_string a string to prefix the meter with (if printing) | ||
1070 | * @param print GNUNET_YES to print the meter, GNUNET_NO to count | ||
1071 | * internally only | ||
1072 | * | ||
1073 | * @return the progress meter | ||
1074 | */ | ||
1075 | static struct ProgressMeter * | ||
1076 | create_meter (unsigned int total, char *start_string, int print) | ||
1077 | { | ||
1078 | struct ProgressMeter *ret; | ||
1079 | |||
1080 | ret = GNUNET_malloc (sizeof (struct ProgressMeter)); | ||
1081 | ret->print = print; | ||
1082 | ret->total = total; | ||
1083 | ret->modnum = total / 4; | ||
1084 | if (ret->modnum == 0) /* Divide by zero check */ | ||
1085 | ret->modnum = 1; | ||
1086 | ret->dotnum = (total / 50) + 1; | ||
1087 | if (start_string != NULL) | ||
1088 | ret->startup_string = GNUNET_strdup (start_string); | ||
1089 | else | ||
1090 | ret->startup_string = GNUNET_strdup (""); | ||
1091 | |||
1092 | return ret; | ||
1093 | } | ||
1094 | |||
1095 | /** | ||
1096 | * Update progress meter (increment by one). | ||
1097 | * | ||
1098 | * @param meter the meter to update and print info for | ||
1099 | * | ||
1100 | * @return GNUNET_YES if called the total requested, | ||
1101 | * GNUNET_NO if more items expected | ||
1102 | */ | ||
1103 | static int | ||
1104 | update_meter (struct ProgressMeter *meter) | ||
1105 | { | ||
1106 | if (meter->print == GNUNET_YES) | ||
1107 | { | ||
1108 | if (meter->completed % meter->modnum == 0) | ||
1109 | { | ||
1110 | if (meter->completed == 0) | ||
1111 | { | ||
1112 | FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); | ||
1113 | } | ||
1114 | else | ||
1115 | FPRINTF (stdout, "%d%%", | ||
1116 | (int) (((float) meter->completed / meter->total) * 100)); | ||
1117 | } | ||
1118 | else if (meter->completed % meter->dotnum == 0) | ||
1119 | FPRINTF (stdout, "%s", "."); | ||
1120 | |||
1121 | if (meter->completed + 1 == meter->total) | ||
1122 | FPRINTF (stdout, "%d%%]\n", 100); | ||
1123 | fflush (stdout); | ||
1124 | } | ||
1125 | meter->completed++; | ||
1126 | |||
1127 | if (meter->completed == meter->total) | ||
1128 | return GNUNET_YES; | ||
1129 | if (meter->completed > meter->total) | ||
1130 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Progress meter overflow!!\n"); | ||
1131 | return GNUNET_NO; | ||
1132 | } | ||
1133 | |||
1134 | /** | ||
1135 | * Reset progress meter. | ||
1136 | * | ||
1137 | * @param meter the meter to reset | ||
1138 | * | ||
1139 | * @return GNUNET_YES if meter reset, | ||
1140 | * GNUNET_SYSERR on error | ||
1141 | */ | ||
1142 | static int | ||
1143 | reset_meter (struct ProgressMeter *meter) | ||
1144 | { | ||
1145 | if (meter == NULL) | ||
1146 | return GNUNET_SYSERR; | ||
1147 | |||
1148 | meter->completed = 0; | ||
1149 | return GNUNET_YES; | ||
1150 | } | ||
1151 | |||
1152 | /** | ||
1153 | * Release resources for meter | ||
1154 | * | ||
1155 | * @param meter the meter to free | ||
1156 | */ | ||
1157 | static void | ||
1158 | free_meter (struct ProgressMeter *meter) | ||
1159 | { | ||
1160 | GNUNET_free_non_null (meter->startup_string); | ||
1161 | GNUNET_free (meter); | ||
1162 | } | ||
1163 | |||
1164 | /** | ||
1165 | * Get a topology from a string input. | ||
1166 | * | ||
1167 | * @param topology where to write the retrieved topology | ||
1168 | * @param topology_string The string to attempt to | ||
1169 | * get a configuration value from | ||
1170 | * @return GNUNET_YES if topology string matched a | ||
1171 | * known topology, GNUNET_NO if not | ||
1172 | */ | ||
1173 | int | ||
1174 | GNUNET_TESTING_topology_get (enum GNUNET_TESTING_Topology *topology, | ||
1175 | const char *topology_string) | ||
1176 | { | ||
1177 | /** | ||
1178 | * Strings representing topologies in enum | ||
1179 | */ | ||
1180 | static const char *topology_strings[] = { | ||
1181 | /** | ||
1182 | * A clique (everyone connected to everyone else). | ||
1183 | */ | ||
1184 | "CLIQUE", | ||
1185 | |||
1186 | /** | ||
1187 | * Small-world network (2d torus plus random links). | ||
1188 | */ | ||
1189 | "SMALL_WORLD", | ||
1190 | |||
1191 | /** | ||
1192 | * Small-world network (ring plus random links). | ||
1193 | */ | ||
1194 | "SMALL_WORLD_RING", | ||
1195 | |||
1196 | /** | ||
1197 | * Ring topology. | ||
1198 | */ | ||
1199 | "RING", | ||
1200 | |||
1201 | /** | ||
1202 | * 2-d torus. | ||
1203 | */ | ||
1204 | "2D_TORUS", | ||
1205 | |||
1206 | /** | ||
1207 | * Random graph. | ||
1208 | */ | ||
1209 | "ERDOS_RENYI", | ||
1210 | |||
1211 | /** | ||
1212 | * Certain percentage of peers are unable to communicate directly | ||
1213 | * replicating NAT conditions | ||
1214 | */ | ||
1215 | "INTERNAT", | ||
1216 | |||
1217 | /** | ||
1218 | * Scale free topology. | ||
1219 | */ | ||
1220 | "SCALE_FREE", | ||
1221 | |||
1222 | /** | ||
1223 | * Straight line topology. | ||
1224 | */ | ||
1225 | "LINE", | ||
1226 | |||
1227 | /** | ||
1228 | * All peers are disconnected. | ||
1229 | */ | ||
1230 | "NONE", | ||
1231 | |||
1232 | /** | ||
1233 | * Read the topology from a file. | ||
1234 | */ | ||
1235 | "FROM_FILE", | ||
1236 | |||
1237 | NULL | ||
1238 | }; | ||
1239 | |||
1240 | int curr = 0; | ||
1241 | |||
1242 | if (topology_string == NULL) | ||
1243 | return GNUNET_NO; | ||
1244 | while (topology_strings[curr] != NULL) | ||
1245 | { | ||
1246 | if (strcasecmp (topology_strings[curr], topology_string) == 0) | ||
1247 | { | ||
1248 | *topology = curr; | ||
1249 | return GNUNET_YES; | ||
1250 | } | ||
1251 | curr++; | ||
1252 | } | ||
1253 | *topology = GNUNET_TESTING_TOPOLOGY_NONE; | ||
1254 | return GNUNET_NO; | ||
1255 | } | ||
1256 | |||
1257 | /** | ||
1258 | * Get connect topology option from string input. | ||
1259 | * | ||
1260 | * @param topology_option where to write the retrieved topology | ||
1261 | * @param topology_string The string to attempt to | ||
1262 | * get a configuration value from | ||
1263 | * @return GNUNET_YES if string matched a known | ||
1264 | * topology option, GNUNET_NO if not | ||
1265 | */ | ||
1266 | int | ||
1267 | GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption | ||
1268 | *topology_option, | ||
1269 | const char *topology_string) | ||
1270 | { | ||
1271 | /** | ||
1272 | * Options for connecting a topology as strings. | ||
1273 | */ | ||
1274 | static const char *topology_option_strings[] = { | ||
1275 | /** | ||
1276 | * Try to connect all peers specified in the topology. | ||
1277 | */ | ||
1278 | "CONNECT_ALL", | ||
1279 | |||
1280 | /** | ||
1281 | * Choose a random subset of connections to create. | ||
1282 | */ | ||
1283 | "CONNECT_RANDOM_SUBSET", | ||
1284 | |||
1285 | /** | ||
1286 | * Create at least X connections for each peer. | ||
1287 | */ | ||
1288 | "CONNECT_MINIMUM", | ||
1289 | |||
1290 | /** | ||
1291 | * Using a depth first search, create one connection | ||
1292 | * per peer. If any are missed (graph disconnected) | ||
1293 | * start over at those peers until all have at least one | ||
1294 | * connection. | ||
1295 | */ | ||
1296 | "CONNECT_DFS", | ||
1297 | |||
1298 | /** | ||
1299 | * Find the N closest peers to each allowed peer in the | ||
1300 | * topology and make sure a connection to those peers | ||
1301 | * exists in the connect topology. | ||
1302 | */ | ||
1303 | "CONNECT_CLOSEST", | ||
1304 | |||
1305 | /** | ||
1306 | * No options specified. | ||
1307 | */ | ||
1308 | "CONNECT_NONE", | ||
1309 | |||
1310 | NULL | ||
1311 | }; | ||
1312 | int curr = 0; | ||
1313 | |||
1314 | if (topology_string == NULL) | ||
1315 | return GNUNET_NO; | ||
1316 | while (NULL != topology_option_strings[curr]) | ||
1317 | { | ||
1318 | if (strcasecmp (topology_option_strings[curr], topology_string) == 0) | ||
1319 | { | ||
1320 | *topology_option = curr; | ||
1321 | return GNUNET_YES; | ||
1322 | } | ||
1323 | curr++; | ||
1324 | } | ||
1325 | *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE; | ||
1326 | return GNUNET_NO; | ||
1327 | } | ||
1328 | |||
1329 | /** | ||
1330 | * Function to iterate over options. Copies | ||
1331 | * the options to the target configuration, | ||
1332 | * updating PORT values as needed. | ||
1333 | * | ||
1334 | * @param cls closure | ||
1335 | * @param section name of the section | ||
1336 | * @param option name of the option | ||
1337 | * @param value value of the option | ||
1338 | */ | ||
1339 | static void | ||
1340 | update_config (void *cls, const char *section, const char *option, | ||
1341 | const char *value) | ||
1342 | { | ||
1343 | struct UpdateContext *ctx = cls; | ||
1344 | unsigned int ival; | ||
1345 | char cval[12]; | ||
1346 | char uval[128]; | ||
1347 | char *single_variable; | ||
1348 | char *per_host_variable; | ||
1349 | unsigned long long num_per_host; | ||
1350 | |||
1351 | GNUNET_asprintf (&single_variable, "single_%s_per_host", section); | ||
1352 | GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section); | ||
1353 | |||
1354 | if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival))) | ||
1355 | { | ||
1356 | if ((ival != 0) && | ||
1357 | (GNUNET_YES != | ||
1358 | GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", | ||
1359 | single_variable))) | ||
1360 | { | ||
1361 | GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++); | ||
1362 | value = cval; | ||
1363 | } | ||
1364 | else if ((ival != 0) && | ||
1365 | (GNUNET_YES == | ||
1366 | GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", | ||
1367 | single_variable)) && | ||
1368 | GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", | ||
1369 | per_host_variable, | ||
1370 | &num_per_host)) | ||
1371 | { | ||
1372 | GNUNET_snprintf (cval, sizeof (cval), "%u", | ||
1373 | ival + ctx->fdnum % num_per_host); | ||
1374 | value = cval; | ||
1375 | } | ||
1376 | |||
1377 | /* FIXME: REMOVE FOREVER HACK HACK HACK */ | ||
1378 | if (0 == strcasecmp (section, "transport-tcp")) | ||
1379 | GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, | ||
1380 | "ADVERTISED_PORT", value); | ||
1381 | } | ||
1382 | |||
1383 | if (0 == strcmp (option, "UNIXPATH")) | ||
1384 | { | ||
1385 | if (GNUNET_YES != | ||
1386 | GNUNET_CONFIGURATION_get_value_yesno (ctx->orig, "testing", | ||
1387 | single_variable)) | ||
1388 | { | ||
1389 | GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, | ||
1390 | ctx->upnum++); | ||
1391 | value = uval; | ||
1392 | } | ||
1393 | else if ((GNUNET_YES == | ||
1394 | GNUNET_CONFIGURATION_get_value_number (ctx->orig, "testing", | ||
1395 | per_host_variable, | ||
1396 | &num_per_host)) && | ||
1397 | (num_per_host > 0)) | ||
1398 | |||
1399 | { | ||
1400 | GNUNET_snprintf (uval, sizeof (uval), "/tmp/test-service-%s-%u", section, | ||
1401 | ctx->fdnum % num_per_host); | ||
1402 | value = uval; | ||
1403 | } | ||
1404 | } | ||
1405 | |||
1406 | if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL)) | ||
1407 | { | ||
1408 | value = ctx->hostname; | ||
1409 | } | ||
1410 | GNUNET_free (single_variable); | ||
1411 | GNUNET_free (per_host_variable); | ||
1412 | GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value); | ||
1413 | } | ||
1414 | |||
1415 | /** | ||
1416 | * Create a new configuration using the given configuration | ||
1417 | * as a template; however, each PORT in the existing cfg | ||
1418 | * must be renumbered by incrementing "*port". If we run | ||
1419 | * out of "*port" numbers, return NULL. | ||
1420 | * | ||
1421 | * @param cfg template configuration | ||
1422 | * @param off the current peer offset | ||
1423 | * @param port port numbers to use, update to reflect | ||
1424 | * port numbers that were used | ||
1425 | * @param upnum number to make unix domain socket names unique | ||
1426 | * @param hostname hostname of the controlling host, to allow control connections from | ||
1427 | * @param fdnum number used to offset the unix domain socket for grouped processes | ||
1428 | * (such as statistics or peerinfo, which can be shared among others) | ||
1429 | * | ||
1430 | * @return new configuration, NULL on error | ||
1431 | */ | ||
1432 | struct GNUNET_CONFIGURATION_Handle * | ||
1433 | GNUNET_TESTING_create_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, uint32_t off, | ||
1434 | uint16_t * port, uint32_t * upnum, const char *hostname, | ||
1435 | uint32_t * fdnum) | ||
1436 | { | ||
1437 | struct UpdateContext uc; | ||
1438 | uint16_t orig; | ||
1439 | char *control_host; | ||
1440 | char *allowed_hosts; | ||
1441 | unsigned long long skew_variance; | ||
1442 | unsigned long long skew_offset; | ||
1443 | long long actual_offset; | ||
1444 | |||
1445 | orig = *port; | ||
1446 | uc.nport = *port; | ||
1447 | uc.upnum = *upnum; | ||
1448 | uc.fdnum = *fdnum; | ||
1449 | uc.ret = GNUNET_CONFIGURATION_create (); | ||
1450 | uc.hostname = hostname; | ||
1451 | uc.orig = cfg; | ||
1452 | |||
1453 | GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc); | ||
1454 | if (uc.nport >= HIGH_PORT) | ||
1455 | { | ||
1456 | *port = orig; | ||
1457 | GNUNET_CONFIGURATION_destroy (uc.ret); | ||
1458 | return NULL; | ||
1459 | } | ||
1460 | |||
1461 | if ((GNUNET_OK == | ||
1462 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "skew_variance", | ||
1463 | &skew_variance)) && | ||
1464 | (skew_variance > 0)) | ||
1465 | { | ||
1466 | skew_offset = | ||
1467 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1468 | skew_variance + 1); | ||
1469 | actual_offset = | ||
1470 | skew_offset - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1471 | skew_variance + 1); | ||
1472 | /* Min is -skew_variance, Max is skew_variance */ | ||
1473 | skew_offset = skew_variance + actual_offset; /* Normal distribution around 0 */ | ||
1474 | GNUNET_CONFIGURATION_set_value_number (uc.ret, "testing", "skew_offset", | ||
1475 | skew_offset); | ||
1476 | } | ||
1477 | |||
1478 | if (GNUNET_CONFIGURATION_get_value_string | ||
1479 | (cfg, "testing", "control_host", &control_host) == GNUNET_OK) | ||
1480 | { | ||
1481 | if (hostname != NULL) | ||
1482 | GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1; %s;", control_host, | ||
1483 | hostname); | ||
1484 | else | ||
1485 | GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", control_host); | ||
1486 | |||
1487 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "ACCEPT_FROM", | ||
1488 | allowed_hosts); | ||
1489 | |||
1490 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "ACCEPT_FROM", | ||
1491 | allowed_hosts); | ||
1492 | |||
1493 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "ACCEPT_FROM", | ||
1494 | allowed_hosts); | ||
1495 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "ACCEPT_FROM", | ||
1496 | allowed_hosts); | ||
1497 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "ACCEPT_FROM", | ||
1498 | allowed_hosts); | ||
1499 | |||
1500 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "core", "UNIXPATH", ""); | ||
1501 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport", "UNIXPATH", ""); | ||
1502 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "dht", "UNIXPATH", ""); | ||
1503 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "statistics", "UNIXPATH", | ||
1504 | ""); | ||
1505 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nse", "UNIXPATH", ""); | ||
1506 | |||
1507 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", | ||
1508 | "USE_LOCALADDR", "YES"); | ||
1509 | GNUNET_free_non_null (control_host); | ||
1510 | GNUNET_free (allowed_hosts); | ||
1511 | } | ||
1512 | |||
1513 | /* arm needs to know to allow connections from the host on which it is running, | ||
1514 | * otherwise gnunet-arm is unable to connect to it in some instances */ | ||
1515 | if (hostname != NULL) | ||
1516 | { | ||
1517 | GNUNET_asprintf (&allowed_hosts, "%s; 127.0.0.1;", hostname); | ||
1518 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", hostname); | ||
1519 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", | ||
1520 | hostname); | ||
1521 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", | ||
1522 | hostname); | ||
1523 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "disablev6", "BINDTO", | ||
1524 | "YES"); | ||
1525 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-tcp", | ||
1526 | "USE_LOCALADDR", "YES"); | ||
1527 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "transport-udp", | ||
1528 | "USE_LOCALADDR", "YES"); | ||
1529 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "arm", "ACCEPT_FROM", | ||
1530 | allowed_hosts); | ||
1531 | GNUNET_free (allowed_hosts); | ||
1532 | } | ||
1533 | else | ||
1534 | { | ||
1535 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", | ||
1536 | "USE_LOCALADDR", "YES"); | ||
1537 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "BINDTO", | ||
1538 | "127.0.0.1"); | ||
1539 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "INTERNAL_ADDRESS", | ||
1540 | "127.0.0.1"); | ||
1541 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "EXTERNAL_ADDRESS", | ||
1542 | "127.0.0.1"); | ||
1543 | GNUNET_CONFIGURATION_set_value_string (uc.ret, "nat", "disablev6", | ||
1544 | "YES"); | ||
1545 | } | ||
1546 | |||
1547 | *port = (uint16_t) uc.nport; | ||
1548 | *upnum = uc.upnum; | ||
1549 | uc.fdnum++; | ||
1550 | *fdnum = uc.fdnum; | ||
1551 | return uc.ret; | ||
1552 | } | ||
1553 | |||
1554 | /* | ||
1555 | * Remove entries from the peer connection list | ||
1556 | * | ||
1557 | * @param pg the peer group we are working with | ||
1558 | * @param first index of the first peer | ||
1559 | * @param second index of the second peer | ||
1560 | * @param list the peer list to use | ||
1561 | * @param check UNUSED | ||
1562 | * | ||
1563 | * @return the number of connections added (can be 0, 1 or 2) | ||
1564 | * | ||
1565 | */ | ||
1566 | static unsigned int | ||
1567 | remove_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, | ||
1568 | unsigned int second, enum PeerLists list, | ||
1569 | unsigned int check) | ||
1570 | { | ||
1571 | int removed; | ||
1572 | |||
1573 | #if OLD | ||
1574 | struct PeerConnection **first_list; | ||
1575 | struct PeerConnection **second_list; | ||
1576 | struct PeerConnection *first_iter; | ||
1577 | struct PeerConnection *second_iter; | ||
1578 | struct PeerConnection **first_tail; | ||
1579 | struct PeerConnection **second_tail; | ||
1580 | |||
1581 | #else | ||
1582 | GNUNET_HashCode hash_first; | ||
1583 | GNUNET_HashCode hash_second; | ||
1584 | |||
1585 | hash_from_uid (first, &hash_first); | ||
1586 | hash_from_uid (second, &hash_second); | ||
1587 | #endif | ||
1588 | |||
1589 | removed = 0; | ||
1590 | #if OLD | ||
1591 | switch (list) | ||
1592 | { | ||
1593 | case ALLOWED: | ||
1594 | first_list = &pg->peers[first].allowed_peers_head; | ||
1595 | second_list = &pg->peers[second].allowed_peers_head; | ||
1596 | first_tail = &pg->peers[first].allowed_peers_tail; | ||
1597 | second_tail = &pg->peers[second].allowed_peers_tail; | ||
1598 | break; | ||
1599 | case CONNECT: | ||
1600 | first_list = &pg->peers[first].connect_peers_head; | ||
1601 | second_list = &pg->peers[second].connect_peers_head; | ||
1602 | first_tail = &pg->peers[first].connect_peers_tail; | ||
1603 | second_tail = &pg->peers[second].connect_peers_tail; | ||
1604 | break; | ||
1605 | case BLACKLIST: | ||
1606 | first_list = &pg->peers[first].blacklisted_peers_head; | ||
1607 | second_list = &pg->peers[second].blacklisted_peers_head; | ||
1608 | first_tail = &pg->peers[first].blacklisted_peers_tail; | ||
1609 | second_tail = &pg->peers[second].blacklisted_peers_tail; | ||
1610 | break; | ||
1611 | case WORKING_SET: | ||
1612 | first_list = &pg->peers[first].connect_peers_working_set_head; | ||
1613 | second_list = &pg->peers[second].connect_peers_working_set_head; | ||
1614 | first_tail = &pg->peers[first].connect_peers_working_set_tail; | ||
1615 | second_tail = &pg->peers[second].connect_peers_working_set_tail; | ||
1616 | break; | ||
1617 | default: | ||
1618 | GNUNET_break (0); | ||
1619 | return 0; | ||
1620 | } | ||
1621 | |||
1622 | first_iter = *first_list; | ||
1623 | while (first_iter != NULL) | ||
1624 | { | ||
1625 | if (first_iter->index == second) | ||
1626 | { | ||
1627 | GNUNET_CONTAINER_DLL_remove (*first_list, *first_tail, first_iter); | ||
1628 | GNUNET_free (first_iter); | ||
1629 | removed++; | ||
1630 | break; | ||
1631 | } | ||
1632 | first_iter = first_iter->next; | ||
1633 | } | ||
1634 | |||
1635 | second_iter = *second_list; | ||
1636 | while (second_iter != NULL) | ||
1637 | { | ||
1638 | if (second_iter->index == first) | ||
1639 | { | ||
1640 | GNUNET_CONTAINER_DLL_remove (*second_list, *second_tail, second_iter); | ||
1641 | GNUNET_free (second_iter); | ||
1642 | removed++; | ||
1643 | break; | ||
1644 | } | ||
1645 | second_iter = second_iter->next; | ||
1646 | } | ||
1647 | #else | ||
1648 | if (GNUNET_YES == | ||
1649 | GNUNET_CONTAINER_multihashmap_contains (pg-> | ||
1650 | peers[first].blacklisted_peers, | ||
1651 | &hash_second)) | ||
1652 | { | ||
1653 | GNUNET_CONTAINER_multihashmap_remove_all (pg-> | ||
1654 | peers[first].blacklisted_peers, | ||
1655 | &hash_second); | ||
1656 | } | ||
1657 | |||
1658 | if (GNUNET_YES == | ||
1659 | GNUNET_CONTAINER_multihashmap_contains (pg-> | ||
1660 | peers[second].blacklisted_peers, | ||
1661 | &hash_first)) | ||
1662 | { | ||
1663 | GNUNET_CONTAINER_multihashmap_remove_all (pg-> | ||
1664 | peers[second].blacklisted_peers, | ||
1665 | &hash_first); | ||
1666 | } | ||
1667 | #endif | ||
1668 | |||
1669 | return removed; | ||
1670 | } | ||
1671 | |||
1672 | /** | ||
1673 | * Add entries to the some list | ||
1674 | * | ||
1675 | * @param pg the peer group we are working with | ||
1676 | * @param first index of the first peer | ||
1677 | * @param second index of the second peer | ||
1678 | * @param list the list type that we should modify | ||
1679 | * @param check GNUNET_YES to check lists before adding | ||
1680 | * GNUNET_NO to force add | ||
1681 | * | ||
1682 | * @return the number of connections added (can be 0, 1 or 2) | ||
1683 | * | ||
1684 | */ | ||
1685 | static unsigned int | ||
1686 | add_connections (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, | ||
1687 | unsigned int second, enum PeerLists list, unsigned int check) | ||
1688 | { | ||
1689 | int added; | ||
1690 | int add_first; | ||
1691 | int add_second; | ||
1692 | |||
1693 | struct PeerConnection **first_list; | ||
1694 | struct PeerConnection **second_list; | ||
1695 | struct PeerConnection *first_iter; | ||
1696 | struct PeerConnection *second_iter; | ||
1697 | struct PeerConnection *new_first; | ||
1698 | struct PeerConnection *new_second; | ||
1699 | struct PeerConnection **first_tail; | ||
1700 | struct PeerConnection **second_tail; | ||
1701 | |||
1702 | switch (list) | ||
1703 | { | ||
1704 | case ALLOWED: | ||
1705 | first_list = &pg->peers[first].allowed_peers_head; | ||
1706 | second_list = &pg->peers[second].allowed_peers_head; | ||
1707 | first_tail = &pg->peers[first].allowed_peers_tail; | ||
1708 | second_tail = &pg->peers[second].allowed_peers_tail; | ||
1709 | break; | ||
1710 | case CONNECT: | ||
1711 | first_list = &pg->peers[first].connect_peers_head; | ||
1712 | second_list = &pg->peers[second].connect_peers_head; | ||
1713 | first_tail = &pg->peers[first].connect_peers_tail; | ||
1714 | second_tail = &pg->peers[second].connect_peers_tail; | ||
1715 | break; | ||
1716 | case BLACKLIST: | ||
1717 | first_list = &pg->peers[first].blacklisted_peers_head; | ||
1718 | second_list = &pg->peers[second].blacklisted_peers_head; | ||
1719 | first_tail = &pg->peers[first].blacklisted_peers_tail; | ||
1720 | second_tail = &pg->peers[second].blacklisted_peers_tail; | ||
1721 | break; | ||
1722 | case WORKING_SET: | ||
1723 | first_list = &pg->peers[first].connect_peers_working_set_head; | ||
1724 | second_list = &pg->peers[second].connect_peers_working_set_head; | ||
1725 | first_tail = &pg->peers[first].connect_peers_working_set_tail; | ||
1726 | second_tail = &pg->peers[second].connect_peers_working_set_tail; | ||
1727 | break; | ||
1728 | default: | ||
1729 | GNUNET_break (0); | ||
1730 | return 0; | ||
1731 | } | ||
1732 | |||
1733 | add_first = GNUNET_YES; | ||
1734 | add_second = GNUNET_YES; | ||
1735 | |||
1736 | if (check == GNUNET_YES) | ||
1737 | { | ||
1738 | first_iter = *first_list; | ||
1739 | while (first_iter != NULL) | ||
1740 | { | ||
1741 | if (first_iter->index == second) | ||
1742 | { | ||
1743 | add_first = GNUNET_NO; | ||
1744 | break; | ||
1745 | } | ||
1746 | first_iter = first_iter->next; | ||
1747 | } | ||
1748 | |||
1749 | second_iter = *second_list; | ||
1750 | while (second_iter != NULL) | ||
1751 | { | ||
1752 | if (second_iter->index == first) | ||
1753 | { | ||
1754 | add_second = GNUNET_NO; | ||
1755 | break; | ||
1756 | } | ||
1757 | second_iter = second_iter->next; | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1761 | added = 0; | ||
1762 | if (add_first) | ||
1763 | { | ||
1764 | new_first = GNUNET_malloc (sizeof (struct PeerConnection)); | ||
1765 | new_first->index = second; | ||
1766 | GNUNET_CONTAINER_DLL_insert (*first_list, *first_tail, new_first); | ||
1767 | pg->peers[first].num_connections++; | ||
1768 | added++; | ||
1769 | } | ||
1770 | |||
1771 | if (add_second) | ||
1772 | { | ||
1773 | new_second = GNUNET_malloc (sizeof (struct PeerConnection)); | ||
1774 | new_second->index = first; | ||
1775 | GNUNET_CONTAINER_DLL_insert (*second_list, *second_tail, new_second); | ||
1776 | pg->peers[second].num_connections++; | ||
1777 | added++; | ||
1778 | } | ||
1779 | |||
1780 | return added; | ||
1781 | } | ||
1782 | |||
1783 | /** | ||
1784 | * Scale free network construction as described in: | ||
1785 | * | ||
1786 | * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999. | ||
1787 | * | ||
1788 | * Start with a network of "one" peer, then progressively add | ||
1789 | * peers up to the total number. At each step, iterate over | ||
1790 | * all possible peers and connect new peer based on number of | ||
1791 | * existing connections of the target peer. | ||
1792 | * | ||
1793 | * @param pg the peer group we are dealing with | ||
1794 | * @param proc the connection processor to use | ||
1795 | * @param list the peer list to use | ||
1796 | * | ||
1797 | * @return the number of connections created | ||
1798 | */ | ||
1799 | static unsigned int | ||
1800 | create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, | ||
1801 | GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) | ||
1802 | { | ||
1803 | |||
1804 | unsigned int total_connections; | ||
1805 | unsigned int outer_count; | ||
1806 | unsigned int i; | ||
1807 | unsigned int previous_total_connections; | ||
1808 | double random; | ||
1809 | double probability; | ||
1810 | |||
1811 | GNUNET_assert (pg->total > 1); | ||
1812 | |||
1813 | /* Add a connection between the first two nodes */ | ||
1814 | total_connections = proc (pg, 0, 1, list, GNUNET_YES); | ||
1815 | |||
1816 | for (outer_count = 1; outer_count < pg->total; outer_count++) | ||
1817 | { | ||
1818 | previous_total_connections = total_connections; | ||
1819 | for (i = 0; i < outer_count; i++) | ||
1820 | { | ||
1821 | probability = | ||
1822 | pg->peers[i].num_connections / (double) previous_total_connections; | ||
1823 | random = | ||
1824 | ((double) | ||
1825 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1826 | UINT64_MAX)) / ((double) UINT64_MAX); | ||
1827 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1828 | "Considering connecting peer %d to peer %d\n", outer_count, | ||
1829 | i); | ||
1830 | if (random < probability) | ||
1831 | { | ||
1832 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", | ||
1833 | outer_count, i); | ||
1834 | total_connections += proc (pg, outer_count, i, list, GNUNET_YES); | ||
1835 | } | ||
1836 | } | ||
1837 | } | ||
1838 | |||
1839 | return total_connections; | ||
1840 | } | ||
1841 | |||
1842 | /** | ||
1843 | * Create a topology given a peer group (set of running peers) | ||
1844 | * and a connection processor. Creates a small world topology | ||
1845 | * according to the rewired ring construction. The basic | ||
1846 | * behavior is that a ring topology is created, but with some | ||
1847 | * probability instead of connecting a peer to the next | ||
1848 | * neighbor in the ring a connection will be created to a peer | ||
1849 | * selected uniformly at random. We use the TESTING | ||
1850 | * PERCENTAGE option to specify what number of | ||
1851 | * connections each peer should have. Default is 2, | ||
1852 | * which makes the ring, any given number is multiplied by | ||
1853 | * the log of the network size; i.e. a PERCENTAGE of 2 makes | ||
1854 | * each peer have on average 2logn connections. The additional | ||
1855 | * connections are made at increasing distance around the ring | ||
1856 | * from the original peer, or to random peers based on the re- | ||
1857 | * wiring probability. The TESTING | ||
1858 | * PROBABILITY option is used as the probability that a given | ||
1859 | * connection is rewired. | ||
1860 | * | ||
1861 | * @param pg the peergroup to create the topology on | ||
1862 | * @param proc the connection processor to call to actually set | ||
1863 | * up connections between two peers | ||
1864 | * @param list the peer list to use | ||
1865 | * | ||
1866 | * @return the number of connections that were set up | ||
1867 | * | ||
1868 | */ | ||
1869 | static unsigned int | ||
1870 | create_small_world_ring (struct GNUNET_TESTING_PeerGroup *pg, | ||
1871 | GNUNET_TESTING_ConnectionProcessor proc, | ||
1872 | enum PeerLists list) | ||
1873 | { | ||
1874 | unsigned int i, j; | ||
1875 | int nodeToConnect; | ||
1876 | unsigned int natLog; | ||
1877 | unsigned int randomPeer; | ||
1878 | double random, logNModifier, probability; | ||
1879 | unsigned int smallWorldConnections; | ||
1880 | int connsPerPeer; | ||
1881 | char *p_string; | ||
1882 | int max; | ||
1883 | int min; | ||
1884 | unsigned int useAnd; | ||
1885 | int connect_attempts; | ||
1886 | |||
1887 | logNModifier = 0.5; /* FIXME: default value? */ | ||
1888 | if (GNUNET_OK == | ||
1889 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", | ||
1890 | &p_string)) | ||
1891 | { | ||
1892 | if (SSCANF (p_string, "%lf", &logNModifier) != 1) | ||
1893 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1894 | _ | ||
1895 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
1896 | p_string, "LOGNMODIFIER", "TESTING"); | ||
1897 | GNUNET_free (p_string); | ||
1898 | } | ||
1899 | probability = 0.5; /* FIXME: default percentage? */ | ||
1900 | if (GNUNET_OK == | ||
1901 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", | ||
1902 | &p_string)) | ||
1903 | { | ||
1904 | if (SSCANF (p_string, "%lf", &probability) != 1) | ||
1905 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1906 | _ | ||
1907 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
1908 | p_string, "PERCENTAGE", "TESTING"); | ||
1909 | GNUNET_free (p_string); | ||
1910 | } | ||
1911 | natLog = log (pg->total); | ||
1912 | connsPerPeer = ceil (natLog * logNModifier); | ||
1913 | |||
1914 | if (connsPerPeer % 2 == 1) | ||
1915 | connsPerPeer += 1; | ||
1916 | |||
1917 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Target is %d connections per peer.", | ||
1918 | connsPerPeer); | ||
1919 | |||
1920 | smallWorldConnections = 0; | ||
1921 | connect_attempts = 0; | ||
1922 | for (i = 0; i < pg->total; i++) | ||
1923 | { | ||
1924 | useAnd = 0; | ||
1925 | max = i + connsPerPeer / 2; | ||
1926 | min = i - connsPerPeer / 2; | ||
1927 | |||
1928 | if (max > pg->total - 1) | ||
1929 | { | ||
1930 | max = max - pg->total; | ||
1931 | useAnd = 1; | ||
1932 | } | ||
1933 | |||
1934 | if (min < 0) | ||
1935 | { | ||
1936 | min = pg->total - 1 + min; | ||
1937 | useAnd = 1; | ||
1938 | } | ||
1939 | |||
1940 | for (j = 0; j < connsPerPeer / 2; j++) | ||
1941 | { | ||
1942 | random = | ||
1943 | ((double) | ||
1944 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
1945 | UINT64_MAX) / ((double) UINT64_MAX)); | ||
1946 | if (random < probability) | ||
1947 | { | ||
1948 | /* Connect to uniformly selected random peer */ | ||
1949 | randomPeer = | ||
1950 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); | ||
1951 | while ((((randomPeer < max) && (randomPeer > min)) && (useAnd == 0)) || | ||
1952 | (((randomPeer > min) || (randomPeer < max)) && (useAnd == 1))) | ||
1953 | { | ||
1954 | randomPeer = | ||
1955 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); | ||
1956 | } | ||
1957 | smallWorldConnections += proc (pg, i, randomPeer, list, GNUNET_YES); | ||
1958 | } | ||
1959 | else | ||
1960 | { | ||
1961 | nodeToConnect = i + j + 1; | ||
1962 | if (nodeToConnect > pg->total - 1) | ||
1963 | { | ||
1964 | nodeToConnect = nodeToConnect - pg->total; | ||
1965 | } | ||
1966 | connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); | ||
1967 | } | ||
1968 | } | ||
1969 | |||
1970 | } | ||
1971 | |||
1972 | connect_attempts += smallWorldConnections; | ||
1973 | |||
1974 | return connect_attempts; | ||
1975 | } | ||
1976 | |||
1977 | /** | ||
1978 | * Create a topology given a peer group (set of running peers) | ||
1979 | * and a connection processor. | ||
1980 | * | ||
1981 | * @param pg the peergroup to create the topology on | ||
1982 | * @param proc the connection processor to call to actually set | ||
1983 | * up connections between two peers | ||
1984 | * @param list the peer list to use | ||
1985 | * | ||
1986 | * @return the number of connections that were set up | ||
1987 | * | ||
1988 | */ | ||
1989 | static unsigned int | ||
1990 | create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, | ||
1991 | GNUNET_TESTING_ConnectionProcessor proc, | ||
1992 | enum PeerLists list) | ||
1993 | { | ||
1994 | unsigned int outer_count, inner_count; | ||
1995 | unsigned int cutoff; | ||
1996 | int connect_attempts; | ||
1997 | double nat_percentage; | ||
1998 | char *p_string; | ||
1999 | |||
2000 | nat_percentage = 0.6; /* FIXME: default percentage? */ | ||
2001 | if (GNUNET_OK == | ||
2002 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", | ||
2003 | &p_string)) | ||
2004 | { | ||
2005 | if (SSCANF (p_string, "%lf", &nat_percentage) != 1) | ||
2006 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2007 | _ | ||
2008 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
2009 | p_string, "PERCENTAGE", "TESTING"); | ||
2010 | GNUNET_free (p_string); | ||
2011 | } | ||
2012 | |||
2013 | cutoff = (unsigned int) (nat_percentage * pg->total); | ||
2014 | connect_attempts = 0; | ||
2015 | for (outer_count = 0; outer_count < pg->total - 1; outer_count++) | ||
2016 | { | ||
2017 | for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) | ||
2018 | { | ||
2019 | if ((outer_count > cutoff) || (inner_count > cutoff)) | ||
2020 | { | ||
2021 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", | ||
2022 | outer_count, inner_count); | ||
2023 | connect_attempts += | ||
2024 | proc (pg, outer_count, inner_count, list, GNUNET_YES); | ||
2025 | } | ||
2026 | } | ||
2027 | } | ||
2028 | return connect_attempts; | ||
2029 | } | ||
2030 | |||
2031 | #if TOPOLOGY_HACK | ||
2032 | /** | ||
2033 | * Create a topology given a peer group (set of running peers) | ||
2034 | * and a connection processor. | ||
2035 | * | ||
2036 | * @param pg the peergroup to create the topology on | ||
2037 | * @param proc the connection processor to call to actually set | ||
2038 | * up connections between two peers | ||
2039 | * @param list the peer list to use | ||
2040 | * | ||
2041 | * @return the number of connections that were set up | ||
2042 | * | ||
2043 | */ | ||
2044 | static unsigned int | ||
2045 | create_nated_internet_copy (struct GNUNET_TESTING_PeerGroup *pg, | ||
2046 | GNUNET_TESTING_ConnectionProcessor proc, | ||
2047 | enum PeerLists list) | ||
2048 | { | ||
2049 | unsigned int outer_count, inner_count; | ||
2050 | unsigned int cutoff; | ||
2051 | int connect_attempts; | ||
2052 | double nat_percentage; | ||
2053 | char *p_string; | ||
2054 | unsigned int count; | ||
2055 | struct ProgressMeter *conn_meter; | ||
2056 | |||
2057 | nat_percentage = 0.6; /* FIXME: default percentage? */ | ||
2058 | if (GNUNET_OK == | ||
2059 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", | ||
2060 | &p_string)) | ||
2061 | { | ||
2062 | if (SSCANF (p_string, "%lf", &nat_percentage) != 1) | ||
2063 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2064 | _ | ||
2065 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
2066 | p_string, "PERCENTAGE", "TESTING"); | ||
2067 | GNUNET_free (p_string); | ||
2068 | } | ||
2069 | |||
2070 | cutoff = (unsigned int) (nat_percentage * pg->total); | ||
2071 | count = 0; | ||
2072 | for (outer_count = 0; outer_count < pg->total - 1; outer_count++) | ||
2073 | { | ||
2074 | for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) | ||
2075 | { | ||
2076 | if ((outer_count > cutoff) || (inner_count > cutoff)) | ||
2077 | { | ||
2078 | count++; | ||
2079 | } | ||
2080 | } | ||
2081 | } | ||
2082 | conn_meter = create_meter (count, "NAT COPY", GNUNET_YES); | ||
2083 | connect_attempts = 0; | ||
2084 | for (outer_count = 0; outer_count < pg->total - 1; outer_count++) | ||
2085 | { | ||
2086 | for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) | ||
2087 | { | ||
2088 | if ((outer_count > cutoff) || (inner_count > cutoff)) | ||
2089 | { | ||
2090 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", | ||
2091 | outer_count, inner_count); | ||
2092 | connect_attempts += | ||
2093 | proc (pg, outer_count, inner_count, list, GNUNET_YES); | ||
2094 | add_connections (pg, outer_count, inner_count, ALLOWED, GNUNET_NO); | ||
2095 | update_meter (conn_meter); | ||
2096 | } | ||
2097 | } | ||
2098 | } | ||
2099 | free_meter (conn_meter); | ||
2100 | |||
2101 | return connect_attempts; | ||
2102 | } | ||
2103 | #endif | ||
2104 | |||
2105 | /** | ||
2106 | * Create a topology given a peer group (set of running peers) | ||
2107 | * and a connection processor. | ||
2108 | * | ||
2109 | * @param pg the peergroup to create the topology on | ||
2110 | * @param proc the connection processor to call to actually set | ||
2111 | * up connections between two peers | ||
2112 | * @param list the peer list to use | ||
2113 | * | ||
2114 | * @return the number of connections that were set up | ||
2115 | * | ||
2116 | */ | ||
2117 | static unsigned int | ||
2118 | create_small_world (struct GNUNET_TESTING_PeerGroup *pg, | ||
2119 | GNUNET_TESTING_ConnectionProcessor proc, | ||
2120 | enum PeerLists list) | ||
2121 | { | ||
2122 | unsigned int i, j, k; | ||
2123 | unsigned int square; | ||
2124 | unsigned int rows; | ||
2125 | unsigned int cols; | ||
2126 | unsigned int toggle = 1; | ||
2127 | unsigned int nodeToConnect; | ||
2128 | unsigned int natLog; | ||
2129 | unsigned int node1Row; | ||
2130 | unsigned int node1Col; | ||
2131 | unsigned int node2Row; | ||
2132 | unsigned int node2Col; | ||
2133 | unsigned int distance; | ||
2134 | double probability, random, percentage; | ||
2135 | unsigned int smallWorldConnections; | ||
2136 | unsigned int small_world_it; | ||
2137 | char *p_string; | ||
2138 | int connect_attempts; | ||
2139 | |||
2140 | square = floor (sqrt (pg->total)); | ||
2141 | rows = square; | ||
2142 | cols = square; | ||
2143 | |||
2144 | percentage = 0.5; /* FIXME: default percentage? */ | ||
2145 | if (GNUNET_OK == | ||
2146 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PERCENTAGE", | ||
2147 | &p_string)) | ||
2148 | { | ||
2149 | if (SSCANF (p_string, "%lf", &percentage) != 1) | ||
2150 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2151 | _ | ||
2152 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
2153 | p_string, "PERCENTAGE", "TESTING"); | ||
2154 | GNUNET_free (p_string); | ||
2155 | } | ||
2156 | if (percentage < 0.0) | ||
2157 | { | ||
2158 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2159 | _ | ||
2160 | ("Invalid value `%s' for option `%s' in section `%s': got %f, needed value greater than 0\n"), | ||
2161 | "PERCENTAGE", "TESTING", percentage); | ||
2162 | percentage = 0.5; | ||
2163 | } | ||
2164 | probability = 0.5; /* FIXME: default percentage? */ | ||
2165 | if (GNUNET_OK == | ||
2166 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", | ||
2167 | &p_string)) | ||
2168 | { | ||
2169 | if (SSCANF (p_string, "%lf", &probability) != 1) | ||
2170 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2171 | _ | ||
2172 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
2173 | p_string, "PROBABILITY", "TESTING"); | ||
2174 | GNUNET_free (p_string); | ||
2175 | } | ||
2176 | if (square * square != pg->total) | ||
2177 | { | ||
2178 | while (rows * cols < pg->total) | ||
2179 | { | ||
2180 | if (toggle % 2 == 0) | ||
2181 | rows++; | ||
2182 | else | ||
2183 | cols++; | ||
2184 | |||
2185 | toggle++; | ||
2186 | } | ||
2187 | } | ||
2188 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2189 | "Connecting nodes in 2d torus topology: %u rows %u columns\n", | ||
2190 | rows, cols); | ||
2191 | connect_attempts = 0; | ||
2192 | /* Rows and columns are all sorted out, now iterate over all nodes and connect each | ||
2193 | * to the node to its right and above. Once this is over, we'll have our torus! | ||
2194 | * Special case for the last node (if the rows and columns are not equal), connect | ||
2195 | * to the first in the row to maintain topology. | ||
2196 | */ | ||
2197 | for (i = 0; i < pg->total; i++) | ||
2198 | { | ||
2199 | /* First connect to the node to the right */ | ||
2200 | if (((i + 1) % cols != 0) && (i + 1 != pg->total)) | ||
2201 | nodeToConnect = i + 1; | ||
2202 | else if (i + 1 == pg->total) | ||
2203 | nodeToConnect = rows * cols - cols; | ||
2204 | else | ||
2205 | nodeToConnect = i - cols + 1; | ||
2206 | |||
2207 | connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); | ||
2208 | |||
2209 | if (i < cols) | ||
2210 | { | ||
2211 | nodeToConnect = (rows * cols) - cols + i; | ||
2212 | if (nodeToConnect >= pg->total) | ||
2213 | nodeToConnect -= cols; | ||
2214 | } | ||
2215 | else | ||
2216 | nodeToConnect = i - cols; | ||
2217 | |||
2218 | if (nodeToConnect < pg->total) | ||
2219 | connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); | ||
2220 | } | ||
2221 | natLog = log (pg->total); | ||
2222 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2223 | "natural log of %d is %d, will run %d iterations\n", pg->total, | ||
2224 | natLog, (int) (natLog * percentage)); | ||
2225 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2226 | "Total connections added thus far: %u!\n", connect_attempts); | ||
2227 | smallWorldConnections = 0; | ||
2228 | small_world_it = (unsigned int) (natLog * percentage); | ||
2229 | if (small_world_it < 1) | ||
2230 | small_world_it = 1; | ||
2231 | GNUNET_assert (small_world_it > 0 && small_world_it < (unsigned int) -1); | ||
2232 | for (i = 0; i < small_world_it; i++) | ||
2233 | { | ||
2234 | for (j = 0; j < pg->total; j++) | ||
2235 | { | ||
2236 | /* Determine the row and column of node at position j on the 2d torus */ | ||
2237 | node1Row = j / cols; | ||
2238 | node1Col = j - (node1Row * cols); | ||
2239 | for (k = 0; k < pg->total; k++) | ||
2240 | { | ||
2241 | /* Determine the row and column of node at position k on the 2d torus */ | ||
2242 | node2Row = k / cols; | ||
2243 | node2Col = k - (node2Row * cols); | ||
2244 | /* Simple Cartesian distance */ | ||
2245 | distance = abs (node1Row - node2Row) + abs (node1Col - node2Col); | ||
2246 | if (distance > 1) | ||
2247 | { | ||
2248 | /* Calculate probability as 1 over the square of the distance */ | ||
2249 | probability = 1.0 / (distance * distance); | ||
2250 | /* Choose a random value between 0 and 1 */ | ||
2251 | random = | ||
2252 | ((double) | ||
2253 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
2254 | UINT64_MAX)) / ((double) UINT64_MAX); | ||
2255 | /* If random < probability, then connect the two nodes */ | ||
2256 | if (random < probability) | ||
2257 | smallWorldConnections += proc (pg, j, k, list, GNUNET_YES); | ||
2258 | |||
2259 | } | ||
2260 | } | ||
2261 | } | ||
2262 | } | ||
2263 | connect_attempts += smallWorldConnections; | ||
2264 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2265 | "Total connections added for small world: %d!\n", | ||
2266 | smallWorldConnections); | ||
2267 | return connect_attempts; | ||
2268 | } | ||
2269 | |||
2270 | /** | ||
2271 | * Create a topology given a peer group (set of running peers) | ||
2272 | * and a connection processor. | ||
2273 | * | ||
2274 | * @param pg the peergroup to create the topology on | ||
2275 | * @param proc the connection processor to call to actually set | ||
2276 | * up connections between two peers | ||
2277 | * @param list the peer list to use | ||
2278 | * | ||
2279 | * @return the number of connections that were set up | ||
2280 | * | ||
2281 | */ | ||
2282 | static unsigned int | ||
2283 | create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, | ||
2284 | GNUNET_TESTING_ConnectionProcessor proc, | ||
2285 | enum PeerLists list) | ||
2286 | { | ||
2287 | double temp_rand; | ||
2288 | unsigned int outer_count; | ||
2289 | unsigned int inner_count; | ||
2290 | int connect_attempts; | ||
2291 | double probability; | ||
2292 | char *p_string; | ||
2293 | |||
2294 | probability = 0.5; /* FIXME: default percentage? */ | ||
2295 | if (GNUNET_OK == | ||
2296 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "TESTING", "PROBABILITY", | ||
2297 | &p_string)) | ||
2298 | { | ||
2299 | if (SSCANF (p_string, "%lf", &probability) != 1) | ||
2300 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2301 | _ | ||
2302 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
2303 | p_string, "PROBABILITY", "TESTING"); | ||
2304 | GNUNET_free (p_string); | ||
2305 | } | ||
2306 | connect_attempts = 0; | ||
2307 | for (outer_count = 0; outer_count < pg->total - 1; outer_count++) | ||
2308 | { | ||
2309 | for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) | ||
2310 | { | ||
2311 | temp_rand = | ||
2312 | ((double) | ||
2313 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
2314 | UINT64_MAX)) / ((double) UINT64_MAX); | ||
2315 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "rand is %f probability is %f\n", | ||
2316 | temp_rand, probability); | ||
2317 | if (temp_rand < probability) | ||
2318 | { | ||
2319 | connect_attempts += | ||
2320 | proc (pg, outer_count, inner_count, list, GNUNET_YES); | ||
2321 | } | ||
2322 | } | ||
2323 | } | ||
2324 | |||
2325 | return connect_attempts; | ||
2326 | } | ||
2327 | |||
2328 | /** | ||
2329 | * Create a topology given a peer group (set of running peers) | ||
2330 | * and a connection processor. This particular function creates | ||
2331 | * the connections for a 2d-torus, plus additional "closest" | ||
2332 | * connections per peer. | ||
2333 | * | ||
2334 | * @param pg the peergroup to create the topology on | ||
2335 | * @param proc the connection processor to call to actually set | ||
2336 | * up connections between two peers | ||
2337 | * @param list the peer list to use | ||
2338 | * | ||
2339 | * @return the number of connections that were set up | ||
2340 | * | ||
2341 | */ | ||
2342 | static unsigned int | ||
2343 | create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, | ||
2344 | GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) | ||
2345 | { | ||
2346 | unsigned int i; | ||
2347 | unsigned int square; | ||
2348 | unsigned int rows; | ||
2349 | unsigned int cols; | ||
2350 | unsigned int toggle = 1; | ||
2351 | unsigned int nodeToConnect; | ||
2352 | int connect_attempts; | ||
2353 | |||
2354 | connect_attempts = 0; | ||
2355 | |||
2356 | square = floor (sqrt (pg->total)); | ||
2357 | rows = square; | ||
2358 | cols = square; | ||
2359 | |||
2360 | if (square * square != pg->total) | ||
2361 | { | ||
2362 | while (rows * cols < pg->total) | ||
2363 | { | ||
2364 | if (toggle % 2 == 0) | ||
2365 | rows++; | ||
2366 | else | ||
2367 | cols++; | ||
2368 | |||
2369 | toggle++; | ||
2370 | } | ||
2371 | } | ||
2372 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2373 | "Connecting nodes in 2d torus topology: %u rows %u columns\n", | ||
2374 | rows, cols); | ||
2375 | /* Rows and columns are all sorted out, now iterate over all nodes and connect each | ||
2376 | * to the node to its right and above. Once this is over, we'll have our torus! | ||
2377 | * Special case for the last node (if the rows and columns are not equal), connect | ||
2378 | * to the first in the row to maintain topology. | ||
2379 | */ | ||
2380 | for (i = 0; i < pg->total; i++) | ||
2381 | { | ||
2382 | /* First connect to the node to the right */ | ||
2383 | if (((i + 1) % cols != 0) && (i + 1 != pg->total)) | ||
2384 | nodeToConnect = i + 1; | ||
2385 | else if (i + 1 == pg->total) | ||
2386 | nodeToConnect = rows * cols - cols; | ||
2387 | else | ||
2388 | nodeToConnect = i - cols + 1; | ||
2389 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, | ||
2390 | nodeToConnect); | ||
2391 | connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); | ||
2392 | |||
2393 | /* Second connect to the node immediately above */ | ||
2394 | if (i < cols) | ||
2395 | { | ||
2396 | nodeToConnect = (rows * cols) - cols + i; | ||
2397 | if (nodeToConnect >= pg->total) | ||
2398 | nodeToConnect -= cols; | ||
2399 | } | ||
2400 | else | ||
2401 | nodeToConnect = i - cols; | ||
2402 | |||
2403 | if (nodeToConnect < pg->total) | ||
2404 | { | ||
2405 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", i, | ||
2406 | nodeToConnect); | ||
2407 | connect_attempts += proc (pg, i, nodeToConnect, list, GNUNET_YES); | ||
2408 | } | ||
2409 | |||
2410 | } | ||
2411 | |||
2412 | return connect_attempts; | ||
2413 | } | ||
2414 | |||
2415 | /** | ||
2416 | * Create a topology given a peer group (set of running peers) | ||
2417 | * and a connection processor. | ||
2418 | * | ||
2419 | * @param pg the peergroup to create the topology on | ||
2420 | * @param proc the connection processor to call to actually set | ||
2421 | * up connections between two peers | ||
2422 | * @param list the peer list to use | ||
2423 | * @param check does the connection processor need to check before | ||
2424 | * performing an action on the list? | ||
2425 | * | ||
2426 | * @return the number of connections that were set up | ||
2427 | * | ||
2428 | */ | ||
2429 | static unsigned int | ||
2430 | create_clique (struct GNUNET_TESTING_PeerGroup *pg, | ||
2431 | GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list, | ||
2432 | unsigned int check) | ||
2433 | { | ||
2434 | unsigned int outer_count; | ||
2435 | unsigned int inner_count; | ||
2436 | int connect_attempts; | ||
2437 | struct ProgressMeter *conn_meter; | ||
2438 | |||
2439 | connect_attempts = 0; | ||
2440 | |||
2441 | conn_meter = | ||
2442 | create_meter ((((pg->total * pg->total) + pg->total) / 2) - pg->total, | ||
2443 | "Create Clique ", GNUNET_NO); | ||
2444 | for (outer_count = 0; outer_count < pg->total - 1; outer_count++) | ||
2445 | { | ||
2446 | for (inner_count = outer_count + 1; inner_count < pg->total; inner_count++) | ||
2447 | { | ||
2448 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", | ||
2449 | outer_count, inner_count); | ||
2450 | connect_attempts += proc (pg, outer_count, inner_count, list, check); | ||
2451 | update_meter (conn_meter); | ||
2452 | } | ||
2453 | } | ||
2454 | reset_meter (conn_meter); | ||
2455 | free_meter (conn_meter); | ||
2456 | return connect_attempts; | ||
2457 | } | ||
2458 | |||
2459 | #if !OLD | ||
2460 | /** | ||
2461 | * Iterator over hash map entries. | ||
2462 | * | ||
2463 | * @param cls closure the peer group | ||
2464 | * @param key the key stored in the hashmap is the | ||
2465 | * index of the peer to connect to | ||
2466 | * @param value value in the hash map, handle to the peer daemon | ||
2467 | * @return GNUNET_YES if we should continue to | ||
2468 | * iterate, | ||
2469 | * GNUNET_NO if not. | ||
2470 | */ | ||
2471 | static int | ||
2472 | unblacklist_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
2473 | { | ||
2474 | struct UnblacklistContext *un_ctx = cls; | ||
2475 | uint32_t second_pos; | ||
2476 | |||
2477 | uid_from_hash (key, &second_pos); | ||
2478 | |||
2479 | unblacklist_connections (un_ctx->pg, un_ctx->first_uid, second_pos); | ||
2480 | |||
2481 | return GNUNET_YES; | ||
2482 | } | ||
2483 | #endif | ||
2484 | |||
2485 | #if !OLD | ||
2486 | /** | ||
2487 | * Create a blacklist topology based on the allowed topology | ||
2488 | * which disallows any connections not in the allowed topology | ||
2489 | * at the transport level. | ||
2490 | * | ||
2491 | * @param pg the peergroup to create the topology on | ||
2492 | * @param proc the connection processor to call to allow | ||
2493 | * up connections between two peers | ||
2494 | * | ||
2495 | * @return the number of connections that were set up | ||
2496 | * | ||
2497 | */ | ||
2498 | static unsigned int | ||
2499 | copy_allowed (struct GNUNET_TESTING_PeerGroup *pg, | ||
2500 | GNUNET_TESTING_ConnectionProcessor proc) | ||
2501 | { | ||
2502 | unsigned int count; | ||
2503 | unsigned int total; | ||
2504 | struct PeerConnection *iter; | ||
2505 | |||
2506 | #if !OLD | ||
2507 | struct UnblacklistContext un_ctx; | ||
2508 | |||
2509 | un_ctx.pg = pg; | ||
2510 | #endif | ||
2511 | total = 0; | ||
2512 | for (count = 0; count < pg->total - 1; count++) | ||
2513 | { | ||
2514 | #if OLD | ||
2515 | iter = pg->peers[count].allowed_peers_head; | ||
2516 | while (iter != NULL) | ||
2517 | { | ||
2518 | remove_connections (pg, count, iter->index, BLACKLIST, GNUNET_YES); | ||
2519 | //unblacklist_connections(pg, count, iter->index); | ||
2520 | iter = iter->next; | ||
2521 | } | ||
2522 | #else | ||
2523 | un_ctx.first_uid = count; | ||
2524 | total += | ||
2525 | GNUNET_CONTAINER_multihashmap_iterate (pg->peers[count].allowed_peers, | ||
2526 | &unblacklist_iterator, &un_ctx); | ||
2527 | #endif | ||
2528 | } | ||
2529 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unblacklisted %u peers\n", total); | ||
2530 | return total; | ||
2531 | } | ||
2532 | #endif | ||
2533 | |||
2534 | /** | ||
2535 | * Create a topology given a peer group (set of running peers) | ||
2536 | * and a connection processor. | ||
2537 | * | ||
2538 | * @param pg the peergroup to create the topology on | ||
2539 | * @param proc the connection processor to call to actually set | ||
2540 | * up connections between two peers | ||
2541 | * @param list which list should be modified | ||
2542 | * | ||
2543 | * @return the number of connections that were set up | ||
2544 | * | ||
2545 | */ | ||
2546 | static unsigned int | ||
2547 | create_line (struct GNUNET_TESTING_PeerGroup *pg, | ||
2548 | GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) | ||
2549 | { | ||
2550 | unsigned int count; | ||
2551 | unsigned int connect_attempts; | ||
2552 | |||
2553 | connect_attempts = 0; | ||
2554 | /* Connect each peer to the next highest numbered peer */ | ||
2555 | for (count = 0; count < pg->total - 1; count++) | ||
2556 | { | ||
2557 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", | ||
2558 | count, count + 1); | ||
2559 | connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); | ||
2560 | } | ||
2561 | |||
2562 | return connect_attempts; | ||
2563 | } | ||
2564 | |||
2565 | /** | ||
2566 | * Create a topology given a peer group (set of running peers) | ||
2567 | * and a connection processor. | ||
2568 | * | ||
2569 | * @param pg the peergroup to create the topology on | ||
2570 | * @param filename the file to read topology information from | ||
2571 | * @param proc the connection processor to call to actually set | ||
2572 | * up connections between two peers | ||
2573 | * @param list the peer list to use | ||
2574 | * | ||
2575 | * @return the number of connections that were set up | ||
2576 | * | ||
2577 | */ | ||
2578 | static unsigned int | ||
2579 | create_from_file (struct GNUNET_TESTING_PeerGroup *pg, char *filename, | ||
2580 | GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) | ||
2581 | { | ||
2582 | int connect_attempts; | ||
2583 | unsigned int first_peer_index; | ||
2584 | unsigned int second_peer_index; | ||
2585 | struct stat frstat; | ||
2586 | int count; | ||
2587 | char *data; | ||
2588 | const char *buf; | ||
2589 | unsigned int total_peers; | ||
2590 | enum States curr_state; | ||
2591 | |||
2592 | connect_attempts = 0; | ||
2593 | if (GNUNET_OK != GNUNET_DISK_file_test (filename)) | ||
2594 | GNUNET_DISK_fn_write (filename, NULL, 0, GNUNET_DISK_PERM_USER_READ); | ||
2595 | |||
2596 | if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0)) | ||
2597 | { | ||
2598 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2599 | "Could not open file `%s' specified for topology!", filename); | ||
2600 | return connect_attempts; | ||
2601 | } | ||
2602 | |||
2603 | data = GNUNET_malloc_large (frstat.st_size); | ||
2604 | GNUNET_assert (data != NULL); | ||
2605 | if (frstat.st_size != GNUNET_DISK_fn_read (filename, data, frstat.st_size)) | ||
2606 | { | ||
2607 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2608 | "Could not read file %s specified for host list, ending test!", | ||
2609 | filename); | ||
2610 | GNUNET_free (data); | ||
2611 | return connect_attempts; | ||
2612 | } | ||
2613 | |||
2614 | buf = data; | ||
2615 | count = 0; | ||
2616 | first_peer_index = 0; | ||
2617 | /* First line should contain a single integer, specifying the number of peers */ | ||
2618 | /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */ | ||
2619 | curr_state = NUM_PEERS; | ||
2620 | while (count < frstat.st_size - 1) | ||
2621 | { | ||
2622 | if ((buf[count] == '\n') || (buf[count] == ' ')) | ||
2623 | { | ||
2624 | count++; | ||
2625 | continue; | ||
2626 | } | ||
2627 | |||
2628 | switch (curr_state) | ||
2629 | { | ||
2630 | case NUM_PEERS: | ||
2631 | errno = 0; | ||
2632 | total_peers = strtoul (&buf[count], NULL, 10); | ||
2633 | if (errno != 0) | ||
2634 | { | ||
2635 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2636 | "Failed to read number of peers from topology file!\n"); | ||
2637 | GNUNET_free (data); | ||
2638 | return connect_attempts; | ||
2639 | } | ||
2640 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u total peers in topology\n", | ||
2641 | total_peers); | ||
2642 | GNUNET_assert (total_peers == pg->total); | ||
2643 | curr_state = PEER_INDEX; | ||
2644 | while ((buf[count] != '\n') && (count < frstat.st_size - 1)) | ||
2645 | count++; | ||
2646 | count++; | ||
2647 | break; | ||
2648 | case PEER_INDEX: | ||
2649 | errno = 0; | ||
2650 | first_peer_index = strtoul (&buf[count], NULL, 10); | ||
2651 | if (errno != 0) | ||
2652 | { | ||
2653 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2654 | "Failed to read peer index from topology file!\n"); | ||
2655 | GNUNET_free (data); | ||
2656 | return connect_attempts; | ||
2657 | } | ||
2658 | while ((buf[count] != ':') && (count < frstat.st_size - 1)) | ||
2659 | count++; | ||
2660 | count++; | ||
2661 | curr_state = OTHER_PEER_INDEX; | ||
2662 | break; | ||
2663 | case COLON: | ||
2664 | if (1 == sscanf (&buf[count], ":")) | ||
2665 | curr_state = OTHER_PEER_INDEX; | ||
2666 | count++; | ||
2667 | break; | ||
2668 | case OTHER_PEER_INDEX: | ||
2669 | errno = 0; | ||
2670 | second_peer_index = strtoul (&buf[count], NULL, 10); | ||
2671 | if (errno != 0) | ||
2672 | { | ||
2673 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2674 | "Failed to peer index from topology file!\n"); | ||
2675 | GNUNET_free (data); | ||
2676 | return connect_attempts; | ||
2677 | } | ||
2678 | /* Assume file is written with first peer 1, but array index is 0 */ | ||
2679 | connect_attempts += | ||
2680 | proc (pg, first_peer_index - 1, second_peer_index - 1, list, | ||
2681 | GNUNET_YES); | ||
2682 | while ((buf[count] != '\n') && (buf[count] != ',') && | ||
2683 | (count < frstat.st_size - 1)) | ||
2684 | count++; | ||
2685 | if (buf[count] == '\n') | ||
2686 | { | ||
2687 | curr_state = PEER_INDEX; | ||
2688 | } | ||
2689 | else if (buf[count] != ',') | ||
2690 | { | ||
2691 | curr_state = OTHER_PEER_INDEX; | ||
2692 | } | ||
2693 | count++; | ||
2694 | break; | ||
2695 | default: | ||
2696 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2697 | "Found bad data in topology file while in state %d!\n", | ||
2698 | curr_state); | ||
2699 | GNUNET_break (0); | ||
2700 | GNUNET_free (data); | ||
2701 | return connect_attempts; | ||
2702 | } | ||
2703 | } | ||
2704 | GNUNET_free (data); | ||
2705 | return connect_attempts; | ||
2706 | } | ||
2707 | |||
2708 | /** | ||
2709 | * Create a topology given a peer group (set of running peers) | ||
2710 | * and a connection processor. | ||
2711 | * | ||
2712 | * @param pg the peergroup to create the topology on | ||
2713 | * @param proc the connection processor to call to actually set | ||
2714 | * up connections between two peers | ||
2715 | * @param list the peer list to use | ||
2716 | * | ||
2717 | * @return the number of connections that were set up | ||
2718 | * | ||
2719 | */ | ||
2720 | static unsigned int | ||
2721 | create_ring (struct GNUNET_TESTING_PeerGroup *pg, | ||
2722 | GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) | ||
2723 | { | ||
2724 | unsigned int count; | ||
2725 | int connect_attempts; | ||
2726 | |||
2727 | connect_attempts = 0; | ||
2728 | |||
2729 | /* Connect each peer to the next highest numbered peer */ | ||
2730 | for (count = 0; count < pg->total - 1; count++) | ||
2731 | { | ||
2732 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer %d to peer %d\n", | ||
2733 | count, count + 1); | ||
2734 | connect_attempts += proc (pg, count, count + 1, list, GNUNET_YES); | ||
2735 | } | ||
2736 | |||
2737 | /* Connect the last peer to the first peer */ | ||
2738 | connect_attempts += proc (pg, pg->total - 1, 0, list, GNUNET_YES); | ||
2739 | |||
2740 | return connect_attempts; | ||
2741 | } | ||
2742 | |||
2743 | #if !OLD | ||
2744 | /** | ||
2745 | * Iterator for writing friends of a peer to a file. | ||
2746 | * | ||
2747 | * @param cls closure, an open writable file handle | ||
2748 | * @param key the key the daemon was stored under | ||
2749 | * @param value the GNUNET_TESTING_Daemon that needs to be written. | ||
2750 | * | ||
2751 | * @return GNUNET_YES to continue iteration | ||
2752 | * | ||
2753 | * TODO: Could replace friend_file_iterator and blacklist_file_iterator | ||
2754 | * with a single file_iterator that takes a closure which contains | ||
2755 | * the prefix to write before the peer. Then this could be used | ||
2756 | * for blacklisting multiple transports and writing the friend | ||
2757 | * file. I'm sure *someone* will complain loudly about other | ||
2758 | * things that negate these functions even existing so no point in | ||
2759 | * "fixing" now. | ||
2760 | */ | ||
2761 | static int | ||
2762 | friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
2763 | { | ||
2764 | FILE *temp_friend_handle = cls; | ||
2765 | struct GNUNET_TESTING_Daemon *peer = value; | ||
2766 | struct GNUNET_PeerIdentity *temppeer; | ||
2767 | struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; | ||
2768 | |||
2769 | temppeer = &peer->id; | ||
2770 | GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); | ||
2771 | FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); | ||
2772 | |||
2773 | return GNUNET_YES; | ||
2774 | } | ||
2775 | |||
2776 | struct BlacklistContext | ||
2777 | { | ||
2778 | /* | ||
2779 | * The (open) file handle to write to | ||
2780 | */ | ||
2781 | FILE *temp_file_handle; | ||
2782 | |||
2783 | /* | ||
2784 | * The transport that this peer will be blacklisted on. | ||
2785 | */ | ||
2786 | char *transport; | ||
2787 | }; | ||
2788 | |||
2789 | /** | ||
2790 | * Iterator for writing blacklist data to appropriate files. | ||
2791 | * | ||
2792 | * @param cls closure, an open writable file handle | ||
2793 | * @param key the key the daemon was stored under | ||
2794 | * @param value the GNUNET_TESTING_Daemon that needs to be written. | ||
2795 | * | ||
2796 | * @return GNUNET_YES to continue iteration | ||
2797 | */ | ||
2798 | static int | ||
2799 | blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
2800 | { | ||
2801 | struct BlacklistContext *blacklist_ctx = cls; | ||
2802 | struct GNUNET_TESTING_Daemon *peer = value; | ||
2803 | struct GNUNET_PeerIdentity *temppeer; | ||
2804 | struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; | ||
2805 | |||
2806 | temppeer = &peer->id; | ||
2807 | GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc); | ||
2808 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", | ||
2809 | blacklist_ctx->transport, (char *) &peer_enc); | ||
2810 | FPRINTF (blacklist_ctx->temp_file_handle, "%s:%s\n", blacklist_ctx->transport, | ||
2811 | (char *) &peer_enc); | ||
2812 | |||
2813 | return GNUNET_YES; | ||
2814 | } | ||
2815 | #endif | ||
2816 | |||
2817 | /* | ||
2818 | * Create the friend files based on the PeerConnection's | ||
2819 | * of each peer in the peer group, and copy the files | ||
2820 | * to the appropriate place | ||
2821 | * | ||
2822 | * @param pg the peer group we are dealing with | ||
2823 | */ | ||
2824 | static int | ||
2825 | create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg) | ||
2826 | { | ||
2827 | FILE *temp_friend_handle; | ||
2828 | unsigned int pg_iter; | ||
2829 | char *temp_service_path; | ||
2830 | struct GNUNET_OS_Process **procarr; | ||
2831 | char *arg; | ||
2832 | char *mytemp; | ||
2833 | |||
2834 | #if NOT_STUPID | ||
2835 | enum GNUNET_OS_ProcessStatusType type; | ||
2836 | unsigned long return_code; | ||
2837 | int count; | ||
2838 | int max_wait = 10; | ||
2839 | #endif | ||
2840 | int ret; | ||
2841 | |||
2842 | ret = GNUNET_OK; | ||
2843 | #if OLD | ||
2844 | struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; | ||
2845 | struct PeerConnection *conn_iter; | ||
2846 | #endif | ||
2847 | procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); | ||
2848 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
2849 | { | ||
2850 | mytemp = GNUNET_DISK_mktemp ("friends"); | ||
2851 | GNUNET_assert (mytemp != NULL); | ||
2852 | temp_friend_handle = FOPEN (mytemp, "wt"); | ||
2853 | GNUNET_assert (temp_friend_handle != NULL); | ||
2854 | #if OLD | ||
2855 | conn_iter = pg->peers[pg_iter].allowed_peers_head; | ||
2856 | while (conn_iter != NULL) | ||
2857 | { | ||
2858 | GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> | ||
2859 | id.hashPubKey, &peer_enc); | ||
2860 | FPRINTF (temp_friend_handle, "%s\n", (char *) &peer_enc); | ||
2861 | conn_iter = conn_iter->next; | ||
2862 | } | ||
2863 | #else | ||
2864 | GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, | ||
2865 | &friend_file_iterator, | ||
2866 | temp_friend_handle); | ||
2867 | #endif | ||
2868 | FCLOSE (temp_friend_handle); | ||
2869 | |||
2870 | if (GNUNET_OK != | ||
2871 | GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, | ||
2872 | "PATHS", "SERVICEHOME", | ||
2873 | &temp_service_path)) | ||
2874 | { | ||
2875 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2876 | _ | ||
2877 | ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), | ||
2878 | "SERVICEHOME", "PATHS"); | ||
2879 | if (UNLINK (mytemp) != 0) | ||
2880 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); | ||
2881 | GNUNET_free (mytemp); | ||
2882 | break; | ||
2883 | } | ||
2884 | |||
2885 | if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ | ||
2886 | { | ||
2887 | GNUNET_asprintf (&arg, "%s/friends", temp_service_path); | ||
2888 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2889 | "Copying file with RENAME(%s,%s)\n", mytemp, arg); | ||
2890 | RENAME (mytemp, arg); | ||
2891 | procarr[pg_iter] = NULL; | ||
2892 | GNUNET_free (arg); | ||
2893 | } | ||
2894 | else /* Remote, scp the file to the correct place */ | ||
2895 | { | ||
2896 | if (NULL != pg->peers[pg_iter].daemon->username) | ||
2897 | GNUNET_asprintf (&arg, "%s@%s:%s/friends", | ||
2898 | pg->peers[pg_iter].daemon->username, | ||
2899 | pg->peers[pg_iter].daemon->hostname, | ||
2900 | temp_service_path); | ||
2901 | else | ||
2902 | GNUNET_asprintf (&arg, "%s:%s/friends", | ||
2903 | pg->peers[pg_iter].daemon->hostname, | ||
2904 | temp_service_path); | ||
2905 | procarr[pg_iter] = | ||
2906 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); | ||
2907 | GNUNET_assert (procarr[pg_iter] != NULL); | ||
2908 | ret = GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: schedule this, throttle! */ | ||
2909 | GNUNET_OS_process_destroy (procarr[pg_iter]); | ||
2910 | if (ret != GNUNET_OK) | ||
2911 | { | ||
2912 | /* FIXME: free contents of 'procarr' array */ | ||
2913 | GNUNET_free (procarr); | ||
2914 | GNUNET_free (temp_service_path); | ||
2915 | GNUNET_free (mytemp); | ||
2916 | GNUNET_free (arg); | ||
2917 | return ret; | ||
2918 | } | ||
2919 | procarr[pg_iter] = NULL; | ||
2920 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2921 | "Copying file with command scp %s %s\n", mytemp, arg); | ||
2922 | GNUNET_free (arg); | ||
2923 | } | ||
2924 | GNUNET_free (temp_service_path); | ||
2925 | GNUNET_free (mytemp); | ||
2926 | } | ||
2927 | |||
2928 | #if NOT_STUPID | ||
2929 | count = 0; | ||
2930 | ret = GNUNET_SYSERR; | ||
2931 | while ((count < max_wait) && (ret != GNUNET_OK)) | ||
2932 | { | ||
2933 | ret = GNUNET_OK; | ||
2934 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
2935 | { | ||
2936 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking copy status of file %d\n", | ||
2937 | pg_iter); | ||
2938 | if (procarr[pg_iter] != NULL) /* Check for already completed! */ | ||
2939 | { | ||
2940 | if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != | ||
2941 | GNUNET_OK) | ||
2942 | { | ||
2943 | ret = GNUNET_SYSERR; | ||
2944 | } | ||
2945 | else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) | ||
2946 | { | ||
2947 | ret = GNUNET_SYSERR; | ||
2948 | } | ||
2949 | else | ||
2950 | { | ||
2951 | GNUNET_OS_process_destroy (procarr[pg_iter]); | ||
2952 | procarr[pg_iter] = NULL; | ||
2953 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); | ||
2954 | } | ||
2955 | } | ||
2956 | } | ||
2957 | count++; | ||
2958 | if (ret == GNUNET_SYSERR) | ||
2959 | { | ||
2960 | /* FIXME: why sleep here? -CG */ | ||
2961 | sleep (1); | ||
2962 | } | ||
2963 | } | ||
2964 | |||
2965 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2966 | "Finished copying all friend files!\n"); | ||
2967 | #endif | ||
2968 | GNUNET_free (procarr); | ||
2969 | return ret; | ||
2970 | } | ||
2971 | |||
2972 | /* | ||
2973 | * Create the blacklist files based on the PeerConnection's | ||
2974 | * of each peer in the peer group, and copy the files | ||
2975 | * to the appropriate place. | ||
2976 | * | ||
2977 | * @param pg the peer group we are dealing with | ||
2978 | * @param transports space delimited list of transports to blacklist | ||
2979 | */ | ||
2980 | static int | ||
2981 | create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, | ||
2982 | const char *transports) | ||
2983 | { | ||
2984 | FILE *temp_file_handle; | ||
2985 | unsigned int pg_iter; | ||
2986 | char *temp_service_path; | ||
2987 | struct GNUNET_OS_Process **procarr; | ||
2988 | char *arg; | ||
2989 | char *mytemp; | ||
2990 | enum GNUNET_OS_ProcessStatusType type; | ||
2991 | unsigned long return_code; | ||
2992 | int count; | ||
2993 | int ret; | ||
2994 | int max_wait = 10; | ||
2995 | int transport_len; | ||
2996 | unsigned int i; | ||
2997 | char *pos; | ||
2998 | char *temp_transports; | ||
2999 | |||
3000 | #if OLD | ||
3001 | struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc; | ||
3002 | struct PeerConnection *conn_iter; | ||
3003 | #else | ||
3004 | static struct BlacklistContext blacklist_ctx; | ||
3005 | #endif | ||
3006 | |||
3007 | procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total); | ||
3008 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
3009 | { | ||
3010 | mytemp = GNUNET_DISK_mktemp ("blacklist"); | ||
3011 | GNUNET_assert (mytemp != NULL); | ||
3012 | temp_file_handle = FOPEN (mytemp, "wt"); | ||
3013 | GNUNET_assert (temp_file_handle != NULL); | ||
3014 | temp_transports = GNUNET_strdup (transports); | ||
3015 | #if !OLD | ||
3016 | blacklist_ctx.temp_file_handle = temp_file_handle; | ||
3017 | #endif | ||
3018 | transport_len = strlen (temp_transports) + 1; | ||
3019 | pos = NULL; | ||
3020 | |||
3021 | for (i = 0; i < transport_len; i++) | ||
3022 | { | ||
3023 | if ((temp_transports[i] == ' ') && (pos == NULL)) | ||
3024 | continue; /* At start of string (whitespace) */ | ||
3025 | else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */ | ||
3026 | { | ||
3027 | temp_transports[i] = '\0'; | ||
3028 | #if OLD | ||
3029 | conn_iter = pg->peers[pg_iter].blacklisted_peers_head; | ||
3030 | while (conn_iter != NULL) | ||
3031 | { | ||
3032 | GNUNET_CRYPTO_hash_to_enc (&pg->peers[conn_iter->index].daemon-> | ||
3033 | id.hashPubKey, &peer_enc); | ||
3034 | FPRINTF (temp_file_handle, "%s:%s\n", pos, (char *) &peer_enc); | ||
3035 | conn_iter = conn_iter->next; | ||
3036 | } | ||
3037 | #else | ||
3038 | blacklist_ctx.transport = pos; | ||
3039 | (void) GNUNET_CONTAINER_multihashmap_iterate (pg-> | ||
3040 | peers | ||
3041 | [pg_iter].blacklisted_peers, | ||
3042 | &blacklist_file_iterator, | ||
3043 | &blacklist_ctx); | ||
3044 | #endif | ||
3045 | pos = NULL; | ||
3046 | } /* At beginning of actual string */ | ||
3047 | else if (pos == NULL) | ||
3048 | { | ||
3049 | pos = &temp_transports[i]; | ||
3050 | } | ||
3051 | } | ||
3052 | |||
3053 | GNUNET_free (temp_transports); | ||
3054 | FCLOSE (temp_file_handle); | ||
3055 | |||
3056 | if (GNUNET_OK != | ||
3057 | GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].daemon->cfg, | ||
3058 | "PATHS", "SERVICEHOME", | ||
3059 | &temp_service_path)) | ||
3060 | { | ||
3061 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3062 | _ | ||
3063 | ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"), | ||
3064 | "SERVICEHOME", "PATHS"); | ||
3065 | if (UNLINK (mytemp) != 0) | ||
3066 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp); | ||
3067 | GNUNET_free (mytemp); | ||
3068 | break; | ||
3069 | } | ||
3070 | |||
3071 | if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */ | ||
3072 | { | ||
3073 | GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path); | ||
3074 | RENAME (mytemp, arg); | ||
3075 | procarr[pg_iter] = NULL; | ||
3076 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3077 | "Copying file with RENAME (%s,%s)\n", mytemp, arg); | ||
3078 | GNUNET_free (arg); | ||
3079 | } | ||
3080 | else /* Remote, scp the file to the correct place */ | ||
3081 | { | ||
3082 | if (NULL != pg->peers[pg_iter].daemon->username) | ||
3083 | GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", | ||
3084 | pg->peers[pg_iter].daemon->username, | ||
3085 | pg->peers[pg_iter].daemon->hostname, | ||
3086 | temp_service_path); | ||
3087 | else | ||
3088 | GNUNET_asprintf (&arg, "%s:%s/blacklist", | ||
3089 | pg->peers[pg_iter].daemon->hostname, | ||
3090 | temp_service_path); | ||
3091 | procarr[pg_iter] = | ||
3092 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "scp", "scp", mytemp, arg, NULL); | ||
3093 | GNUNET_assert (procarr[pg_iter] != NULL); | ||
3094 | GNUNET_OS_process_wait (procarr[pg_iter]); /* FIXME: add scheduled blacklist file copy that parallelizes file copying! */ | ||
3095 | |||
3096 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3097 | "Copying file with command scp %s %s\n", mytemp, arg); | ||
3098 | GNUNET_free (arg); | ||
3099 | } | ||
3100 | GNUNET_free (temp_service_path); | ||
3101 | GNUNET_free (mytemp); | ||
3102 | } | ||
3103 | |||
3104 | count = 0; | ||
3105 | ret = GNUNET_SYSERR; | ||
3106 | while ((count < max_wait) && (ret != GNUNET_OK)) | ||
3107 | { | ||
3108 | ret = GNUNET_OK; | ||
3109 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
3110 | { | ||
3111 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3112 | "Checking copy status of file %d\n", pg_iter); | ||
3113 | if (procarr[pg_iter] != NULL) /* Check for already completed! */ | ||
3114 | { | ||
3115 | if (GNUNET_OS_process_status (procarr[pg_iter], &type, &return_code) != | ||
3116 | GNUNET_OK) | ||
3117 | { | ||
3118 | ret = GNUNET_SYSERR; | ||
3119 | } | ||
3120 | else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0)) | ||
3121 | { | ||
3122 | ret = GNUNET_SYSERR; | ||
3123 | } | ||
3124 | else | ||
3125 | { | ||
3126 | GNUNET_OS_process_destroy (procarr[pg_iter]); | ||
3127 | procarr[pg_iter] = NULL; | ||
3128 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "File %d copied\n", pg_iter); | ||
3129 | } | ||
3130 | } | ||
3131 | } | ||
3132 | count++; | ||
3133 | if (ret == GNUNET_SYSERR) | ||
3134 | { | ||
3135 | /* FIXME: why sleep here? -CG */ | ||
3136 | sleep (1); | ||
3137 | } | ||
3138 | } | ||
3139 | |||
3140 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3141 | "Finished copying all blacklist files!\n"); | ||
3142 | GNUNET_free (procarr); | ||
3143 | return ret; | ||
3144 | } | ||
3145 | |||
3146 | /* Forward Declaration */ | ||
3147 | static void | ||
3148 | schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
3149 | |||
3150 | /** | ||
3151 | * Choose a random peer's next connection to create, and | ||
3152 | * call schedule_connect to set up the connect task. | ||
3153 | * | ||
3154 | * @param pg the peer group to connect | ||
3155 | */ | ||
3156 | static void | ||
3157 | preschedule_connect (struct GNUNET_TESTING_PeerGroup *pg) | ||
3158 | { | ||
3159 | struct ConnectTopologyContext *ct_ctx = &pg->ct_ctx; | ||
3160 | struct PeerConnection *connection_iter; | ||
3161 | struct ConnectContext *connect_context; | ||
3162 | uint32_t random_peer; | ||
3163 | |||
3164 | if (ct_ctx->remaining_connections == 0) | ||
3165 | return; | ||
3166 | random_peer = | ||
3167 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); | ||
3168 | while (pg->peers[random_peer].connect_peers_head == NULL) | ||
3169 | random_peer = | ||
3170 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, pg->total); | ||
3171 | |||
3172 | connection_iter = pg->peers[random_peer].connect_peers_head; | ||
3173 | connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); | ||
3174 | connect_context->first_index = random_peer; | ||
3175 | connect_context->second_index = connection_iter->index; | ||
3176 | connect_context->ct_ctx = ct_ctx; | ||
3177 | connect_context->task = | ||
3178 | GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); | ||
3179 | GNUNET_CONTAINER_DLL_insert (pg->cc_head, pg->cc_tail, connect_context); | ||
3180 | GNUNET_CONTAINER_DLL_remove (pg->peers[random_peer].connect_peers_head, | ||
3181 | pg->peers[random_peer].connect_peers_tail, | ||
3182 | connection_iter); | ||
3183 | GNUNET_free (connection_iter); | ||
3184 | ct_ctx->remaining_connections--; | ||
3185 | } | ||
3186 | |||
3187 | #if USE_SEND_HELLOS | ||
3188 | /* Forward declaration */ | ||
3189 | static void | ||
3190 | schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
3191 | |||
3192 | /** | ||
3193 | * Close connections and free the hello context. | ||
3194 | * | ||
3195 | * @param cls the 'struct SendHelloContext *' | ||
3196 | * @param tc scheduler context | ||
3197 | */ | ||
3198 | static void | ||
3199 | free_hello_context (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3200 | { | ||
3201 | struct SendHelloContext *send_hello_context = cls; | ||
3202 | |||
3203 | if (send_hello_context->peer->daemon->server != NULL) | ||
3204 | { | ||
3205 | GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); | ||
3206 | send_hello_context->peer->daemon->server = NULL; | ||
3207 | } | ||
3208 | if (send_hello_context->peer->daemon->th != NULL) | ||
3209 | { | ||
3210 | GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); | ||
3211 | send_hello_context->peer->daemon->th = NULL; | ||
3212 | } | ||
3213 | if (send_hello_context->core_connect_task != GNUNET_SCHEDULER_NO_TASK) | ||
3214 | { | ||
3215 | GNUNET_SCHEDULER_cancel (send_hello_context->core_connect_task); | ||
3216 | send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; | ||
3217 | } | ||
3218 | send_hello_context->pg->outstanding_connects--; | ||
3219 | GNUNET_free (send_hello_context); | ||
3220 | } | ||
3221 | |||
3222 | /** | ||
3223 | * For peers that haven't yet connected, notify | ||
3224 | * the caller that they have failed (timeout). | ||
3225 | * | ||
3226 | * @param cls the 'struct SendHelloContext *' | ||
3227 | * @param tc scheduler context | ||
3228 | */ | ||
3229 | static void | ||
3230 | notify_remaining_connections_failed (void *cls, | ||
3231 | const struct GNUNET_SCHEDULER_TaskContext | ||
3232 | *tc) | ||
3233 | { | ||
3234 | struct SendHelloContext *send_hello_context = cls; | ||
3235 | struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; | ||
3236 | struct PeerConnection *connection; | ||
3237 | |||
3238 | GNUNET_CORE_disconnect (send_hello_context->peer->daemon->server); | ||
3239 | send_hello_context->peer->daemon->server = NULL; | ||
3240 | |||
3241 | connection = send_hello_context->peer->connect_peers_head; | ||
3242 | |||
3243 | while (connection != NULL) | ||
3244 | { | ||
3245 | if (pg->notify_connection != NULL) | ||
3246 | { | ||
3247 | pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, &pg->peers[connection->index].daemon->id, 0, /* FIXME */ | ||
3248 | send_hello_context->peer->daemon->cfg, | ||
3249 | pg->peers[connection->index].daemon->cfg, | ||
3250 | send_hello_context->peer->daemon, | ||
3251 | pg->peers[connection->index].daemon, | ||
3252 | "Peers failed to connect (timeout)"); | ||
3253 | } | ||
3254 | GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, | ||
3255 | send_hello_context->peer->connect_peers_tail, | ||
3256 | connection); | ||
3257 | GNUNET_free (connection); | ||
3258 | connection = connection->next; | ||
3259 | } | ||
3260 | GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); | ||
3261 | #if BAD | ||
3262 | other_peer = &pg->peers[connection->index]; | ||
3263 | #endif | ||
3264 | } | ||
3265 | |||
3266 | /** | ||
3267 | * For peers that haven't yet connected, send | ||
3268 | * CORE connect requests. | ||
3269 | * | ||
3270 | * @param cls the 'struct SendHelloContext *' | ||
3271 | * @param tc scheduler context | ||
3272 | */ | ||
3273 | static void | ||
3274 | send_core_connect_requests (void *cls, | ||
3275 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3276 | { | ||
3277 | struct SendHelloContext *send_hello_context = cls; | ||
3278 | struct PeerConnection *conn; | ||
3279 | |||
3280 | GNUNET_assert (send_hello_context->peer->daemon->server != NULL); | ||
3281 | |||
3282 | send_hello_context->core_connect_task = GNUNET_SCHEDULER_NO_TASK; | ||
3283 | |||
3284 | send_hello_context->connect_attempts++; | ||
3285 | if (send_hello_context->connect_attempts < | ||
3286 | send_hello_context->pg->ct_ctx.connect_attempts) | ||
3287 | { | ||
3288 | conn = send_hello_context->peer->connect_peers_head; | ||
3289 | while (conn != NULL) | ||
3290 | { | ||
3291 | GNUNET_TRANSPORT_try_connect (send_hello_context->peer->daemon->th, | ||
3292 | &send_hello_context->pg->peers[conn-> | ||
3293 | index].daemon-> | ||
3294 | id); | ||
3295 | conn = conn->next; | ||
3296 | } | ||
3297 | send_hello_context->core_connect_task = | ||
3298 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide | ||
3299 | (send_hello_context->pg-> | ||
3300 | ct_ctx.connect_timeout, | ||
3301 | send_hello_context->pg-> | ||
3302 | ct_ctx.connect_attempts), | ||
3303 | &send_core_connect_requests, | ||
3304 | send_hello_context); | ||
3305 | } | ||
3306 | else | ||
3307 | { | ||
3308 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3309 | "Timeout before all connections created, marking rest as failed!\n"); | ||
3310 | GNUNET_SCHEDULER_add_now (¬ify_remaining_connections_failed, | ||
3311 | send_hello_context); | ||
3312 | } | ||
3313 | |||
3314 | } | ||
3315 | |||
3316 | /** | ||
3317 | * Success, connection is up. Signal client our success. | ||
3318 | * | ||
3319 | * @param cls our "struct SendHelloContext" | ||
3320 | * @param peer identity of the peer that has connected | ||
3321 | * @param atsi performance information | ||
3322 | * | ||
3323 | * FIXME: remove peers from BOTH lists, call notify twice, should | ||
3324 | * double the speed of connections as long as the list iteration | ||
3325 | * doesn't take too long! | ||
3326 | */ | ||
3327 | static void | ||
3328 | core_connect_notify (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
3329 | const struct GNUNET_ATS_Information *atsi) | ||
3330 | { | ||
3331 | struct SendHelloContext *send_hello_context = cls; | ||
3332 | struct PeerConnection *connection; | ||
3333 | struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; | ||
3334 | |||
3335 | #if BAD | ||
3336 | struct PeerData *other_peer; | ||
3337 | #endif | ||
3338 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peer %s to peer %s\n", | ||
3339 | ctx->d1->shortname, GNUNET_i2s (peer)); | ||
3340 | if (0 == | ||
3341 | memcmp (&send_hello_context->peer->daemon->id, peer, | ||
3342 | sizeof (struct GNUNET_PeerIdentity))) | ||
3343 | return; | ||
3344 | |||
3345 | connection = send_hello_context->peer->connect_peers_head; | ||
3346 | #if BAD | ||
3347 | other_peer = NULL; | ||
3348 | #endif | ||
3349 | |||
3350 | while ((connection != NULL) && | ||
3351 | (0 != | ||
3352 | memcmp (&pg->peers[connection->index].daemon->id, peer, | ||
3353 | sizeof (struct GNUNET_PeerIdentity)))) | ||
3354 | { | ||
3355 | connection = connection->next; | ||
3356 | } | ||
3357 | |||
3358 | if (connection == NULL) | ||
3359 | { | ||
3360 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3361 | "Connected peer %s to %s, not in list (no problem(?))\n", | ||
3362 | GNUNET_i2s (peer), send_hello_context->peer->daemon->shortname); | ||
3363 | } | ||
3364 | else | ||
3365 | { | ||
3366 | #if BAD | ||
3367 | other_peer = &pg->peers[connection->index]; | ||
3368 | #endif | ||
3369 | if (pg->notify_connection != NULL) | ||
3370 | { | ||
3371 | pg->notify_connection (pg->notify_connection_cls, &send_hello_context->peer->daemon->id, peer, 0, /* FIXME */ | ||
3372 | send_hello_context->peer->daemon->cfg, | ||
3373 | pg->peers[connection->index].daemon->cfg, | ||
3374 | send_hello_context->peer->daemon, | ||
3375 | pg->peers[connection->index].daemon, NULL); | ||
3376 | } | ||
3377 | GNUNET_CONTAINER_DLL_remove (send_hello_context->peer->connect_peers_head, | ||
3378 | send_hello_context->peer->connect_peers_tail, | ||
3379 | connection); | ||
3380 | GNUNET_free (connection); | ||
3381 | } | ||
3382 | |||
3383 | #if BAD | ||
3384 | /* Notify of reverse connection and remove from other peers list of outstanding */ | ||
3385 | if (other_peer != NULL) | ||
3386 | { | ||
3387 | connection = other_peer->connect_peers_head; | ||
3388 | while ((connection != NULL) && | ||
3389 | (0 != | ||
3390 | memcmp (&send_hello_context->peer->daemon->id, | ||
3391 | &pg->peers[connection->index].daemon->id, | ||
3392 | sizeof (struct GNUNET_PeerIdentity)))) | ||
3393 | { | ||
3394 | connection = connection->next; | ||
3395 | } | ||
3396 | if (connection != NULL) | ||
3397 | { | ||
3398 | if (pg->notify_connection != NULL) | ||
3399 | { | ||
3400 | pg->notify_connection (pg->notify_connection_cls, peer, &send_hello_context->peer->daemon->id, 0, /* FIXME */ | ||
3401 | pg->peers[connection->index].daemon->cfg, | ||
3402 | send_hello_context->peer->daemon->cfg, | ||
3403 | pg->peers[connection->index].daemon, | ||
3404 | send_hello_context->peer->daemon, NULL); | ||
3405 | } | ||
3406 | |||
3407 | GNUNET_CONTAINER_DLL_remove (other_peer->connect_peers_head, | ||
3408 | other_peer->connect_peers_tail, connection); | ||
3409 | GNUNET_free (connection); | ||
3410 | } | ||
3411 | } | ||
3412 | #endif | ||
3413 | |||
3414 | if (send_hello_context->peer->connect_peers_head == NULL) | ||
3415 | { | ||
3416 | GNUNET_SCHEDULER_add_now (&free_hello_context, send_hello_context); | ||
3417 | } | ||
3418 | } | ||
3419 | |||
3420 | /** | ||
3421 | * Notify of a successful connection to the core service. | ||
3422 | * | ||
3423 | * @param cls a struct SendHelloContext * | ||
3424 | * @param server handle to the core service | ||
3425 | * @param my_identity the peer identity of this peer | ||
3426 | */ | ||
3427 | void | ||
3428 | core_init (void *cls, struct GNUNET_CORE_Handle *server, | ||
3429 | struct GNUNET_PeerIdentity *my_identity) | ||
3430 | { | ||
3431 | struct SendHelloContext *send_hello_context = cls; | ||
3432 | |||
3433 | send_hello_context->core_ready = GNUNET_YES; | ||
3434 | } | ||
3435 | |||
3436 | /** | ||
3437 | * Function called once a hello has been sent | ||
3438 | * to the transport, move on to the next one | ||
3439 | * or go away forever. | ||
3440 | * | ||
3441 | * @param cls the 'struct SendHelloContext *' | ||
3442 | * @param tc scheduler context | ||
3443 | */ | ||
3444 | static void | ||
3445 | hello_sent_callback (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3446 | { | ||
3447 | struct SendHelloContext *send_hello_context = cls; | ||
3448 | |||
3449 | //unsigned int pg_iter; | ||
3450 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
3451 | { | ||
3452 | GNUNET_free (send_hello_context); | ||
3453 | return; | ||
3454 | } | ||
3455 | |||
3456 | send_hello_context->pg->remaining_hellos--; | ||
3457 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent HELLO, have %d remaining!\n", | ||
3458 | send_hello_context->pg->remaining_hellos); | ||
3459 | if (send_hello_context->peer_pos == NULL) /* All HELLOs (for this peer!) have been transmitted! */ | ||
3460 | { | ||
3461 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3462 | "All hellos for this peer sent, disconnecting transport!\n"); | ||
3463 | GNUNET_assert (send_hello_context->peer->daemon->th != NULL); | ||
3464 | GNUNET_TRANSPORT_disconnect (send_hello_context->peer->daemon->th); | ||
3465 | send_hello_context->peer->daemon->th = NULL; | ||
3466 | GNUNET_assert (send_hello_context->peer->daemon->server == NULL); | ||
3467 | send_hello_context->peer->daemon->server = | ||
3468 | GNUNET_CORE_connect (send_hello_context->peer->cfg, 1, | ||
3469 | send_hello_context, &core_init, | ||
3470 | &core_connect_notify, NULL, NULL, NULL, GNUNET_NO, | ||
3471 | NULL, GNUNET_NO, no_handlers); | ||
3472 | |||
3473 | send_hello_context->core_connect_task = | ||
3474 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide | ||
3475 | (send_hello_context->pg-> | ||
3476 | ct_ctx.connect_timeout, | ||
3477 | send_hello_context->pg-> | ||
3478 | ct_ctx.connect_attempts), | ||
3479 | &send_core_connect_requests, | ||
3480 | send_hello_context); | ||
3481 | } | ||
3482 | else | ||
3483 | GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); | ||
3484 | } | ||
3485 | |||
3486 | /** | ||
3487 | * Connect to a peer, give it all the HELLO's of those peers | ||
3488 | * we will later ask it to connect to. | ||
3489 | * | ||
3490 | * @param ct_ctx the overall connection context | ||
3491 | */ | ||
3492 | static void | ||
3493 | schedule_send_hellos (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3494 | { | ||
3495 | struct SendHelloContext *send_hello_context = cls; | ||
3496 | struct GNUNET_TESTING_PeerGroup *pg = send_hello_context->pg; | ||
3497 | |||
3498 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
3499 | { | ||
3500 | GNUNET_free (send_hello_context); | ||
3501 | return; | ||
3502 | } | ||
3503 | |||
3504 | GNUNET_assert (send_hello_context->peer_pos != NULL); /* All of the HELLO sends to be scheduled have been scheduled! */ | ||
3505 | |||
3506 | if (((send_hello_context->peer->daemon->th == NULL) && | ||
3507 | (pg->outstanding_connects > pg->max_outstanding_connections)) || | ||
3508 | (pg->stop_connects == GNUNET_YES)) | ||
3509 | { | ||
3510 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3511 | "Delaying connect, we have too many outstanding connections!\n"); | ||
3512 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
3513 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
3514 | &schedule_send_hellos, send_hello_context); | ||
3515 | } | ||
3516 | else | ||
3517 | { | ||
3518 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3519 | "Creating connection, outstanding_connections is %d\n", | ||
3520 | outstanding_connects); | ||
3521 | if (send_hello_context->peer->daemon->th == NULL) | ||
3522 | { | ||
3523 | pg->outstanding_connects++; /* Actual TRANSPORT, CORE connections! */ | ||
3524 | send_hello_context->peer->daemon->th = | ||
3525 | GNUNET_TRANSPORT_connect (send_hello_context->peer->cfg, NULL, | ||
3526 | send_hello_context, NULL, NULL, NULL); | ||
3527 | } | ||
3528 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3529 | "Offering HELLO of peer %s to peer %s\n", | ||
3530 | send_hello_context->peer->daemon->shortname, | ||
3531 | pg->peers[send_hello_context->peer_pos->index]. | ||
3532 | daemon->shortname); | ||
3533 | GNUNET_TRANSPORT_offer_hello (send_hello_context->peer->daemon->th, | ||
3534 | (const struct GNUNET_MessageHeader *) | ||
3535 | pg->peers[send_hello_context->peer_pos-> | ||
3536 | index].daemon->hello, | ||
3537 | &hello_sent_callback, send_hello_context); | ||
3538 | send_hello_context->peer_pos = send_hello_context->peer_pos->next; | ||
3539 | GNUNET_assert (send_hello_context->peer->daemon->th != NULL); | ||
3540 | } | ||
3541 | } | ||
3542 | #endif | ||
3543 | |||
3544 | /** | ||
3545 | * Internal notification of a connection, kept so that we can ensure some connections | ||
3546 | * happen instead of flooding all testing daemons with requests to connect. | ||
3547 | */ | ||
3548 | static void | ||
3549 | internal_connect_notify (void *cls, const struct GNUNET_PeerIdentity *first, | ||
3550 | const struct GNUNET_PeerIdentity *second, | ||
3551 | uint32_t distance, | ||
3552 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
3553 | const struct GNUNET_CONFIGURATION_Handle *second_cfg, | ||
3554 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
3555 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
3556 | const char *emsg) | ||
3557 | { | ||
3558 | struct ConnectContext *connect_ctx = cls; | ||
3559 | struct ConnectTopologyContext *ct_ctx = connect_ctx->ct_ctx; | ||
3560 | struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; | ||
3561 | struct PeerConnection *connection; | ||
3562 | |||
3563 | GNUNET_assert (NULL != connect_ctx->cc); | ||
3564 | connect_ctx->cc = NULL; | ||
3565 | GNUNET_assert (0 < pg->outstanding_connects); | ||
3566 | pg->outstanding_connects--; | ||
3567 | GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, connect_ctx); | ||
3568 | /* | ||
3569 | * Check whether the inverse connection has been scheduled yet, | ||
3570 | * if not, we can remove it from the other peers list and avoid | ||
3571 | * even trying to connect them again! | ||
3572 | */ | ||
3573 | connection = pg->peers[connect_ctx->second_index].connect_peers_head; | ||
3574 | #if BAD | ||
3575 | other_peer = NULL; | ||
3576 | #endif | ||
3577 | |||
3578 | while ((connection != NULL) && | ||
3579 | (0 != | ||
3580 | memcmp (first, &pg->peers[connection->index].daemon->id, | ||
3581 | sizeof (struct GNUNET_PeerIdentity)))) | ||
3582 | connection = connection->next; | ||
3583 | |||
3584 | if (connection != NULL) /* Can safely remove! */ | ||
3585 | { | ||
3586 | GNUNET_assert (0 < ct_ctx->remaining_connections); | ||
3587 | ct_ctx->remaining_connections--; | ||
3588 | if (pg->notify_connection != NULL) /* Notify of reverse connection */ | ||
3589 | pg->notify_connection (pg->notify_connection_cls, second, first, distance, | ||
3590 | second_cfg, first_cfg, second_daemon, first_daemon, | ||
3591 | emsg); | ||
3592 | |||
3593 | GNUNET_CONTAINER_DLL_remove (pg-> | ||
3594 | peers[connect_ctx-> | ||
3595 | second_index].connect_peers_head, | ||
3596 | pg->peers[connect_ctx-> | ||
3597 | second_index].connect_peers_tail, | ||
3598 | connection); | ||
3599 | GNUNET_free (connection); | ||
3600 | } | ||
3601 | |||
3602 | if (ct_ctx->remaining_connections == 0) | ||
3603 | { | ||
3604 | if (ct_ctx->notify_connections_done != NULL) | ||
3605 | { | ||
3606 | ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); | ||
3607 | ct_ctx->notify_connections_done = NULL; | ||
3608 | } | ||
3609 | } | ||
3610 | else | ||
3611 | preschedule_connect (pg); | ||
3612 | |||
3613 | if (pg->notify_connection != NULL) | ||
3614 | pg->notify_connection (pg->notify_connection_cls, first, second, distance, | ||
3615 | first_cfg, second_cfg, first_daemon, second_daemon, | ||
3616 | emsg); | ||
3617 | GNUNET_free (connect_ctx); | ||
3618 | } | ||
3619 | |||
3620 | /** | ||
3621 | * Either delay a connection (because there are too many outstanding) | ||
3622 | * or schedule it for right now. | ||
3623 | * | ||
3624 | * @param cls a connection context | ||
3625 | * @param tc the task runtime context | ||
3626 | */ | ||
3627 | static void | ||
3628 | schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
3629 | { | ||
3630 | struct ConnectContext *connect_context = cls; | ||
3631 | struct GNUNET_TESTING_PeerGroup *pg = connect_context->ct_ctx->pg; | ||
3632 | |||
3633 | connect_context->task = GNUNET_SCHEDULER_NO_TASK; | ||
3634 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
3635 | return; | ||
3636 | |||
3637 | if ((pg->outstanding_connects > pg->max_outstanding_connections) || | ||
3638 | (pg->stop_connects == GNUNET_YES)) | ||
3639 | { | ||
3640 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3641 | "Delaying connect, we have too many outstanding connections!\n"); | ||
3642 | connect_context->task = | ||
3643 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
3644 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
3645 | &schedule_connect, connect_context); | ||
3646 | return; | ||
3647 | } | ||
3648 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3649 | "Creating connection, outstanding_connections is %d (max %d)\n", | ||
3650 | pg->outstanding_connects, pg->max_outstanding_connections); | ||
3651 | pg->outstanding_connects++; | ||
3652 | pg->total_connects_scheduled++; | ||
3653 | GNUNET_assert (NULL == connect_context->cc); | ||
3654 | connect_context->cc = | ||
3655 | GNUNET_TESTING_daemons_connect (pg-> | ||
3656 | peers[connect_context-> | ||
3657 | first_index].daemon, | ||
3658 | pg->peers[connect_context-> | ||
3659 | second_index].daemon, | ||
3660 | connect_context->ct_ctx->connect_timeout, | ||
3661 | connect_context->ct_ctx->connect_attempts, | ||
3662 | #if USE_SEND_HELLOS | ||
3663 | GNUNET_NO, | ||
3664 | #else | ||
3665 | GNUNET_YES, | ||
3666 | #endif | ||
3667 | &internal_connect_notify, | ||
3668 | connect_context); | ||
3669 | |||
3670 | } | ||
3671 | |||
3672 | #if !OLD | ||
3673 | /** | ||
3674 | * Iterator for actually scheduling connections to be created | ||
3675 | * between two peers. | ||
3676 | * | ||
3677 | * @param cls closure, a GNUNET_TESTING_Daemon | ||
3678 | * @param key the key the second Daemon was stored under | ||
3679 | * @param value the GNUNET_TESTING_Daemon that the first is to connect to | ||
3680 | * | ||
3681 | * @return GNUNET_YES to continue iteration | ||
3682 | */ | ||
3683 | static int | ||
3684 | connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
3685 | { | ||
3686 | struct ConnectTopologyContext *ct_ctx = cls; | ||
3687 | struct PeerData *first = ct_ctx->first; | ||
3688 | struct GNUNET_TESTING_Daemon *second = value; | ||
3689 | struct ConnectContext *connect_context; | ||
3690 | |||
3691 | connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); | ||
3692 | connect_context->first = first->daemon; | ||
3693 | connect_context->second = second; | ||
3694 | connect_context->ct_ctx = ct_ctx; | ||
3695 | connect_context->task = | ||
3696 | GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); | ||
3697 | GNUNET_CONTAINER_DLL_insert (ct_ctx->pg->cc_head, ct_ctx->pg->cc_tail, | ||
3698 | connect_context); | ||
3699 | return GNUNET_YES; | ||
3700 | } | ||
3701 | #endif | ||
3702 | |||
3703 | #if !OLD | ||
3704 | /** | ||
3705 | * Iterator for copying all entries in the allowed hashmap to the | ||
3706 | * connect hashmap. | ||
3707 | * | ||
3708 | * @param cls closure, a GNUNET_TESTING_Daemon | ||
3709 | * @param key the key the second Daemon was stored under | ||
3710 | * @param value the GNUNET_TESTING_Daemon that the first is to connect to | ||
3711 | * | ||
3712 | * @return GNUNET_YES to continue iteration | ||
3713 | */ | ||
3714 | static int | ||
3715 | copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
3716 | { | ||
3717 | struct PeerData *first = cls; | ||
3718 | |||
3719 | GNUNET_assert (GNUNET_OK == | ||
3720 | GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key, | ||
3721 | value, | ||
3722 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
3723 | |||
3724 | return GNUNET_YES; | ||
3725 | } | ||
3726 | #endif | ||
3727 | |||
3728 | /** | ||
3729 | * Make the peers to connect the same as those that are allowed to be | ||
3730 | * connected. | ||
3731 | * | ||
3732 | * @param pg the peer group | ||
3733 | */ | ||
3734 | static int | ||
3735 | copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg) | ||
3736 | { | ||
3737 | unsigned int pg_iter; | ||
3738 | int ret; | ||
3739 | int total; | ||
3740 | |||
3741 | #if OLD | ||
3742 | struct PeerConnection *iter; | ||
3743 | #endif | ||
3744 | total = 0; | ||
3745 | ret = 0; | ||
3746 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
3747 | { | ||
3748 | #if OLD | ||
3749 | iter = pg->peers[pg_iter].allowed_peers_head; | ||
3750 | while (iter != NULL) | ||
3751 | { | ||
3752 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3753 | "Creating connection between %d and %d\n", pg_iter, | ||
3754 | iter->index); | ||
3755 | total += add_connections (pg, pg_iter, iter->index, CONNECT, GNUNET_YES); | ||
3756 | //total += add_actual_connections(pg, pg_iter, iter->index); | ||
3757 | iter = iter->next; | ||
3758 | } | ||
3759 | #else | ||
3760 | ret = | ||
3761 | GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, | ||
3762 | ©_topology_iterator, | ||
3763 | &pg->peers[pg_iter]); | ||
3764 | #endif | ||
3765 | if (GNUNET_SYSERR == ret) | ||
3766 | return GNUNET_SYSERR; | ||
3767 | |||
3768 | total = total + ret; | ||
3769 | } | ||
3770 | |||
3771 | return total; | ||
3772 | } | ||
3773 | |||
3774 | /** | ||
3775 | * Connect the topology as specified by the PeerConnection's | ||
3776 | * of each peer in the peer group | ||
3777 | * | ||
3778 | * @param pg the peer group we are dealing with | ||
3779 | * @param connect_timeout how long try connecting two peers | ||
3780 | * @param connect_attempts how many times (max) to attempt | ||
3781 | * @param notify_callback callback to notify when finished | ||
3782 | * @param notify_cls closure for notify callback | ||
3783 | * | ||
3784 | * @return the number of connections that will be attempted | ||
3785 | */ | ||
3786 | static int | ||
3787 | connect_topology (struct GNUNET_TESTING_PeerGroup *pg, | ||
3788 | struct GNUNET_TIME_Relative connect_timeout, | ||
3789 | unsigned int connect_attempts, | ||
3790 | GNUNET_TESTING_NotifyCompletion notify_callback, | ||
3791 | void *notify_cls) | ||
3792 | { | ||
3793 | unsigned int pg_iter; | ||
3794 | unsigned int total; | ||
3795 | |||
3796 | #if OLD | ||
3797 | struct PeerConnection *connection_iter; | ||
3798 | #endif | ||
3799 | #if USE_SEND_HELLOS | ||
3800 | struct SendHelloContext *send_hello_context; | ||
3801 | #endif | ||
3802 | |||
3803 | total = 0; | ||
3804 | pg->ct_ctx.notify_connections_done = notify_callback; | ||
3805 | pg->ct_ctx.notify_cls = notify_cls; | ||
3806 | pg->ct_ctx.pg = pg; | ||
3807 | |||
3808 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
3809 | { | ||
3810 | #if OLD | ||
3811 | connection_iter = pg->peers[pg_iter].connect_peers_head; | ||
3812 | while (connection_iter != NULL) | ||
3813 | { | ||
3814 | connection_iter = connection_iter->next; | ||
3815 | total++; | ||
3816 | } | ||
3817 | #else | ||
3818 | total += | ||
3819 | GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers); | ||
3820 | #endif | ||
3821 | } | ||
3822 | |||
3823 | if (total == 0) | ||
3824 | return total; | ||
3825 | |||
3826 | pg->ct_ctx.connect_timeout = connect_timeout; | ||
3827 | pg->ct_ctx.connect_attempts = connect_attempts; | ||
3828 | pg->ct_ctx.remaining_connections = total; | ||
3829 | |||
3830 | #if USE_SEND_HELLOS | ||
3831 | /* First give all peers the HELLO's of other peers (connect to first peer's transport service, give HELLO's of other peers, continue...) */ | ||
3832 | pg->remaining_hellos = total; | ||
3833 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
3834 | { | ||
3835 | send_hello_context = GNUNET_malloc (sizeof (struct SendHelloContext)); | ||
3836 | send_hello_context->peer = &pg->peers[pg_iter]; | ||
3837 | send_hello_context->peer_pos = pg->peers[pg_iter].connect_peers_head; | ||
3838 | send_hello_context->pg = pg; | ||
3839 | GNUNET_SCHEDULER_add_now (&schedule_send_hellos, send_hello_context); | ||
3840 | } | ||
3841 | #else | ||
3842 | for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) | ||
3843 | { | ||
3844 | preschedule_connect (pg); | ||
3845 | } | ||
3846 | #endif | ||
3847 | return total; | ||
3848 | |||
3849 | } | ||
3850 | |||
3851 | /** | ||
3852 | * Takes a peer group and creates a topology based on the | ||
3853 | * one specified. Creates a topology means generates friend | ||
3854 | * files for the peers so they can only connect to those allowed | ||
3855 | * by the topology. This will only have an effect once peers | ||
3856 | * are started if the FRIENDS_ONLY option is set in the base | ||
3857 | * config. Also takes an optional restrict topology which | ||
3858 | * disallows connections based on particular transports | ||
3859 | * UNLESS they are specified in the restricted topology. | ||
3860 | * | ||
3861 | * @param pg the peer group struct representing the running peers | ||
3862 | * @param topology which topology to connect the peers in | ||
3863 | * @param restrict_topology disallow restrict_transports transport | ||
3864 | * connections to peers NOT in this topology | ||
3865 | * use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions | ||
3866 | * @param restrict_transports space delimited list of transports to blacklist | ||
3867 | * to create restricted topology | ||
3868 | * | ||
3869 | * @return the maximum number of connections were all allowed peers | ||
3870 | * connected to each other | ||
3871 | */ | ||
3872 | unsigned int | ||
3873 | GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, | ||
3874 | enum GNUNET_TESTING_Topology topology, | ||
3875 | enum GNUNET_TESTING_Topology restrict_topology, | ||
3876 | const char *restrict_transports) | ||
3877 | { | ||
3878 | int ret; | ||
3879 | |||
3880 | unsigned int num_connections; | ||
3881 | int unblacklisted_connections; | ||
3882 | char *filename; | ||
3883 | struct PeerConnection *conn_iter; | ||
3884 | struct PeerConnection *temp_conn; | ||
3885 | unsigned int off; | ||
3886 | |||
3887 | #if !OLD | ||
3888 | unsigned int i; | ||
3889 | |||
3890 | for (i = 0; i < pg->total; i++) | ||
3891 | { | ||
3892 | pg->peers[i].allowed_peers = GNUNET_CONTAINER_multihashmap_create (100); | ||
3893 | pg->peers[i].connect_peers = GNUNET_CONTAINER_multihashmap_create (100); | ||
3894 | pg->peers[i].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create (100); | ||
3895 | pg->peers[i].pg = pg; | ||
3896 | } | ||
3897 | #endif | ||
3898 | |||
3899 | switch (topology) | ||
3900 | { | ||
3901 | case GNUNET_TESTING_TOPOLOGY_CLIQUE: | ||
3902 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating clique topology\n"); | ||
3903 | num_connections = create_clique (pg, &add_connections, ALLOWED, GNUNET_NO); | ||
3904 | break; | ||
3905 | case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: | ||
3906 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3907 | "Creating small world (ring) topology\n"); | ||
3908 | num_connections = create_small_world_ring (pg, &add_connections, ALLOWED); | ||
3909 | break; | ||
3910 | case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: | ||
3911 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3912 | "Creating small world (2d-torus) topology\n"); | ||
3913 | num_connections = create_small_world (pg, &add_connections, ALLOWED); | ||
3914 | break; | ||
3915 | case GNUNET_TESTING_TOPOLOGY_RING: | ||
3916 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring topology\n"); | ||
3917 | num_connections = create_ring (pg, &add_connections, ALLOWED); | ||
3918 | break; | ||
3919 | case GNUNET_TESTING_TOPOLOGY_2D_TORUS: | ||
3920 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating 2d torus topology\n"); | ||
3921 | num_connections = create_2d_torus (pg, &add_connections, ALLOWED); | ||
3922 | break; | ||
3923 | case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: | ||
3924 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Erdos-Renyi topology\n"); | ||
3925 | num_connections = create_erdos_renyi (pg, &add_connections, ALLOWED); | ||
3926 | break; | ||
3927 | case GNUNET_TESTING_TOPOLOGY_INTERNAT: | ||
3928 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating InterNAT topology\n"); | ||
3929 | num_connections = create_nated_internet (pg, &add_connections, ALLOWED); | ||
3930 | break; | ||
3931 | case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: | ||
3932 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating Scale Free topology\n"); | ||
3933 | num_connections = create_scale_free (pg, &add_connections, ALLOWED); | ||
3934 | break; | ||
3935 | case GNUNET_TESTING_TOPOLOGY_LINE: | ||
3936 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3937 | "Creating straight line topology\n"); | ||
3938 | num_connections = create_line (pg, &add_connections, ALLOWED); | ||
3939 | break; | ||
3940 | case GNUNET_TESTING_TOPOLOGY_FROM_FILE: | ||
3941 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating topology from file!\n"); | ||
3942 | if (GNUNET_OK == | ||
3943 | GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing", | ||
3944 | "topology_file", &filename)) | ||
3945 | num_connections = | ||
3946 | create_from_file (pg, filename, &add_connections, ALLOWED); | ||
3947 | else | ||
3948 | { | ||
3949 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
3950 | "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!\n"); | ||
3951 | num_connections = 0; | ||
3952 | } | ||
3953 | break; | ||
3954 | case GNUNET_TESTING_TOPOLOGY_NONE: | ||
3955 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3956 | _ | ||
3957 | ("Creating no allowed topology (all peers can connect at core level)\n")); | ||
3958 | num_connections = pg->total * pg->total; /* Clique is allowed! */ | ||
3959 | break; | ||
3960 | default: | ||
3961 | num_connections = 0; | ||
3962 | break; | ||
3963 | } | ||
3964 | |||
3965 | if (GNUNET_YES == | ||
3966 | GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F")) | ||
3967 | { | ||
3968 | ret = create_and_copy_friend_files (pg); | ||
3969 | if (ret != GNUNET_OK) | ||
3970 | { | ||
3971 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3972 | "Failed during friend file copying!\n"); | ||
3973 | return GNUNET_SYSERR; | ||
3974 | } | ||
3975 | else | ||
3976 | { | ||
3977 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3978 | "Friend files created/copied successfully!\n"); | ||
3979 | } | ||
3980 | } | ||
3981 | |||
3982 | /* Use the create clique method to initially set all connections as blacklisted. */ | ||
3983 | if ((restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE) && | ||
3984 | (restrict_topology != GNUNET_TESTING_TOPOLOGY_FROM_FILE)) | ||
3985 | create_clique (pg, &add_connections, BLACKLIST, GNUNET_NO); | ||
3986 | else | ||
3987 | return num_connections; | ||
3988 | |||
3989 | unblacklisted_connections = 0; | ||
3990 | /* Un-blacklist connections as per the topology specified */ | ||
3991 | switch (restrict_topology) | ||
3992 | { | ||
3993 | case GNUNET_TESTING_TOPOLOGY_CLIQUE: | ||
3994 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3995 | "Blacklisting all but clique topology\n"); | ||
3996 | unblacklisted_connections = | ||
3997 | create_clique (pg, &remove_connections, BLACKLIST, GNUNET_NO); | ||
3998 | break; | ||
3999 | case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: | ||
4000 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4001 | "Blacklisting all but small world (ring) topology\n"); | ||
4002 | unblacklisted_connections = | ||
4003 | create_small_world_ring (pg, &remove_connections, BLACKLIST); | ||
4004 | break; | ||
4005 | case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: | ||
4006 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4007 | "Blacklisting all but small world (2d-torus) topology\n"); | ||
4008 | unblacklisted_connections = | ||
4009 | create_small_world (pg, &remove_connections, BLACKLIST); | ||
4010 | break; | ||
4011 | case GNUNET_TESTING_TOPOLOGY_RING: | ||
4012 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4013 | "Blacklisting all but ring topology\n"); | ||
4014 | unblacklisted_connections = | ||
4015 | create_ring (pg, &remove_connections, BLACKLIST); | ||
4016 | break; | ||
4017 | case GNUNET_TESTING_TOPOLOGY_2D_TORUS: | ||
4018 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4019 | "Blacklisting all but 2d torus topology\n"); | ||
4020 | unblacklisted_connections = | ||
4021 | create_2d_torus (pg, &remove_connections, BLACKLIST); | ||
4022 | break; | ||
4023 | case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: | ||
4024 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4025 | "Blacklisting all but Erdos-Renyi topology\n"); | ||
4026 | unblacklisted_connections = | ||
4027 | create_erdos_renyi (pg, &remove_connections, BLACKLIST); | ||
4028 | break; | ||
4029 | case GNUNET_TESTING_TOPOLOGY_INTERNAT: | ||
4030 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4031 | "Blacklisting all but InterNAT topology\n"); | ||
4032 | |||
4033 | #if TOPOLOGY_HACK | ||
4034 | for (off = 0; off < pg->total; off++) | ||
4035 | { | ||
4036 | conn_iter = pg->peers[off].allowed_peers_head; | ||
4037 | while (conn_iter != NULL) | ||
4038 | { | ||
4039 | temp_conn = conn_iter->next; | ||
4040 | GNUNET_free (conn_iter); | ||
4041 | conn_iter = temp_conn; | ||
4042 | } | ||
4043 | pg->peers[off].allowed_peers_head = NULL; | ||
4044 | pg->peers[off].allowed_peers_tail = NULL; | ||
4045 | |||
4046 | conn_iter = pg->peers[off].connect_peers_head; | ||
4047 | while (conn_iter != NULL) | ||
4048 | { | ||
4049 | temp_conn = conn_iter->next; | ||
4050 | GNUNET_free (conn_iter); | ||
4051 | conn_iter = temp_conn; | ||
4052 | } | ||
4053 | pg->peers[off].connect_peers_head = NULL; | ||
4054 | pg->peers[off].connect_peers_tail = NULL; | ||
4055 | } | ||
4056 | unblacklisted_connections = | ||
4057 | create_nated_internet_copy (pg, &remove_connections, BLACKLIST); | ||
4058 | #else | ||
4059 | unblacklisted_connections = | ||
4060 | create_nated_internet (pg, &remove_connections, BLACKLIST); | ||
4061 | #endif | ||
4062 | |||
4063 | break; | ||
4064 | case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: | ||
4065 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4066 | "Blacklisting all but Scale Free topology\n"); | ||
4067 | unblacklisted_connections = | ||
4068 | create_scale_free (pg, &remove_connections, BLACKLIST); | ||
4069 | break; | ||
4070 | case GNUNET_TESTING_TOPOLOGY_LINE: | ||
4071 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4072 | "Blacklisting all but straight line topology\n"); | ||
4073 | unblacklisted_connections = | ||
4074 | create_line (pg, &remove_connections, BLACKLIST); | ||
4075 | default: | ||
4076 | break; | ||
4077 | } | ||
4078 | |||
4079 | if ((unblacklisted_connections > 0) && (restrict_transports != NULL)) | ||
4080 | { | ||
4081 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating blacklist with `%s'\n", | ||
4082 | restrict_transports); | ||
4083 | ret = create_and_copy_blacklist_files (pg, restrict_transports); | ||
4084 | if (ret != GNUNET_OK) | ||
4085 | { | ||
4086 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4087 | "Failed during blacklist file copying!\n"); | ||
4088 | return 0; | ||
4089 | } | ||
4090 | else | ||
4091 | { | ||
4092 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4093 | "Blacklist files created/copied successfully!\n"); | ||
4094 | } | ||
4095 | } | ||
4096 | return num_connections; | ||
4097 | } | ||
4098 | |||
4099 | #if !OLD | ||
4100 | /** | ||
4101 | * Iterator for choosing random peers to connect. | ||
4102 | * | ||
4103 | * @param cls closure, a RandomContext | ||
4104 | * @param key the key the second Daemon was stored under | ||
4105 | * @param value the GNUNET_TESTING_Daemon that the first is to connect to | ||
4106 | * | ||
4107 | * @return GNUNET_YES to continue iteration | ||
4108 | */ | ||
4109 | static int | ||
4110 | random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
4111 | { | ||
4112 | struct RandomContext *random_ctx = cls; | ||
4113 | double random_number; | ||
4114 | uint32_t second_pos; | ||
4115 | GNUNET_HashCode first_hash; | ||
4116 | |||
4117 | random_number = | ||
4118 | ((double) | ||
4119 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
4120 | UINT64_MAX)) / ((double) UINT64_MAX); | ||
4121 | if (random_number < random_ctx->percentage) | ||
4122 | { | ||
4123 | GNUNET_assert (GNUNET_OK == | ||
4124 | GNUNET_CONTAINER_multihashmap_put (random_ctx-> | ||
4125 | first->connect_peers_working_set, | ||
4126 | key, value, | ||
4127 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
4128 | } | ||
4129 | |||
4130 | /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */ | ||
4131 | uid_from_hash (key, &second_pos); | ||
4132 | hash_from_uid (random_ctx->first_uid, &first_hash); | ||
4133 | GNUNET_assert (random_ctx->pg->total > second_pos); | ||
4134 | GNUNET_assert (GNUNET_YES == | ||
4135 | GNUNET_CONTAINER_multihashmap_remove (random_ctx-> | ||
4136 | pg->peers | ||
4137 | [second_pos].connect_peers, | ||
4138 | &first_hash, | ||
4139 | random_ctx-> | ||
4140 | first->daemon)); | ||
4141 | |||
4142 | return GNUNET_YES; | ||
4143 | } | ||
4144 | |||
4145 | /** | ||
4146 | * Iterator for adding at least X peers to a peers connection set. | ||
4147 | * | ||
4148 | * @param cls closure, MinimumContext | ||
4149 | * @param key the key the second Daemon was stored under | ||
4150 | * @param value the GNUNET_TESTING_Daemon that the first is to connect to | ||
4151 | * | ||
4152 | * @return GNUNET_YES to continue iteration | ||
4153 | */ | ||
4154 | static int | ||
4155 | minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
4156 | { | ||
4157 | struct MinimumContext *min_ctx = cls; | ||
4158 | uint32_t second_pos; | ||
4159 | GNUNET_HashCode first_hash; | ||
4160 | unsigned int i; | ||
4161 | |||
4162 | if (GNUNET_CONTAINER_multihashmap_size | ||
4163 | (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add) | ||
4164 | { | ||
4165 | for (i = 0; i < min_ctx->num_to_add; i++) | ||
4166 | { | ||
4167 | if (min_ctx->pg_array[i] == min_ctx->current) | ||
4168 | { | ||
4169 | GNUNET_assert (GNUNET_OK == | ||
4170 | GNUNET_CONTAINER_multihashmap_put (min_ctx-> | ||
4171 | first->connect_peers_working_set, | ||
4172 | key, value, | ||
4173 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
4174 | uid_from_hash (key, &second_pos); | ||
4175 | hash_from_uid (min_ctx->first_uid, &first_hash); | ||
4176 | GNUNET_assert (min_ctx->pg->total > second_pos); | ||
4177 | GNUNET_assert (GNUNET_OK == | ||
4178 | GNUNET_CONTAINER_multihashmap_put (min_ctx-> | ||
4179 | pg->peers | ||
4180 | [second_pos].connect_peers_working_set, | ||
4181 | &first_hash, | ||
4182 | min_ctx->first-> | ||
4183 | daemon, | ||
4184 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
4185 | /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */ | ||
4186 | GNUNET_assert (GNUNET_YES == | ||
4187 | GNUNET_CONTAINER_multihashmap_remove (min_ctx-> | ||
4188 | pg->peers | ||
4189 | [second_pos].connect_peers, | ||
4190 | &first_hash, | ||
4191 | min_ctx-> | ||
4192 | first->daemon)); | ||
4193 | } | ||
4194 | } | ||
4195 | min_ctx->current++; | ||
4196 | return GNUNET_YES; | ||
4197 | } | ||
4198 | else | ||
4199 | return GNUNET_NO; /* We can stop iterating, we have enough peers! */ | ||
4200 | |||
4201 | } | ||
4202 | |||
4203 | /** | ||
4204 | * Iterator for adding peers to a connection set based on a depth first search. | ||
4205 | * | ||
4206 | * @param cls closure, MinimumContext | ||
4207 | * @param key the key the second daemon was stored under | ||
4208 | * @param value the GNUNET_TESTING_Daemon that the first is to connect to | ||
4209 | * | ||
4210 | * @return GNUNET_YES to continue iteration | ||
4211 | */ | ||
4212 | static int | ||
4213 | dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value) | ||
4214 | { | ||
4215 | struct DFSContext *dfs_ctx = cls; | ||
4216 | GNUNET_HashCode first_hash; | ||
4217 | |||
4218 | if (dfs_ctx->current == dfs_ctx->chosen) | ||
4219 | { | ||
4220 | GNUNET_assert (GNUNET_OK == | ||
4221 | GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> | ||
4222 | first->connect_peers_working_set, | ||
4223 | key, value, | ||
4224 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
4225 | uid_from_hash (key, &dfs_ctx->second_uid); | ||
4226 | hash_from_uid (dfs_ctx->first_uid, &first_hash); | ||
4227 | GNUNET_assert (GNUNET_OK == | ||
4228 | GNUNET_CONTAINER_multihashmap_put (dfs_ctx-> | ||
4229 | pg->peers[dfs_ctx-> | ||
4230 | second_uid].connect_peers_working_set, | ||
4231 | &first_hash, | ||
4232 | dfs_ctx->first->daemon, | ||
4233 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
4234 | GNUNET_assert (GNUNET_YES == | ||
4235 | GNUNET_CONTAINER_multihashmap_remove (dfs_ctx-> | ||
4236 | pg->peers | ||
4237 | [dfs_ctx->second_uid].connect_peers, | ||
4238 | &first_hash, | ||
4239 | dfs_ctx-> | ||
4240 | first->daemon)); | ||
4241 | /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */ | ||
4242 | return GNUNET_NO; /* We have found our peer, don't iterate more */ | ||
4243 | } | ||
4244 | |||
4245 | dfs_ctx->current++; | ||
4246 | return GNUNET_YES; | ||
4247 | } | ||
4248 | #endif | ||
4249 | |||
4250 | /** | ||
4251 | * From the set of connections possible, choose percentage percent of connections | ||
4252 | * to actually connect. | ||
4253 | * | ||
4254 | * @param pg the peergroup we are dealing with | ||
4255 | * @param percentage what percent of total connections to make | ||
4256 | */ | ||
4257 | void | ||
4258 | choose_random_connections (struct GNUNET_TESTING_PeerGroup *pg, | ||
4259 | double percentage) | ||
4260 | { | ||
4261 | uint32_t pg_iter; | ||
4262 | |||
4263 | #if OLD | ||
4264 | struct PeerConnection *conn_iter; | ||
4265 | double random_number; | ||
4266 | #else | ||
4267 | struct RandomContext random_ctx; | ||
4268 | #endif | ||
4269 | |||
4270 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4271 | { | ||
4272 | #if OLD | ||
4273 | conn_iter = pg->peers[pg_iter].connect_peers_head; | ||
4274 | while (conn_iter != NULL) | ||
4275 | { | ||
4276 | random_number = | ||
4277 | ((double) | ||
4278 | GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
4279 | UINT64_MAX)) / ((double) UINT64_MAX); | ||
4280 | if (random_number < percentage) | ||
4281 | { | ||
4282 | add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, | ||
4283 | GNUNET_YES); | ||
4284 | } | ||
4285 | conn_iter = conn_iter->next; | ||
4286 | } | ||
4287 | #else | ||
4288 | random_ctx.first_uid = pg_iter; | ||
4289 | random_ctx.first = &pg->peers[pg_iter]; | ||
4290 | random_ctx.percentage = percentage; | ||
4291 | random_ctx.pg = pg; | ||
4292 | pg->peers[pg_iter].connect_peers_working_set = | ||
4293 | GNUNET_CONTAINER_multihashmap_create (pg->total); | ||
4294 | GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, | ||
4295 | &random_connect_iterator, | ||
4296 | &random_ctx); | ||
4297 | /* Now remove the old connections */ | ||
4298 | GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); | ||
4299 | /* And replace with the random set */ | ||
4300 | pg->peers[pg_iter].connect_peers = | ||
4301 | pg->peers[pg_iter].connect_peers_working_set; | ||
4302 | #endif | ||
4303 | } | ||
4304 | |||
4305 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4306 | { | ||
4307 | conn_iter = pg->peers[pg_iter].connect_peers_head; | ||
4308 | while (pg->peers[pg_iter].connect_peers_head != NULL) | ||
4309 | remove_connections (pg, pg_iter, | ||
4310 | pg->peers[pg_iter].connect_peers_head->index, CONNECT, | ||
4311 | GNUNET_YES); | ||
4312 | |||
4313 | pg->peers[pg_iter].connect_peers_head = | ||
4314 | pg->peers[pg_iter].connect_peers_working_set_head; | ||
4315 | pg->peers[pg_iter].connect_peers_tail = | ||
4316 | pg->peers[pg_iter].connect_peers_working_set_tail; | ||
4317 | pg->peers[pg_iter].connect_peers_working_set_head = NULL; | ||
4318 | pg->peers[pg_iter].connect_peers_working_set_tail = NULL; | ||
4319 | } | ||
4320 | } | ||
4321 | |||
4322 | /** | ||
4323 | * Count the number of connections in a linked list of connections. | ||
4324 | * | ||
4325 | * @param conn_list the connection list to get the count of | ||
4326 | * | ||
4327 | * @return the number of elements in the list | ||
4328 | */ | ||
4329 | static unsigned int | ||
4330 | count_connections (struct PeerConnection *conn_list) | ||
4331 | { | ||
4332 | struct PeerConnection *iter; | ||
4333 | unsigned int count; | ||
4334 | |||
4335 | count = 0; | ||
4336 | iter = conn_list; | ||
4337 | while (iter != NULL) | ||
4338 | { | ||
4339 | iter = iter->next; | ||
4340 | count++; | ||
4341 | } | ||
4342 | return count; | ||
4343 | } | ||
4344 | |||
4345 | static unsigned int | ||
4346 | count_workingset_connections (struct GNUNET_TESTING_PeerGroup *pg) | ||
4347 | { | ||
4348 | unsigned int count; | ||
4349 | unsigned int pg_iter; | ||
4350 | |||
4351 | #if OLD | ||
4352 | struct PeerConnection *conn_iter; | ||
4353 | #endif | ||
4354 | count = 0; | ||
4355 | |||
4356 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4357 | { | ||
4358 | #if OLD | ||
4359 | conn_iter = pg->peers[pg_iter].connect_peers_working_set_head; | ||
4360 | while (conn_iter != NULL) | ||
4361 | { | ||
4362 | count++; | ||
4363 | conn_iter = conn_iter->next; | ||
4364 | } | ||
4365 | #else | ||
4366 | count += | ||
4367 | GNUNET_CONTAINER_multihashmap_size (pg-> | ||
4368 | peers | ||
4369 | [pg_iter].connect_peers_working_set); | ||
4370 | #endif | ||
4371 | } | ||
4372 | |||
4373 | return count; | ||
4374 | } | ||
4375 | |||
4376 | static unsigned int | ||
4377 | count_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg) | ||
4378 | { | ||
4379 | unsigned int count; | ||
4380 | unsigned int pg_iter; | ||
4381 | |||
4382 | #if OLD | ||
4383 | struct PeerConnection *conn_iter; | ||
4384 | #endif | ||
4385 | |||
4386 | count = 0; | ||
4387 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4388 | { | ||
4389 | #if OLD | ||
4390 | conn_iter = pg->peers[pg_iter].allowed_peers_head; | ||
4391 | while (conn_iter != NULL) | ||
4392 | { | ||
4393 | count++; | ||
4394 | conn_iter = conn_iter->next; | ||
4395 | } | ||
4396 | #else | ||
4397 | count += | ||
4398 | GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].allowed_peers); | ||
4399 | #endif | ||
4400 | } | ||
4401 | |||
4402 | return count; | ||
4403 | } | ||
4404 | |||
4405 | /** | ||
4406 | * From the set of connections possible, choose at least num connections per | ||
4407 | * peer. | ||
4408 | * | ||
4409 | * @param pg the peergroup we are dealing with | ||
4410 | * @param num how many connections at least should each peer have (if possible)? | ||
4411 | */ | ||
4412 | static void | ||
4413 | choose_minimum (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) | ||
4414 | { | ||
4415 | #if !OLD | ||
4416 | struct MinimumContext minimum_ctx; | ||
4417 | #else | ||
4418 | struct PeerConnection *conn_iter; | ||
4419 | unsigned int temp_list_size; | ||
4420 | unsigned int i; | ||
4421 | unsigned int count; | ||
4422 | uint32_t random; /* Random list entry to connect peer to */ | ||
4423 | #endif | ||
4424 | uint32_t pg_iter; | ||
4425 | |||
4426 | #if OLD | ||
4427 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4428 | { | ||
4429 | temp_list_size = count_connections (pg->peers[pg_iter].connect_peers_head); | ||
4430 | if (temp_list_size == 0) | ||
4431 | { | ||
4432 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Peer %d has 0 connections!?!?\n", | ||
4433 | pg_iter); | ||
4434 | break; | ||
4435 | } | ||
4436 | for (i = 0; i < num; i++) | ||
4437 | { | ||
4438 | random = | ||
4439 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_list_size); | ||
4440 | conn_iter = pg->peers[pg_iter].connect_peers_head; | ||
4441 | for (count = 0; count < random; count++) | ||
4442 | conn_iter = conn_iter->next; | ||
4443 | /* We now have a random connection, connect it! */ | ||
4444 | GNUNET_assert (conn_iter != NULL); | ||
4445 | add_connections (pg, pg_iter, conn_iter->index, WORKING_SET, GNUNET_YES); | ||
4446 | } | ||
4447 | } | ||
4448 | #else | ||
4449 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4450 | { | ||
4451 | pg->peers[pg_iter].connect_peers_working_set = | ||
4452 | GNUNET_CONTAINER_multihashmap_create (num); | ||
4453 | } | ||
4454 | |||
4455 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4456 | { | ||
4457 | minimum_ctx.first_uid = pg_iter; | ||
4458 | minimum_ctx.pg_array = | ||
4459 | GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, | ||
4460 | GNUNET_CONTAINER_multihashmap_size | ||
4461 | (pg->peers[pg_iter].connect_peers)); | ||
4462 | minimum_ctx.first = &pg->peers[pg_iter]; | ||
4463 | minimum_ctx.pg = pg; | ||
4464 | minimum_ctx.num_to_add = num; | ||
4465 | minimum_ctx.current = 0; | ||
4466 | GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers, | ||
4467 | &minimum_connect_iterator, | ||
4468 | &minimum_ctx); | ||
4469 | } | ||
4470 | |||
4471 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4472 | { | ||
4473 | /* Remove the "old" connections */ | ||
4474 | GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); | ||
4475 | /* And replace with the working set */ | ||
4476 | pg->peers[pg_iter].connect_peers = | ||
4477 | pg->peers[pg_iter].connect_peers_working_set; | ||
4478 | } | ||
4479 | #endif | ||
4480 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4481 | { | ||
4482 | while (pg->peers[pg_iter].connect_peers_head != NULL) | ||
4483 | { | ||
4484 | conn_iter = pg->peers[pg_iter].connect_peers_head; | ||
4485 | GNUNET_CONTAINER_DLL_remove (pg->peers[pg_iter].connect_peers_head, | ||
4486 | pg->peers[pg_iter].connect_peers_tail, | ||
4487 | conn_iter); | ||
4488 | GNUNET_free (conn_iter); | ||
4489 | /*remove_connections(pg, pg_iter, pg->peers[pg_iter].connect_peers_head->index, CONNECT, GNUNET_YES); */ | ||
4490 | } | ||
4491 | |||
4492 | pg->peers[pg_iter].connect_peers_head = | ||
4493 | pg->peers[pg_iter].connect_peers_working_set_head; | ||
4494 | pg->peers[pg_iter].connect_peers_tail = | ||
4495 | pg->peers[pg_iter].connect_peers_working_set_tail; | ||
4496 | pg->peers[pg_iter].connect_peers_working_set_head = NULL; | ||
4497 | pg->peers[pg_iter].connect_peers_working_set_tail = NULL; | ||
4498 | } | ||
4499 | } | ||
4500 | |||
4501 | #if !OLD | ||
4502 | struct FindClosestContext | ||
4503 | { | ||
4504 | /** | ||
4505 | * The currently known closest peer. | ||
4506 | */ | ||
4507 | struct GNUNET_TESTING_Daemon *closest; | ||
4508 | |||
4509 | /** | ||
4510 | * The info for the peer we are adding connections for. | ||
4511 | */ | ||
4512 | struct PeerData *curr_peer; | ||
4513 | |||
4514 | /** | ||
4515 | * The distance (bits) between the current | ||
4516 | * peer and the currently known closest. | ||
4517 | */ | ||
4518 | unsigned int closest_dist; | ||
4519 | |||
4520 | /** | ||
4521 | * The offset of the closest known peer in | ||
4522 | * the peer group. | ||
4523 | */ | ||
4524 | unsigned int closest_num; | ||
4525 | }; | ||
4526 | |||
4527 | /** | ||
4528 | * Iterator over hash map entries of the allowed | ||
4529 | * peer connections. Find the closest, not already | ||
4530 | * connected peer and return it. | ||
4531 | * | ||
4532 | * @param cls closure (struct FindClosestContext) | ||
4533 | * @param key current key code (hash of offset in pg) | ||
4534 | * @param value value in the hash map - a GNUNET_TESTING_Daemon | ||
4535 | * @return GNUNET_YES if we should continue to | ||
4536 | * iterate, | ||
4537 | * GNUNET_NO if not. | ||
4538 | */ | ||
4539 | static int | ||
4540 | find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value) | ||
4541 | { | ||
4542 | struct FindClosestContext *closest_ctx = cls; | ||
4543 | struct GNUNET_TESTING_Daemon *daemon = value; | ||
4544 | |||
4545 | if (((closest_ctx->closest == NULL) || | ||
4546 | (GNUNET_CRYPTO_hash_matching_bits | ||
4547 | (&daemon->id.hashPubKey, | ||
4548 | &closest_ctx->curr_peer->daemon->id.hashPubKey) > | ||
4549 | closest_ctx->closest_dist)) && | ||
4550 | (GNUNET_YES != | ||
4551 | GNUNET_CONTAINER_multihashmap_contains (closest_ctx-> | ||
4552 | curr_peer->connect_peers, key))) | ||
4553 | { | ||
4554 | closest_ctx->closest_dist = | ||
4555 | GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey, | ||
4556 | &closest_ctx->curr_peer->daemon-> | ||
4557 | id.hashPubKey); | ||
4558 | closest_ctx->closest = daemon; | ||
4559 | uid_from_hash (key, &closest_ctx->closest_num); | ||
4560 | } | ||
4561 | return GNUNET_YES; | ||
4562 | } | ||
4563 | |||
4564 | /** | ||
4565 | * From the set of connections possible, choose at num connections per | ||
4566 | * peer based on depth which are closest out of those allowed. Guaranteed | ||
4567 | * to add num peers to connect to, provided there are that many peers | ||
4568 | * in the underlay topology to connect to. | ||
4569 | * | ||
4570 | * @param pg the peergroup we are dealing with | ||
4571 | * @param num how many connections at least should each peer have (if possible)? | ||
4572 | * @param proc processor to actually add the connections | ||
4573 | * @param list the peer list to use | ||
4574 | */ | ||
4575 | void | ||
4576 | add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num, | ||
4577 | GNUNET_TESTING_ConnectionProcessor proc, enum PeerLists list) | ||
4578 | { | ||
4579 | #if OLD | ||
4580 | |||
4581 | #else | ||
4582 | struct FindClosestContext closest_ctx; | ||
4583 | #endif | ||
4584 | uint32_t pg_iter; | ||
4585 | uint32_t i; | ||
4586 | |||
4587 | for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */ | ||
4588 | { | ||
4589 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4590 | { | ||
4591 | closest_ctx.curr_peer = &pg->peers[pg_iter]; | ||
4592 | closest_ctx.closest = NULL; | ||
4593 | closest_ctx.closest_dist = 0; | ||
4594 | closest_ctx.closest_num = 0; | ||
4595 | GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers, | ||
4596 | &find_closest_peers, &closest_ctx); | ||
4597 | if (closest_ctx.closest != NULL) | ||
4598 | { | ||
4599 | GNUNET_assert (closest_ctx.closest_num < pg->total); | ||
4600 | proc (pg, pg_iter, closest_ctx.closest_num, list); | ||
4601 | } | ||
4602 | } | ||
4603 | } | ||
4604 | } | ||
4605 | #endif | ||
4606 | |||
4607 | /** | ||
4608 | * From the set of connections possible, choose at least num connections per | ||
4609 | * peer based on depth first traversal of peer connections. If DFS leaves | ||
4610 | * peers unconnected, ensure those peers get connections. | ||
4611 | * | ||
4612 | * @param pg the peergroup we are dealing with | ||
4613 | * @param num how many connections at least should each peer have (if possible)? | ||
4614 | */ | ||
4615 | void | ||
4616 | perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num) | ||
4617 | { | ||
4618 | uint32_t pg_iter; | ||
4619 | uint32_t dfs_count; | ||
4620 | uint32_t starting_peer; | ||
4621 | uint32_t least_connections; | ||
4622 | uint32_t random_connection; | ||
4623 | |||
4624 | #if OLD | ||
4625 | unsigned int temp_count; | ||
4626 | struct PeerConnection *peer_iter; | ||
4627 | #else | ||
4628 | struct DFSContext dfs_ctx; | ||
4629 | GNUNET_HashCode second_hash; | ||
4630 | #endif | ||
4631 | |||
4632 | #if OLD | ||
4633 | starting_peer = 0; | ||
4634 | dfs_count = 0; | ||
4635 | while ((count_workingset_connections (pg) < num * pg->total) && | ||
4636 | (count_allowed_connections (pg) > 0)) | ||
4637 | { | ||
4638 | if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ | ||
4639 | { | ||
4640 | least_connections = -1; /* Set to very high number */ | ||
4641 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4642 | { | ||
4643 | temp_count = | ||
4644 | count_connections (pg-> | ||
4645 | peers[pg_iter].connect_peers_working_set_head); | ||
4646 | if (temp_count < least_connections) | ||
4647 | { | ||
4648 | starting_peer = pg_iter; | ||
4649 | least_connections = temp_count; | ||
4650 | } | ||
4651 | } | ||
4652 | } | ||
4653 | |||
4654 | temp_count = | ||
4655 | count_connections (pg->peers[starting_peer].connect_peers_head); | ||
4656 | if (temp_count == 0) | ||
4657 | continue; /* FIXME: infinite loop? */ | ||
4658 | |||
4659 | random_connection = | ||
4660 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, temp_count); | ||
4661 | temp_count = 0; | ||
4662 | peer_iter = pg->peers[starting_peer].connect_peers_head; | ||
4663 | while (temp_count < random_connection) | ||
4664 | { | ||
4665 | peer_iter = peer_iter->next; | ||
4666 | temp_count++; | ||
4667 | } | ||
4668 | GNUNET_assert (peer_iter != NULL); | ||
4669 | add_connections (pg, starting_peer, peer_iter->index, WORKING_SET, | ||
4670 | GNUNET_NO); | ||
4671 | remove_connections (pg, starting_peer, peer_iter->index, CONNECT, | ||
4672 | GNUNET_YES); | ||
4673 | starting_peer = peer_iter->index; | ||
4674 | dfs_count++; | ||
4675 | } | ||
4676 | |||
4677 | #else | ||
4678 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4679 | { | ||
4680 | pg->peers[pg_iter].connect_peers_working_set = | ||
4681 | GNUNET_CONTAINER_multihashmap_create (num); | ||
4682 | } | ||
4683 | |||
4684 | starting_peer = 0; | ||
4685 | dfs_count = 0; | ||
4686 | while ((count_workingset_connections (pg) < num * pg->total) && | ||
4687 | (count_allowed_connections (pg) > 0)) | ||
4688 | { | ||
4689 | if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */ | ||
4690 | { | ||
4691 | least_connections = -1; /* Set to very high number */ | ||
4692 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4693 | { | ||
4694 | if (GNUNET_CONTAINER_multihashmap_size | ||
4695 | (pg->peers[pg_iter].connect_peers_working_set) < least_connections) | ||
4696 | { | ||
4697 | starting_peer = pg_iter; | ||
4698 | least_connections = | ||
4699 | GNUNET_CONTAINER_multihashmap_size (pg-> | ||
4700 | peers | ||
4701 | [pg_iter].connect_peers_working_set); | ||
4702 | } | ||
4703 | } | ||
4704 | } | ||
4705 | |||
4706 | if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0) /* Ensure there is at least one peer left to connect! */ | ||
4707 | { | ||
4708 | dfs_count = 0; | ||
4709 | continue; | ||
4710 | } | ||
4711 | |||
4712 | /* Choose a random peer from the chosen peers set of connections to add */ | ||
4713 | dfs_ctx.chosen = | ||
4714 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
4715 | GNUNET_CONTAINER_multihashmap_size (pg->peers | ||
4716 | [starting_peer].connect_peers)); | ||
4717 | dfs_ctx.first_uid = starting_peer; | ||
4718 | dfs_ctx.first = &pg->peers[starting_peer]; | ||
4719 | dfs_ctx.pg = pg; | ||
4720 | dfs_ctx.current = 0; | ||
4721 | |||
4722 | GNUNET_CONTAINER_multihashmap_iterate (pg-> | ||
4723 | peers[starting_peer].connect_peers, | ||
4724 | &dfs_connect_iterator, &dfs_ctx); | ||
4725 | /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */ | ||
4726 | hash_from_uid (dfs_ctx.second_uid, &second_hash); | ||
4727 | GNUNET_assert (GNUNET_YES == | ||
4728 | GNUNET_CONTAINER_multihashmap_remove (pg->peers | ||
4729 | [starting_peer].connect_peers, | ||
4730 | &second_hash, | ||
4731 | pg-> | ||
4732 | peers | ||
4733 | [dfs_ctx.second_uid].daemon)); | ||
4734 | starting_peer = dfs_ctx.second_uid; | ||
4735 | } | ||
4736 | |||
4737 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | ||
4738 | { | ||
4739 | /* Remove the "old" connections */ | ||
4740 | GNUNET_CONTAINER_multihashmap_destroy (pg->peers[pg_iter].connect_peers); | ||
4741 | /* And replace with the working set */ | ||
4742 | pg->peers[pg_iter].connect_peers = | ||
4743 | pg->peers[pg_iter].connect_peers_working_set; | ||
4744 | } | ||
4745 | #endif | ||
4746 | } | ||
4747 | |||
4748 | /** | ||
4749 | * Internal callback for topology information for a particular peer. | ||
4750 | */ | ||
4751 | static void | ||
4752 | internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *peer, | ||
4753 | const struct GNUNET_ATS_Information *atsi, | ||
4754 | unsigned int atsi_count) | ||
4755 | { | ||
4756 | struct CoreContext *core_ctx = cls; | ||
4757 | struct TopologyIterateContext *iter_ctx = core_ctx->iter_context; | ||
4758 | |||
4759 | if (peer == NULL) /* Either finished, or something went wrong */ | ||
4760 | { | ||
4761 | iter_ctx->completed++; | ||
4762 | iter_ctx->connected--; | ||
4763 | /* One core context allocated per iteration, must free! */ | ||
4764 | GNUNET_free (core_ctx); | ||
4765 | } | ||
4766 | else | ||
4767 | { | ||
4768 | iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id, peer, NULL); | ||
4769 | } | ||
4770 | |||
4771 | if (iter_ctx->completed == iter_ctx->total) | ||
4772 | { | ||
4773 | iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL); | ||
4774 | /* Once all are done, free the iteration context */ | ||
4775 | GNUNET_free (iter_ctx); | ||
4776 | } | ||
4777 | } | ||
4778 | |||
4779 | /** | ||
4780 | * Check running topology iteration tasks, if below max start a new one, otherwise | ||
4781 | * schedule for some time in the future. | ||
4782 | */ | ||
4783 | static void | ||
4784 | schedule_get_topology (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
4785 | { | ||
4786 | struct CoreContext *core_context = cls; | ||
4787 | struct TopologyIterateContext *topology_context = | ||
4788 | (struct TopologyIterateContext *) core_context->iter_context; | ||
4789 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
4790 | return; | ||
4791 | |||
4792 | if (topology_context->connected > | ||
4793 | topology_context->pg->max_outstanding_connections) | ||
4794 | { | ||
4795 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4796 | "Delaying connect, we have too many outstanding connections!\n"); | ||
4797 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
4798 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
4799 | &schedule_get_topology, core_context); | ||
4800 | } | ||
4801 | else | ||
4802 | { | ||
4803 | topology_context->connected++; | ||
4804 | |||
4805 | if (GNUNET_OK != | ||
4806 | GNUNET_CORE_iterate_peers (core_context->daemon->cfg, | ||
4807 | &internal_topology_callback, core_context)) | ||
4808 | { | ||
4809 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n"); | ||
4810 | internal_topology_callback (core_context, NULL, NULL, 0); | ||
4811 | } | ||
4812 | } | ||
4813 | } | ||
4814 | |||
4815 | /** | ||
4816 | * Iterate over all (running) peers in the peer group, retrieve | ||
4817 | * all connections that each currently has. | ||
4818 | */ | ||
4819 | void | ||
4820 | GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, | ||
4821 | GNUNET_TESTING_NotifyTopology cb, void *cls) | ||
4822 | { | ||
4823 | struct TopologyIterateContext *topology_context; | ||
4824 | struct CoreContext *core_ctx; | ||
4825 | unsigned int i; | ||
4826 | unsigned int total_count; | ||
4827 | |||
4828 | /* Allocate a single topology iteration context */ | ||
4829 | topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext)); | ||
4830 | topology_context->topology_cb = cb; | ||
4831 | topology_context->cls = cls; | ||
4832 | topology_context->pg = pg; | ||
4833 | total_count = 0; | ||
4834 | for (i = 0; i < pg->total; i++) | ||
4835 | { | ||
4836 | if (pg->peers[i].daemon->running == GNUNET_YES) | ||
4837 | { | ||
4838 | /* Allocate one core context per core we need to connect to */ | ||
4839 | core_ctx = GNUNET_malloc (sizeof (struct CoreContext)); | ||
4840 | core_ctx->daemon = pg->peers[i].daemon; | ||
4841 | /* Set back pointer to topology iteration context */ | ||
4842 | core_ctx->iter_context = topology_context; | ||
4843 | GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx); | ||
4844 | total_count++; | ||
4845 | } | ||
4846 | } | ||
4847 | if (total_count == 0) | ||
4848 | { | ||
4849 | cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!"); | ||
4850 | GNUNET_free (topology_context); | ||
4851 | } | ||
4852 | else | ||
4853 | topology_context->total = total_count; | ||
4854 | return; | ||
4855 | } | ||
4856 | |||
4857 | /** | ||
4858 | * Callback function to process statistic values. | ||
4859 | * This handler is here only really to insert a peer | ||
4860 | * identity (or daemon) so the statistics can be uniquely | ||
4861 | * tied to a single running peer. | ||
4862 | * | ||
4863 | * @param cls closure | ||
4864 | * @param subsystem name of subsystem that created the statistic | ||
4865 | * @param name the name of the datum | ||
4866 | * @param value the current value | ||
4867 | * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not | ||
4868 | * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration | ||
4869 | */ | ||
4870 | static int | ||
4871 | internal_stats_callback (void *cls, const char *subsystem, const char *name, | ||
4872 | uint64_t value, int is_persistent) | ||
4873 | { | ||
4874 | struct StatsCoreContext *core_context = cls; | ||
4875 | struct StatsIterateContext *stats_context = | ||
4876 | (struct StatsIterateContext *) core_context->iter_context; | ||
4877 | |||
4878 | return stats_context->proc (stats_context->cls, &core_context->daemon->id, | ||
4879 | subsystem, name, value, is_persistent); | ||
4880 | } | ||
4881 | |||
4882 | |||
4883 | /** | ||
4884 | * We don't need the statistics handle anymore, destroy it. | ||
4885 | * | ||
4886 | * @param cls Closure (the statistics handle to destroy) | ||
4887 | * @param tc Task Context | ||
4888 | */ | ||
4889 | static void | ||
4890 | internal_destroy_statistics (void *cls, | ||
4891 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
4892 | { | ||
4893 | struct GNUNET_STATISTICS_Handle *h = cls; | ||
4894 | |||
4895 | GNUNET_STATISTICS_destroy (h, GNUNET_NO); | ||
4896 | } | ||
4897 | |||
4898 | |||
4899 | /** | ||
4900 | * Internal continuation call for statistics iteration. | ||
4901 | * | ||
4902 | * @param cls closure, the CoreContext for this iteration | ||
4903 | * @param success whether or not the statistics iterations | ||
4904 | * was canceled or not (we don't care) | ||
4905 | */ | ||
4906 | static void | ||
4907 | internal_stats_cont (void *cls, int success) | ||
4908 | { | ||
4909 | struct StatsCoreContext *core_context = cls; | ||
4910 | struct StatsIterateContext *stats_context = | ||
4911 | (struct StatsIterateContext *) core_context->iter_context; | ||
4912 | |||
4913 | stats_context->connected--; | ||
4914 | stats_context->completed++; | ||
4915 | |||
4916 | if (stats_context->completed == stats_context->total) | ||
4917 | { | ||
4918 | stats_context->cont (stats_context->cls, GNUNET_YES); | ||
4919 | GNUNET_free (stats_context); | ||
4920 | } | ||
4921 | |||
4922 | if (core_context->stats_handle != NULL) | ||
4923 | /* Cannot destroy handle inside the continuation */ | ||
4924 | GNUNET_SCHEDULER_add_now (&internal_destroy_statistics, | ||
4925 | core_context->stats_handle); | ||
4926 | |||
4927 | GNUNET_free (core_context); | ||
4928 | } | ||
4929 | |||
4930 | /** | ||
4931 | * Check running topology iteration tasks, if below max start a new one, otherwise | ||
4932 | * schedule for some time in the future. | ||
4933 | */ | ||
4934 | static void | ||
4935 | schedule_get_statistics (void *cls, | ||
4936 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
4937 | { | ||
4938 | struct StatsCoreContext *core_context = cls; | ||
4939 | struct StatsIterateContext *stats_context = | ||
4940 | (struct StatsIterateContext *) core_context->iter_context; | ||
4941 | |||
4942 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
4943 | return; | ||
4944 | |||
4945 | if (stats_context->connected > stats_context->pg->max_outstanding_connections) | ||
4946 | { | ||
4947 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
4948 | "Delaying connect, we have too many outstanding connections!\n"); | ||
4949 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
4950 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
4951 | &schedule_get_statistics, core_context); | ||
4952 | } | ||
4953 | else | ||
4954 | { | ||
4955 | stats_context->connected++; | ||
4956 | core_context->stats_handle = | ||
4957 | GNUNET_STATISTICS_create ("testing", core_context->daemon->cfg); | ||
4958 | if (core_context->stats_handle == NULL) | ||
4959 | { | ||
4960 | internal_stats_cont (core_context, GNUNET_NO); | ||
4961 | return; | ||
4962 | } | ||
4963 | |||
4964 | core_context->stats_get_handle = | ||
4965 | GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL, | ||
4966 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
4967 | &internal_stats_cont, &internal_stats_callback, | ||
4968 | core_context); | ||
4969 | if (core_context->stats_get_handle == NULL) | ||
4970 | internal_stats_cont (core_context, GNUNET_NO); | ||
4971 | |||
4972 | } | ||
4973 | } | ||
4974 | |||
4975 | struct DuplicateStats | ||
4976 | { | ||
4977 | /** | ||
4978 | * Next item in the list | ||
4979 | */ | ||
4980 | struct DuplicateStats *next; | ||
4981 | |||
4982 | /** | ||
4983 | * Nasty string, concatenation of relevant information. | ||
4984 | */ | ||
4985 | char *unique_string; | ||
4986 | }; | ||
4987 | |||
4988 | /** | ||
4989 | * Check whether the combination of port/host/unix domain socket | ||
4990 | * already exists in the list of peers being checked for statistics. | ||
4991 | * | ||
4992 | * @param pg the peergroup in question | ||
4993 | * @param specific_peer the peer we're concerned with | ||
4994 | * @param stats_list the list to return to the caller | ||
4995 | * | ||
4996 | * @return GNUNET_YES if the statistics instance has been seen already, | ||
4997 | * GNUNET_NO if not (and we may have added it to the list) | ||
4998 | */ | ||
4999 | static int | ||
5000 | stats_check_existing (struct GNUNET_TESTING_PeerGroup *pg, | ||
5001 | struct PeerData *specific_peer, | ||
5002 | struct DuplicateStats **stats_list) | ||
5003 | { | ||
5004 | struct DuplicateStats *pos; | ||
5005 | char *unix_domain_socket; | ||
5006 | unsigned long long port; | ||
5007 | char *to_match; | ||
5008 | |||
5009 | if (GNUNET_YES != | ||
5010 | GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing", | ||
5011 | "single_statistics_per_host")) | ||
5012 | return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */ | ||
5013 | |||
5014 | pos = *stats_list; | ||
5015 | if (GNUNET_OK != | ||
5016 | GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg, "statistics", | ||
5017 | "unixpath", &unix_domain_socket)) | ||
5018 | return GNUNET_NO; | ||
5019 | |||
5020 | if (GNUNET_OK != | ||
5021 | GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics", | ||
5022 | "port", &port)) | ||
5023 | { | ||
5024 | GNUNET_free (unix_domain_socket); | ||
5025 | return GNUNET_NO; | ||
5026 | } | ||
5027 | |||
5028 | if (specific_peer->daemon->hostname != NULL) | ||
5029 | GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname, | ||
5030 | unix_domain_socket, port); | ||
5031 | else | ||
5032 | GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port); | ||
5033 | |||
5034 | while (pos != NULL) | ||
5035 | { | ||
5036 | if (0 == strcmp (to_match, pos->unique_string)) | ||
5037 | { | ||
5038 | GNUNET_free (unix_domain_socket); | ||
5039 | GNUNET_free (to_match); | ||
5040 | return GNUNET_YES; | ||
5041 | } | ||
5042 | pos = pos->next; | ||
5043 | } | ||
5044 | pos = GNUNET_malloc (sizeof (struct DuplicateStats)); | ||
5045 | pos->unique_string = to_match; | ||
5046 | pos->next = *stats_list; | ||
5047 | *stats_list = pos; | ||
5048 | GNUNET_free (unix_domain_socket); | ||
5049 | return GNUNET_NO; | ||
5050 | } | ||
5051 | |||
5052 | /** | ||
5053 | * Iterate over all (running) peers in the peer group, retrieve | ||
5054 | * all statistics from each. | ||
5055 | * | ||
5056 | * @param pg the peergroup to iterate statistics of | ||
5057 | * @param cont continuation to call once all stats have been retrieved | ||
5058 | * @param proc processing function for each statistic from each peer | ||
5059 | * @param cls closure to pass to proc | ||
5060 | * | ||
5061 | */ | ||
5062 | void | ||
5063 | GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, | ||
5064 | GNUNET_STATISTICS_Callback cont, | ||
5065 | GNUNET_TESTING_STATISTICS_Iterator proc, | ||
5066 | void *cls) | ||
5067 | { | ||
5068 | struct StatsIterateContext *stats_context; | ||
5069 | struct StatsCoreContext *core_ctx; | ||
5070 | unsigned int i; | ||
5071 | unsigned int total_count; | ||
5072 | struct DuplicateStats *stats_list; | ||
5073 | struct DuplicateStats *pos; | ||
5074 | |||
5075 | stats_list = NULL; | ||
5076 | |||
5077 | /* Allocate a single stats iteration context */ | ||
5078 | stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext)); | ||
5079 | stats_context->cont = cont; | ||
5080 | stats_context->proc = proc; | ||
5081 | stats_context->cls = cls; | ||
5082 | stats_context->pg = pg; | ||
5083 | total_count = 0; | ||
5084 | |||
5085 | for (i = 0; i < pg->total; i++) | ||
5086 | { | ||
5087 | if ((pg->peers[i].daemon->running == GNUNET_YES) && | ||
5088 | (GNUNET_NO == stats_check_existing (pg, &pg->peers[i], &stats_list))) | ||
5089 | { | ||
5090 | /* Allocate one core context per core we need to connect to */ | ||
5091 | core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext)); | ||
5092 | core_ctx->daemon = pg->peers[i].daemon; | ||
5093 | /* Set back pointer to topology iteration context */ | ||
5094 | core_ctx->iter_context = stats_context; | ||
5095 | GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx); | ||
5096 | total_count++; | ||
5097 | } | ||
5098 | } | ||
5099 | |||
5100 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5101 | "Retrieving stats from %u total instances.\n", total_count); | ||
5102 | if (0 != total_count) | ||
5103 | stats_context->total = total_count; | ||
5104 | else | ||
5105 | GNUNET_free (stats_context); | ||
5106 | if (stats_list != NULL) | ||
5107 | { | ||
5108 | pos = stats_list; | ||
5109 | while (pos != NULL) | ||
5110 | { | ||
5111 | GNUNET_free (pos->unique_string); | ||
5112 | stats_list = pos->next; | ||
5113 | GNUNET_free (pos); | ||
5114 | pos = stats_list->next; | ||
5115 | } | ||
5116 | } | ||
5117 | return; | ||
5118 | } | ||
5119 | |||
5120 | /** | ||
5121 | * Stop the connection process temporarily. | ||
5122 | * | ||
5123 | * @param pg the peer group to stop connecting | ||
5124 | */ | ||
5125 | void | ||
5126 | GNUNET_TESTING_stop_connections (struct GNUNET_TESTING_PeerGroup *pg) | ||
5127 | { | ||
5128 | pg->stop_connects = GNUNET_YES; | ||
5129 | } | ||
5130 | |||
5131 | /** | ||
5132 | * Resume the connection process temporarily. | ||
5133 | * | ||
5134 | * @param pg the peer group to resume connecting | ||
5135 | */ | ||
5136 | void | ||
5137 | GNUNET_TESTING_resume_connections (struct GNUNET_TESTING_PeerGroup *pg) | ||
5138 | { | ||
5139 | pg->stop_connects = GNUNET_NO; | ||
5140 | } | ||
5141 | |||
5142 | /** | ||
5143 | * There are many ways to connect peers that are supported by this function. | ||
5144 | * To connect peers in the same topology that was created via the | ||
5145 | * GNUNET_TESTING_create_topology, the topology variable must be set to | ||
5146 | * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, | ||
5147 | * a new instance of that topology will be generated and attempted to be | ||
5148 | * connected. This could result in some connections being impossible, | ||
5149 | * because some topologies are non-deterministic. | ||
5150 | * | ||
5151 | * @param pg the peer group struct representing the running peers | ||
5152 | * @param topology which topology to connect the peers in | ||
5153 | * @param options options for connecting the topology | ||
5154 | * @param option_modifier modifier for options that take a parameter | ||
5155 | * @param connect_timeout how long to wait before giving up on connecting | ||
5156 | * two peers | ||
5157 | * @param connect_attempts how many times to attempt to connect two peers | ||
5158 | * over the connect_timeout duration | ||
5159 | * @param notify_callback notification to be called once all connections completed | ||
5160 | * @param notify_cls closure for notification callback | ||
5161 | * | ||
5162 | * @return the number of connections that will be attempted, GNUNET_SYSERR on error | ||
5163 | */ | ||
5164 | int | ||
5165 | GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, | ||
5166 | enum GNUNET_TESTING_Topology topology, | ||
5167 | enum GNUNET_TESTING_TopologyOption options, | ||
5168 | double option_modifier, | ||
5169 | struct GNUNET_TIME_Relative connect_timeout, | ||
5170 | unsigned int connect_attempts, | ||
5171 | GNUNET_TESTING_NotifyCompletion | ||
5172 | notify_callback, void *notify_cls) | ||
5173 | { | ||
5174 | switch (topology) | ||
5175 | { | ||
5176 | case GNUNET_TESTING_TOPOLOGY_CLIQUE: | ||
5177 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5178 | "Creating clique CONNECT topology\n"); | ||
5179 | create_clique (pg, &add_connections, CONNECT, GNUNET_NO); | ||
5180 | break; | ||
5181 | case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING: | ||
5182 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5183 | "Creating small world (ring) CONNECT topology\n"); | ||
5184 | create_small_world_ring (pg, &add_connections, CONNECT); | ||
5185 | break; | ||
5186 | case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD: | ||
5187 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5188 | "Creating small world (2d-torus) CONNECT topology\n"); | ||
5189 | create_small_world (pg, &add_connections, CONNECT); | ||
5190 | break; | ||
5191 | case GNUNET_TESTING_TOPOLOGY_RING: | ||
5192 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating ring CONNECT topology\n"); | ||
5193 | create_ring (pg, &add_connections, CONNECT); | ||
5194 | break; | ||
5195 | case GNUNET_TESTING_TOPOLOGY_2D_TORUS: | ||
5196 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5197 | "Creating 2d torus CONNECT topology\n"); | ||
5198 | create_2d_torus (pg, &add_connections, CONNECT); | ||
5199 | break; | ||
5200 | case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI: | ||
5201 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5202 | "Creating Erdos-Renyi CONNECT topology\n"); | ||
5203 | create_erdos_renyi (pg, &add_connections, CONNECT); | ||
5204 | break; | ||
5205 | case GNUNET_TESTING_TOPOLOGY_INTERNAT: | ||
5206 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5207 | "Creating InterNAT CONNECT topology\n"); | ||
5208 | create_nated_internet (pg, &add_connections, CONNECT); | ||
5209 | break; | ||
5210 | case GNUNET_TESTING_TOPOLOGY_SCALE_FREE: | ||
5211 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5212 | "Creating Scale Free CONNECT topology\n"); | ||
5213 | create_scale_free (pg, &add_connections, CONNECT); | ||
5214 | break; | ||
5215 | case GNUNET_TESTING_TOPOLOGY_LINE: | ||
5216 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5217 | "Creating straight line CONNECT topology\n"); | ||
5218 | create_line (pg, &add_connections, CONNECT); | ||
5219 | break; | ||
5220 | case GNUNET_TESTING_TOPOLOGY_NONE: | ||
5221 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating no CONNECT topology\n"); | ||
5222 | copy_allowed_topology (pg); | ||
5223 | break; | ||
5224 | default: | ||
5225 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
5226 | _("Unknown topology specification, can't connect peers!\n")); | ||
5227 | return GNUNET_SYSERR; | ||
5228 | } | ||
5229 | |||
5230 | switch (options) | ||
5231 | { | ||
5232 | case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: | ||
5233 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5234 | "Connecting random subset (%'.2f percent) of possible peers\n", | ||
5235 | 100 * option_modifier); | ||
5236 | choose_random_connections (pg, option_modifier); | ||
5237 | break; | ||
5238 | case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: | ||
5239 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5240 | "Connecting a minimum of %u peers each (if possible)\n", | ||
5241 | (unsigned int) option_modifier); | ||
5242 | choose_minimum (pg, (unsigned int) option_modifier); | ||
5243 | break; | ||
5244 | case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: | ||
5245 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5246 | "Using DFS to connect a minimum of %u peers each (if possible)\n", | ||
5247 | (unsigned int) option_modifier); | ||
5248 | #if FIXME | ||
5249 | perform_dfs (pg, (int) option_modifier); | ||
5250 | #endif | ||
5251 | break; | ||
5252 | case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST: | ||
5253 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5254 | "Finding additional %u closest peers each (if possible)\n", | ||
5255 | (unsigned int) option_modifier); | ||
5256 | #if FIXME | ||
5257 | add_closest (pg, (unsigned int) option_modifier, &add_connections, CONNECT); | ||
5258 | #endif | ||
5259 | break; | ||
5260 | case GNUNET_TESTING_TOPOLOGY_OPTION_NONE: | ||
5261 | break; | ||
5262 | case GNUNET_TESTING_TOPOLOGY_OPTION_ALL: | ||
5263 | break; | ||
5264 | default: | ||
5265 | break; | ||
5266 | } | ||
5267 | |||
5268 | return connect_topology (pg, connect_timeout, connect_attempts, | ||
5269 | notify_callback, notify_cls); | ||
5270 | } | ||
5271 | |||
5272 | /** | ||
5273 | * Lookup and return the number of SSH connections to a host. | ||
5274 | * | ||
5275 | * @param hostname the hostname to lookup in the list | ||
5276 | * @param pg the peergroup that the host belongs to | ||
5277 | * | ||
5278 | * @return the number of current ssh connections to the host | ||
5279 | */ | ||
5280 | static unsigned int | ||
5281 | count_outstanding_at_host (const char *hostname, | ||
5282 | struct GNUNET_TESTING_PeerGroup *pg) | ||
5283 | { | ||
5284 | struct OutstandingSSH *pos; | ||
5285 | |||
5286 | pos = pg->ssh_head; | ||
5287 | while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) | ||
5288 | pos = pos->next; | ||
5289 | GNUNET_assert (pos != NULL); | ||
5290 | return pos->outstanding; | ||
5291 | } | ||
5292 | |||
5293 | /** | ||
5294 | * Increment the number of SSH connections to a host by one. | ||
5295 | * | ||
5296 | * @param hostname the hostname to lookup in the list | ||
5297 | * @param pg the peergroup that the host belongs to | ||
5298 | * | ||
5299 | */ | ||
5300 | static void | ||
5301 | increment_outstanding_at_host (const char *hostname, | ||
5302 | struct GNUNET_TESTING_PeerGroup *pg) | ||
5303 | { | ||
5304 | struct OutstandingSSH *pos; | ||
5305 | |||
5306 | pos = pg->ssh_head; | ||
5307 | while ((NULL != pos) && (strcmp (pos->hostname, hostname) != 0)) | ||
5308 | pos = pos->next; | ||
5309 | GNUNET_assert (NULL != pos); | ||
5310 | pos->outstanding++; | ||
5311 | } | ||
5312 | |||
5313 | /** | ||
5314 | * Decrement the number of SSH connections to a host by one. | ||
5315 | * | ||
5316 | * @param hostname the hostname to lookup in the list | ||
5317 | * @param pg the peergroup that the host belongs to | ||
5318 | * | ||
5319 | */ | ||
5320 | static void | ||
5321 | decrement_outstanding_at_host (const char *hostname, | ||
5322 | struct GNUNET_TESTING_PeerGroup *pg) | ||
5323 | { | ||
5324 | struct OutstandingSSH *pos; | ||
5325 | |||
5326 | pos = pg->ssh_head; | ||
5327 | while ((pos != NULL) && (strcmp (pos->hostname, hostname) != 0)) | ||
5328 | pos = pos->next; | ||
5329 | GNUNET_assert (pos != NULL); | ||
5330 | pos->outstanding--; | ||
5331 | } | ||
5332 | |||
5333 | /** | ||
5334 | * Callback that is called whenever a hostkey is generated | ||
5335 | * for a peer. Call the real callback and decrement the | ||
5336 | * starting counter for the peergroup. | ||
5337 | * | ||
5338 | * @param cls closure | ||
5339 | * @param id identifier for the daemon, NULL on error | ||
5340 | * @param d handle for the daemon | ||
5341 | * @param emsg error message (NULL on success) | ||
5342 | */ | ||
5343 | static void | ||
5344 | internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
5345 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
5346 | { | ||
5347 | struct InternalStartContext *internal_context = cls; | ||
5348 | |||
5349 | internal_context->peer->pg->starting--; | ||
5350 | internal_context->peer->pg->started++; | ||
5351 | if (internal_context->hostname != NULL) | ||
5352 | decrement_outstanding_at_host (internal_context->hostname, | ||
5353 | internal_context->peer->pg); | ||
5354 | if (internal_context->hostkey_callback != NULL) | ||
5355 | internal_context->hostkey_callback (internal_context->hostkey_cls, id, d, | ||
5356 | emsg); | ||
5357 | else if (internal_context->peer->pg->started == | ||
5358 | internal_context->peer->pg->total) | ||
5359 | { | ||
5360 | internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */ | ||
5361 | GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg); | ||
5362 | } | ||
5363 | } | ||
5364 | |||
5365 | /** | ||
5366 | * Callback that is called whenever a peer has finished starting. | ||
5367 | * Call the real callback and decrement the starting counter | ||
5368 | * for the peergroup. | ||
5369 | * | ||
5370 | * @param cls closure | ||
5371 | * @param id identifier for the daemon, NULL on error | ||
5372 | * @param cfg config | ||
5373 | * @param d handle for the daemon | ||
5374 | * @param emsg error message (NULL on success) | ||
5375 | */ | ||
5376 | static void | ||
5377 | internal_startup_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
5378 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
5379 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
5380 | { | ||
5381 | struct InternalStartContext *internal_context = cls; | ||
5382 | |||
5383 | internal_context->peer->pg->starting--; | ||
5384 | if (internal_context->hostname != NULL) | ||
5385 | decrement_outstanding_at_host (internal_context->hostname, | ||
5386 | internal_context->peer->pg); | ||
5387 | if (internal_context->start_cb != NULL) | ||
5388 | internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d, | ||
5389 | emsg); | ||
5390 | } | ||
5391 | |||
5392 | |||
5393 | /** | ||
5394 | * Calls GNUNET_TESTING_daemon_continue_startup to set the daemon's state | ||
5395 | * from HOSTKEY_CREATED to TOPOLOGY_SETUP. Makes sure not to saturate a host | ||
5396 | * with requests delaying them when needed. | ||
5397 | * | ||
5398 | * @param cls closure: internal context of the daemon. | ||
5399 | * @param tc TaskContext | ||
5400 | */ | ||
5401 | static void | ||
5402 | internal_continue_startup (void *cls, | ||
5403 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
5404 | { | ||
5405 | struct InternalStartContext *internal_context = cls; | ||
5406 | |||
5407 | internal_context->peer->startup_task = GNUNET_SCHEDULER_NO_TASK; | ||
5408 | |||
5409 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
5410 | { | ||
5411 | return; | ||
5412 | } | ||
5413 | |||
5414 | if ((internal_context->peer->pg->starting < | ||
5415 | internal_context->peer->pg->max_concurrent_ssh) || | ||
5416 | ((internal_context->hostname != NULL) && | ||
5417 | (count_outstanding_at_host | ||
5418 | (internal_context->hostname, | ||
5419 | internal_context->peer->pg) < | ||
5420 | internal_context->peer->pg->max_concurrent_ssh))) | ||
5421 | { | ||
5422 | if (internal_context->hostname != NULL) | ||
5423 | increment_outstanding_at_host (internal_context->hostname, | ||
5424 | internal_context->peer->pg); | ||
5425 | internal_context->peer->pg->starting++; | ||
5426 | GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon); | ||
5427 | } | ||
5428 | else | ||
5429 | { | ||
5430 | internal_context->peer->startup_task = | ||
5431 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
5432 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
5433 | &internal_continue_startup, | ||
5434 | internal_context); | ||
5435 | } | ||
5436 | } | ||
5437 | |||
5438 | /** | ||
5439 | * Callback for informing us about a successful | ||
5440 | * or unsuccessful churn start call. | ||
5441 | * | ||
5442 | * @param cls a ChurnContext | ||
5443 | * @param id the peer identity of the started peer | ||
5444 | * @param cfg the handle to the configuration of the peer | ||
5445 | * @param d handle to the daemon for the peer | ||
5446 | * @param emsg NULL on success, non-NULL on failure | ||
5447 | * | ||
5448 | */ | ||
5449 | void | ||
5450 | churn_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
5451 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
5452 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
5453 | { | ||
5454 | struct ChurnRestartContext *startup_ctx = cls; | ||
5455 | struct ChurnContext *churn_ctx = startup_ctx->churn_ctx; | ||
5456 | |||
5457 | unsigned int total_left; | ||
5458 | char *error_message; | ||
5459 | |||
5460 | error_message = NULL; | ||
5461 | if (emsg != NULL) | ||
5462 | { | ||
5463 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
5464 | "Churn stop callback failed with error `%s'\n", emsg); | ||
5465 | churn_ctx->num_failed_start++; | ||
5466 | } | ||
5467 | else | ||
5468 | { | ||
5469 | churn_ctx->num_to_start--; | ||
5470 | } | ||
5471 | |||
5472 | total_left = | ||
5473 | (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + | ||
5474 | (churn_ctx->num_to_start - churn_ctx->num_failed_start); | ||
5475 | |||
5476 | if (total_left == 0) | ||
5477 | { | ||
5478 | if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) | ||
5479 | GNUNET_asprintf (&error_message, | ||
5480 | "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", | ||
5481 | churn_ctx->num_failed_start, churn_ctx->num_failed_stop); | ||
5482 | churn_ctx->cb (churn_ctx->cb_cls, error_message); | ||
5483 | GNUNET_free_non_null (error_message); | ||
5484 | GNUNET_free (churn_ctx); | ||
5485 | GNUNET_free (startup_ctx); | ||
5486 | } | ||
5487 | } | ||
5488 | |||
5489 | static void | ||
5490 | schedule_churn_restart (void *cls, | ||
5491 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
5492 | { | ||
5493 | struct PeerRestartContext *peer_restart_ctx = cls; | ||
5494 | struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx; | ||
5495 | |||
5496 | if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) | ||
5497 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
5498 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
5499 | &schedule_churn_restart, peer_restart_ctx); | ||
5500 | else | ||
5501 | { | ||
5502 | if (startup_ctx->churn_ctx->service != NULL) | ||
5503 | GNUNET_TESTING_daemon_start_stopped_service (peer_restart_ctx->daemon, | ||
5504 | startup_ctx-> | ||
5505 | churn_ctx->service, | ||
5506 | startup_ctx->timeout, | ||
5507 | &churn_start_callback, | ||
5508 | startup_ctx); | ||
5509 | else | ||
5510 | GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon, | ||
5511 | startup_ctx->timeout, | ||
5512 | &churn_start_callback, startup_ctx); | ||
5513 | GNUNET_free (peer_restart_ctx); | ||
5514 | } | ||
5515 | } | ||
5516 | |||
5517 | /** | ||
5518 | * Callback for informing us about a successful | ||
5519 | * or unsuccessful churn start call. | ||
5520 | * | ||
5521 | * @param cls a struct ServiceStartContext *startup_ctx | ||
5522 | * @param id the peer identity of the started peer | ||
5523 | * @param cfg the handle to the configuration of the peer | ||
5524 | * @param d handle to the daemon for the peer | ||
5525 | * @param emsg NULL on success, non-NULL on failure | ||
5526 | * | ||
5527 | */ | ||
5528 | void | ||
5529 | service_start_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
5530 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
5531 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
5532 | { | ||
5533 | struct ServiceStartContext *startup_ctx = (struct ServiceStartContext *) cls; | ||
5534 | |||
5535 | if (emsg != NULL) | ||
5536 | { | ||
5537 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
5538 | "Service start failed with error `%s'\n", emsg); | ||
5539 | } | ||
5540 | |||
5541 | startup_ctx->outstanding--; | ||
5542 | startup_ctx->remaining--; | ||
5543 | |||
5544 | if (startup_ctx->remaining == 0) | ||
5545 | { | ||
5546 | startup_ctx->cb (startup_ctx->cb_cls, NULL); | ||
5547 | GNUNET_free (startup_ctx->service); | ||
5548 | GNUNET_free (startup_ctx); | ||
5549 | } | ||
5550 | } | ||
5551 | |||
5552 | static void | ||
5553 | schedule_service_start (void *cls, | ||
5554 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
5555 | { | ||
5556 | struct PeerServiceStartContext *peer_ctx = cls; | ||
5557 | struct ServiceStartContext *startup_ctx = peer_ctx->start_ctx; | ||
5558 | |||
5559 | if (startup_ctx->outstanding > startup_ctx->pg->max_concurrent_ssh) | ||
5560 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
5561 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
5562 | &schedule_service_start, peer_ctx); | ||
5563 | else | ||
5564 | { | ||
5565 | |||
5566 | GNUNET_TESTING_daemon_start_service (peer_ctx->daemon, startup_ctx->service, | ||
5567 | startup_ctx->timeout, | ||
5568 | &service_start_callback, startup_ctx); | ||
5569 | GNUNET_free (peer_ctx); | ||
5570 | } | ||
5571 | } | ||
5572 | |||
5573 | |||
5574 | static void | ||
5575 | internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
5576 | { | ||
5577 | struct InternalStartContext *internal_context = cls; | ||
5578 | |||
5579 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | ||
5580 | { | ||
5581 | return; | ||
5582 | } | ||
5583 | |||
5584 | if ((internal_context->peer->pg->starting < | ||
5585 | internal_context->peer->pg->max_concurrent_ssh) || | ||
5586 | ((internal_context->hostname != NULL) && | ||
5587 | (count_outstanding_at_host | ||
5588 | (internal_context->hostname, | ||
5589 | internal_context->peer->pg) < | ||
5590 | internal_context->peer->pg->max_concurrent_ssh))) | ||
5591 | { | ||
5592 | if (internal_context->hostname != NULL) | ||
5593 | increment_outstanding_at_host (internal_context->hostname, | ||
5594 | internal_context->peer->pg); | ||
5595 | internal_context->peer->pg->starting++; | ||
5596 | internal_context->peer->daemon = | ||
5597 | GNUNET_TESTING_daemon_start (internal_context->peer->cfg, | ||
5598 | internal_context->timeout, GNUNET_NO, | ||
5599 | internal_context->hostname, | ||
5600 | internal_context->username, | ||
5601 | internal_context->sshport, | ||
5602 | internal_context->hostkey, | ||
5603 | &internal_hostkey_callback, | ||
5604 | internal_context, | ||
5605 | &internal_startup_callback, | ||
5606 | internal_context); | ||
5607 | } | ||
5608 | else | ||
5609 | { | ||
5610 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
5611 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
5612 | &internal_start, internal_context); | ||
5613 | } | ||
5614 | } | ||
5615 | |||
5616 | #if USE_START_HELPER | ||
5617 | |||
5618 | struct PeerStartHelperContext | ||
5619 | { | ||
5620 | struct GNUNET_TESTING_PeerGroup *pg; | ||
5621 | |||
5622 | struct HostData *host; | ||
5623 | |||
5624 | struct GNUNET_OS_Process *proc; | ||
5625 | }; | ||
5626 | |||
5627 | static void | ||
5628 | check_peers_started (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
5629 | { | ||
5630 | struct PeerStartHelperContext *helper = cls; | ||
5631 | enum GNUNET_OS_ProcessStatusType type; | ||
5632 | unsigned long code; | ||
5633 | unsigned int i; | ||
5634 | GNUNET_TESTING_NotifyDaemonRunning cb; | ||
5635 | |||
5636 | if (GNUNET_NO == GNUNET_OS_process_status (helper->proc, &type, &code)) /* Still running, wait some more! */ | ||
5637 | { | ||
5638 | GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_EXEC_WAIT, | ||
5639 | &check_peers_started, helper); | ||
5640 | return; | ||
5641 | } | ||
5642 | |||
5643 | helper->pg->starting--; | ||
5644 | if (helper->pg->starting == 0) /* All peers have finished starting! */ | ||
5645 | { | ||
5646 | /* Call the peer started callback for each peer, set proper FSM state (?) */ | ||
5647 | for (i = 0; i < helper->pg->total; i++) | ||
5648 | { | ||
5649 | cb = helper->pg->peers[i].daemon->cb; | ||
5650 | helper->pg->peers[i].daemon->cb = NULL; | ||
5651 | helper->pg->peers[i].daemon->running = GNUNET_YES; | ||
5652 | helper->pg->peers[i].daemon->phase = SP_START_DONE; | ||
5653 | if (NULL != cb) | ||
5654 | { | ||
5655 | if ((type != GNUNET_OS_PROCESS_EXITED) || (code != 0)) | ||
5656 | cb (helper->pg->peers[i].daemon->cb_cls, | ||
5657 | &helper->pg->peers[i].daemon->id, | ||
5658 | helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, | ||
5659 | "Failed to execute peerStartHelper.pl, or return code bad!"); | ||
5660 | else | ||
5661 | cb (helper->pg->peers[i].daemon->cb_cls, | ||
5662 | &helper->pg->peers[i].daemon->id, | ||
5663 | helper->pg->peers[i].daemon->cfg, helper->pg->peers[i].daemon, | ||
5664 | NULL); | ||
5665 | |||
5666 | } | ||
5667 | |||
5668 | } | ||
5669 | } | ||
5670 | GNUNET_OS_process_destroy (helper->proc); | ||
5671 | } | ||
5672 | |||
5673 | static void | ||
5674 | start_peer_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
5675 | { | ||
5676 | struct PeerStartHelperContext *helper = cls; | ||
5677 | char *baseservicehome; | ||
5678 | char *tempdir; | ||
5679 | char *arg; | ||
5680 | |||
5681 | /* ssh user@host peerStartHelper /path/to/basedirectory */ | ||
5682 | GNUNET_assert (GNUNET_OK == | ||
5683 | GNUNET_CONFIGURATION_get_value_string (helper->pg->cfg, | ||
5684 | "PATHS", "SERVICEHOME", | ||
5685 | &baseservicehome)); | ||
5686 | GNUNET_asprintf (&tempdir, "%s/%s/", baseservicehome, helper->host->hostname); | ||
5687 | if (NULL != helper->host->username) | ||
5688 | GNUNET_asprintf (&arg, "%s@%s", helper->host->username, | ||
5689 | helper->host->hostname); | ||
5690 | else | ||
5691 | GNUNET_asprintf (&arg, "%s", helper->host->hostname); | ||
5692 | |||
5693 | /* FIXME: Doesn't support ssh_port option! */ | ||
5694 | helper->proc = | ||
5695 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, | ||
5696 | "peerStartHelper.pl", tempdir, NULL); | ||
5697 | GNUNET_assert (helper->proc != NULL); | ||
5698 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting peers with cmd ssh %s %s %s\n", | ||
5699 | arg, "peerStartHelper.pl", tempdir); | ||
5700 | GNUNET_SCHEDULER_add_now (&check_peers_started, helper); | ||
5701 | GNUNET_free (tempdir); | ||
5702 | GNUNET_free (baseservicehome); | ||
5703 | GNUNET_free (arg); | ||
5704 | } | ||
5705 | #endif | ||
5706 | |||
5707 | /** | ||
5708 | * Function which continues a peer group starting up | ||
5709 | * after successfully generating hostkeys for each peer. | ||
5710 | * | ||
5711 | * @param pg the peer group to continue starting | ||
5712 | * | ||
5713 | */ | ||
5714 | void | ||
5715 | GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg) | ||
5716 | { | ||
5717 | unsigned int i; | ||
5718 | |||
5719 | #if USE_START_HELPER | ||
5720 | if ((pg->num_hosts > 0) && (pg->hostkey_data != NULL)) | ||
5721 | { | ||
5722 | struct PeerStartHelperContext *helper; | ||
5723 | |||
5724 | pg->starting = pg->num_hosts; | ||
5725 | for (i = 0; i < pg->num_hosts; i++) | ||
5726 | { | ||
5727 | helper = GNUNET_malloc (sizeof (struct PeerStartHelperContext)); | ||
5728 | helper->pg = pg; | ||
5729 | helper->host = &pg->hosts[i]; | ||
5730 | GNUNET_SCHEDULER_add_now (&start_peer_helper, helper); | ||
5731 | } | ||
5732 | } | ||
5733 | else | ||
5734 | { | ||
5735 | pg->starting = 0; | ||
5736 | for (i = 0; i < pg->total; i++) | ||
5737 | { | ||
5738 | pg->peers[i].startup_task = | ||
5739 | GNUNET_SCHEDULER_add_now (&internal_continue_startup, | ||
5740 | &pg->peers[i].internal_context); | ||
5741 | } | ||
5742 | } | ||
5743 | #else | ||
5744 | pg->starting = 0; | ||
5745 | for (i = 0; i < pg->total; i++) | ||
5746 | { | ||
5747 | pg->peers[i].startup_task = | ||
5748 | GNUNET_SCHEDULER_add_now (&internal_continue_startup, | ||
5749 | &pg->peers[i].internal_context); | ||
5750 | } | ||
5751 | #endif | ||
5752 | } | ||
5753 | |||
5754 | #if USE_START_HELPER | ||
5755 | static void | ||
5756 | call_hostkey_callbacks (void *cls, | ||
5757 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
5758 | { | ||
5759 | struct GNUNET_TESTING_PeerGroup *pg = cls; | ||
5760 | unsigned int i; | ||
5761 | |||
5762 | for (i = 0; i < pg->total; i++) | ||
5763 | { | ||
5764 | if (pg->peers[i].internal_context.hostkey_callback != NULL) | ||
5765 | pg->peers[i].internal_context.hostkey_callback (pg->peers[i]. | ||
5766 | internal_context.hostkey_cls, | ||
5767 | &pg->peers[i].daemon->id, | ||
5768 | pg->peers[i].daemon, | ||
5769 | NULL); | ||
5770 | } | ||
5771 | |||
5772 | if (pg->peers[0].internal_context.hostkey_callback == NULL) | ||
5773 | GNUNET_TESTING_daemons_continue_startup (pg); | ||
5774 | } | ||
5775 | #endif | ||
5776 | |||
5777 | /** | ||
5778 | * Start count gnunet instances with the same set of transports and | ||
5779 | * applications. The port numbers (any option called "PORT") will be | ||
5780 | * adjusted to ensure that no two peers running on the same system | ||
5781 | * have the same port(s) in their respective configurations. | ||
5782 | * | ||
5783 | * @param cfg configuration template to use | ||
5784 | * @param total number of daemons to start | ||
5785 | * @param max_concurrent_connections for testing, how many peers can | ||
5786 | * we connect to simultaneously | ||
5787 | * @param max_concurrent_ssh when starting with ssh, how many ssh | ||
5788 | * connections will we allow at once (based on remote hosts allowed!) | ||
5789 | * @param timeout total time allowed for peers to start | ||
5790 | * @param hostkey_callback function to call on each peers hostkey generation | ||
5791 | * if NULL, peers will be started by this call, if non-null, | ||
5792 | * GNUNET_TESTING_daemons_continue_startup must be called after | ||
5793 | * successful hostkey generation | ||
5794 | * @param hostkey_cls closure for hostkey callback | ||
5795 | * @param cb function to call on each daemon that was started | ||
5796 | * @param cb_cls closure for cb | ||
5797 | * @param connect_callback function to call each time two hosts are connected | ||
5798 | * @param connect_callback_cls closure for connect_callback | ||
5799 | * @param hostnames linked list of host structs to use to start peers on | ||
5800 | * (NULL to run on localhost only) | ||
5801 | * | ||
5802 | * @return NULL on error, otherwise handle to control peer group | ||
5803 | */ | ||
5804 | struct GNUNET_TESTING_PeerGroup * | ||
5805 | GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
5806 | unsigned int total, | ||
5807 | unsigned int max_concurrent_connections, | ||
5808 | unsigned int max_concurrent_ssh, | ||
5809 | struct GNUNET_TIME_Relative timeout, | ||
5810 | GNUNET_TESTING_NotifyHostkeyCreated | ||
5811 | hostkey_callback, void *hostkey_cls, | ||
5812 | GNUNET_TESTING_NotifyDaemonRunning cb, | ||
5813 | void *cb_cls, | ||
5814 | GNUNET_TESTING_NotifyConnection connect_callback, | ||
5815 | void *connect_callback_cls, | ||
5816 | const struct GNUNET_TESTING_Host *hostnames) | ||
5817 | { | ||
5818 | struct GNUNET_TESTING_PeerGroup *pg; | ||
5819 | const struct GNUNET_TESTING_Host *hostpos; | ||
5820 | const char *hostname; | ||
5821 | const char *username; | ||
5822 | char *baseservicehome; | ||
5823 | char *newservicehome; | ||
5824 | char *tmpdir; | ||
5825 | char *hostkeys_file; | ||
5826 | char *arg; | ||
5827 | char *ssh_port_str; | ||
5828 | struct GNUNET_DISK_FileHandle *fd; | ||
5829 | struct GNUNET_CONFIGURATION_Handle *pcfg; | ||
5830 | unsigned int off; | ||
5831 | struct OutstandingSSH *ssh_entry; | ||
5832 | unsigned int hostcnt; | ||
5833 | unsigned int i; | ||
5834 | uint16_t minport; | ||
5835 | uint16_t sshport; | ||
5836 | uint32_t upnum; | ||
5837 | uint32_t fdnum; | ||
5838 | uint64_t fs; | ||
5839 | uint64_t total_hostkeys; | ||
5840 | struct GNUNET_OS_Process *proc; | ||
5841 | |||
5842 | username = NULL; | ||
5843 | if (0 == total) | ||
5844 | { | ||
5845 | GNUNET_break (0); | ||
5846 | return NULL; | ||
5847 | } | ||
5848 | |||
5849 | upnum = 0; | ||
5850 | fdnum = 0; | ||
5851 | pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup)); | ||
5852 | pg->cfg = cfg; | ||
5853 | pg->notify_connection = connect_callback; | ||
5854 | pg->notify_connection_cls = connect_callback_cls; | ||
5855 | pg->total = total; | ||
5856 | pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
5857 | pg->peers = GNUNET_malloc (total * sizeof (struct PeerData)); | ||
5858 | pg->max_outstanding_connections = max_concurrent_connections; | ||
5859 | pg->max_concurrent_ssh = max_concurrent_ssh; | ||
5860 | if (NULL != hostnames) | ||
5861 | { | ||
5862 | off = 0; | ||
5863 | hostpos = hostnames; | ||
5864 | while (hostpos != NULL) | ||
5865 | { | ||
5866 | hostpos = hostpos->next; | ||
5867 | off++; | ||
5868 | } | ||
5869 | pg->hosts = GNUNET_malloc (off * sizeof (struct HostData)); | ||
5870 | off = 0; | ||
5871 | |||
5872 | hostpos = hostnames; | ||
5873 | while (hostpos != NULL) | ||
5874 | { | ||
5875 | pg->hosts[off].minport = LOW_PORT; | ||
5876 | pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname); | ||
5877 | if (hostpos->username != NULL) | ||
5878 | pg->hosts[off].username = GNUNET_strdup (hostpos->username); | ||
5879 | pg->hosts[off].sshport = hostpos->port; | ||
5880 | hostpos = hostpos->next; | ||
5881 | off++; | ||
5882 | } | ||
5883 | |||
5884 | if (off == 0) | ||
5885 | { | ||
5886 | pg->hosts = NULL; | ||
5887 | } | ||
5888 | hostcnt = off; | ||
5889 | minport = 0; | ||
5890 | pg->num_hosts = off; | ||
5891 | } | ||
5892 | else | ||
5893 | { | ||
5894 | hostcnt = 0; | ||
5895 | minport = LOW_PORT; | ||
5896 | } | ||
5897 | |||
5898 | /* Create the servicehome directory for each remote peer */ | ||
5899 | GNUNET_assert (GNUNET_OK == | ||
5900 | GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", | ||
5901 | "SERVICEHOME", | ||
5902 | &baseservicehome)); | ||
5903 | for (i = 0; i < pg->num_hosts; i++) | ||
5904 | { | ||
5905 | ssh_entry = GNUNET_malloc (sizeof (struct OutstandingSSH)); | ||
5906 | ssh_entry->hostname = pg->hosts[i].hostname; /* Don't free! */ | ||
5907 | GNUNET_CONTAINER_DLL_insert (pg->ssh_head, pg->ssh_tail, ssh_entry); | ||
5908 | GNUNET_asprintf (&tmpdir, "%s/%s", baseservicehome, pg->hosts[i].hostname); | ||
5909 | if (NULL != pg->hosts[i].username) | ||
5910 | GNUNET_asprintf (&arg, "%s@%s", pg->hosts[i].username, | ||
5911 | pg->hosts[i].hostname); | ||
5912 | else | ||
5913 | GNUNET_asprintf (&arg, "%s", pg->hosts[i].hostname); | ||
5914 | if (pg->hosts[i].sshport != 0) | ||
5915 | { | ||
5916 | GNUNET_asprintf (&ssh_port_str, "%d", pg->hosts[i].sshport); | ||
5917 | proc = | ||
5918 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", "-P", ssh_port_str, | ||
5919 | "-q", | ||
5920 | arg, "mkdir -p", tmpdir, NULL); | ||
5921 | } | ||
5922 | else | ||
5923 | proc = | ||
5924 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "ssh", "ssh", arg, "mkdir -p", | ||
5925 | tmpdir, NULL); | ||
5926 | GNUNET_assert (proc != NULL); | ||
5927 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5928 | "Creating remote dir with command ssh %s %s %s\n", arg, | ||
5929 | " mkdir -p ", tmpdir); | ||
5930 | GNUNET_free (tmpdir); | ||
5931 | GNUNET_free (arg); | ||
5932 | GNUNET_OS_process_wait (proc); | ||
5933 | GNUNET_OS_process_destroy (proc); | ||
5934 | } | ||
5935 | GNUNET_free (baseservicehome); | ||
5936 | baseservicehome = NULL; | ||
5937 | |||
5938 | if (GNUNET_YES == | ||
5939 | GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "HOSTKEYSFILE", | ||
5940 | &hostkeys_file)) | ||
5941 | { | ||
5942 | if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file)) | ||
5943 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
5944 | _("Could not read hostkeys file!\n")); | ||
5945 | else | ||
5946 | { | ||
5947 | /* Check hostkey file size, read entire thing into memory */ | ||
5948 | fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ, | ||
5949 | GNUNET_DISK_PERM_NONE); | ||
5950 | if (NULL == fd) | ||
5951 | { | ||
5952 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", | ||
5953 | hostkeys_file); | ||
5954 | GNUNET_free (hostkeys_file); | ||
5955 | for (i = 0; i < pg->num_hosts; i++) | ||
5956 | { | ||
5957 | GNUNET_free (pg->hosts[i].hostname); | ||
5958 | GNUNET_free_non_null (pg->hosts[i].username); | ||
5959 | } | ||
5960 | GNUNET_free (pg->peers); | ||
5961 | GNUNET_free (pg->hosts); | ||
5962 | GNUNET_free (pg); | ||
5963 | return NULL; | ||
5964 | } | ||
5965 | |||
5966 | if (GNUNET_OK != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES, GNUNET_YES)) | ||
5967 | fs = 0; | ||
5968 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5969 | "Found file size %llu for hostkeys\n", fs); | ||
5970 | if (0 != (fs % HOSTKEYFILESIZE)) | ||
5971 | { | ||
5972 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
5973 | "File size %llu seems incorrect for hostkeys...\n", fs); | ||
5974 | } | ||
5975 | else | ||
5976 | { | ||
5977 | total_hostkeys = fs / HOSTKEYFILESIZE; | ||
5978 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
5979 | "Will read %llu hostkeys from file\n", total_hostkeys); | ||
5980 | pg->hostkey_data = GNUNET_malloc_large (fs); | ||
5981 | GNUNET_assert (fs == GNUNET_DISK_file_read (fd, pg->hostkey_data, fs)); | ||
5982 | } | ||
5983 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); | ||
5984 | } | ||
5985 | GNUNET_free (hostkeys_file); | ||
5986 | } | ||
5987 | |||
5988 | for (off = 0; off < total; off++) | ||
5989 | { | ||
5990 | if (hostcnt > 0) | ||
5991 | { | ||
5992 | hostname = pg->hosts[off % hostcnt].hostname; | ||
5993 | username = pg->hosts[off % hostcnt].username; | ||
5994 | sshport = pg->hosts[off % hostcnt].sshport; | ||
5995 | pcfg = | ||
5996 | GNUNET_TESTING_create_cfg (cfg, off, &pg->hosts[off % hostcnt].minport, &upnum, | ||
5997 | hostname, &fdnum); | ||
5998 | } | ||
5999 | else | ||
6000 | { | ||
6001 | hostname = NULL; | ||
6002 | username = NULL; | ||
6003 | sshport = 0; | ||
6004 | pcfg = GNUNET_TESTING_create_cfg (cfg, off, &minport, &upnum, hostname, &fdnum); | ||
6005 | } | ||
6006 | |||
6007 | if (NULL == pcfg) | ||
6008 | { | ||
6009 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
6010 | _ | ||
6011 | ("Could not create configuration for peer number %u on `%s'!\n"), | ||
6012 | off, hostname == NULL ? "localhost" : hostname); | ||
6013 | continue; | ||
6014 | } | ||
6015 | |||
6016 | if (GNUNET_YES == | ||
6017 | GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME", | ||
6018 | &baseservicehome)) | ||
6019 | { | ||
6020 | if (hostname != NULL) | ||
6021 | GNUNET_asprintf (&newservicehome, "%s/%s/%d/", baseservicehome, | ||
6022 | hostname, off); | ||
6023 | else | ||
6024 | GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off); | ||
6025 | GNUNET_free (baseservicehome); | ||
6026 | baseservicehome = NULL; | ||
6027 | } | ||
6028 | else | ||
6029 | { | ||
6030 | tmpdir = getenv ("TMPDIR"); | ||
6031 | tmpdir = tmpdir ? tmpdir : "/tmp"; | ||
6032 | if (hostname != NULL) | ||
6033 | GNUNET_asprintf (&newservicehome, "%s/%s/%s/%d/", tmpdir, hostname, | ||
6034 | "gnunet-testing-test-test", off); | ||
6035 | else | ||
6036 | GNUNET_asprintf (&newservicehome, "%s/%s/%d/", tmpdir, | ||
6037 | "gnunet-testing-test-test", off); | ||
6038 | } | ||
6039 | GNUNET_CONFIGURATION_set_value_string (pcfg, "PATHS", "SERVICEHOME", | ||
6040 | newservicehome); | ||
6041 | GNUNET_free (newservicehome); | ||
6042 | pg->peers[off].cfg = pcfg; | ||
6043 | pg->peers[off].pg = pg; | ||
6044 | pg->peers[off].internal_context.peer = &pg->peers[off]; | ||
6045 | pg->peers[off].internal_context.timeout = timeout; | ||
6046 | pg->peers[off].internal_context.hostname = hostname; | ||
6047 | pg->peers[off].internal_context.username = username; | ||
6048 | pg->peers[off].internal_context.sshport = sshport; | ||
6049 | if (pg->hostkey_data != NULL) | ||
6050 | pg->peers[off].internal_context.hostkey = | ||
6051 | &pg->hostkey_data[off * HOSTKEYFILESIZE]; | ||
6052 | pg->peers[off].internal_context.hostkey_callback = hostkey_callback; | ||
6053 | pg->peers[off].internal_context.hostkey_cls = hostkey_cls; | ||
6054 | pg->peers[off].internal_context.start_cb = cb; | ||
6055 | pg->peers[off].internal_context.start_cb_cls = cb_cls; | ||
6056 | #if !USE_START_HELPER | ||
6057 | GNUNET_SCHEDULER_add_now (&internal_start, | ||
6058 | &pg->peers[off].internal_context); | ||
6059 | #else | ||
6060 | if ((pg->hostkey_data != NULL) && (hostcnt > 0)) | ||
6061 | { | ||
6062 | pg->peers[off].daemon = | ||
6063 | GNUNET_TESTING_daemon_start (pcfg, timeout, GNUNET_YES, hostname, | ||
6064 | username, sshport, | ||
6065 | pg->peers[off].internal_context.hostkey, | ||
6066 | &internal_hostkey_callback, | ||
6067 | &pg->peers[off].internal_context, | ||
6068 | &internal_startup_callback, | ||
6069 | &pg->peers[off].internal_context); | ||
6070 | /** | ||
6071 | * At this point, given that we had a hostkeyfile, | ||
6072 | * we can call the hostkey callback! | ||
6073 | * But first, we should copy (rsync) all of the configs | ||
6074 | * and hostkeys to the remote peers. Then let topology | ||
6075 | * creation happen, then call the peer start helper processes, | ||
6076 | * then set pg->whatever_phase for each peer and let them | ||
6077 | * enter the fsm to get the HELLO's for peers and start connecting. | ||
6078 | */ | ||
6079 | } | ||
6080 | else | ||
6081 | { | ||
6082 | GNUNET_SCHEDULER_add_now (&internal_start, | ||
6083 | &pg->peers[off].internal_context); | ||
6084 | } | ||
6085 | |||
6086 | #endif | ||
6087 | } | ||
6088 | |||
6089 | #if USE_START_HELPER /* Now the peergroup has been set up, hostkeys and configs written to files. */ | ||
6090 | if ((pg->hostkey_data != NULL) && (hostcnt > 0)) | ||
6091 | { | ||
6092 | for (off = 0; off < hostcnt; off++) | ||
6093 | { | ||
6094 | |||
6095 | if (hostcnt > 0) | ||
6096 | { | ||
6097 | hostname = pg->hosts[off % hostcnt].hostname; | ||
6098 | username = pg->hosts[off % hostcnt].username; | ||
6099 | sshport = pg->hosts[off % hostcnt].sshport; | ||
6100 | } | ||
6101 | else | ||
6102 | { | ||
6103 | hostname = NULL; | ||
6104 | username = NULL; | ||
6105 | sshport = 0; | ||
6106 | } | ||
6107 | |||
6108 | if (GNUNET_YES == | ||
6109 | GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS", "SERVICEHOME", | ||
6110 | &baseservicehome)) | ||
6111 | { | ||
6112 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "baseservice home is %s\n", | ||
6113 | baseservicehome); | ||
6114 | if (hostname != NULL) | ||
6115 | GNUNET_asprintf (&newservicehome, "%s/%s/", baseservicehome, | ||
6116 | hostname); | ||
6117 | else | ||
6118 | GNUNET_asprintf (&newservicehome, "%s/", baseservicehome); | ||
6119 | GNUNET_free (baseservicehome); | ||
6120 | baseservicehome = NULL; | ||
6121 | } | ||
6122 | else | ||
6123 | { | ||
6124 | tmpdir = getenv ("TMPDIR"); | ||
6125 | tmpdir = tmpdir ? tmpdir : "/tmp"; | ||
6126 | if (hostname != NULL) | ||
6127 | GNUNET_asprintf (&newservicehome, "%s/%s/%s/", tmpdir, hostname, | ||
6128 | "gnunet-testing-test-test"); | ||
6129 | else | ||
6130 | GNUNET_asprintf (&newservicehome, "%s/%s/", tmpdir, | ||
6131 | "gnunet-testing-test-test", off); | ||
6132 | } | ||
6133 | |||
6134 | if (NULL != username) | ||
6135 | GNUNET_asprintf (&arg, "%s@%s:%s", username, pg->hosts[off].hostname, | ||
6136 | newservicehome); | ||
6137 | else | ||
6138 | GNUNET_asprintf (&arg, "%s:%s", pg->hosts[off].hostname, | ||
6139 | newservicehome); | ||
6140 | |||
6141 | /* FIXME: Doesn't support ssh_port option! */ | ||
6142 | proc = | ||
6143 | GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "rsync", "rsync", "-r", | ||
6144 | newservicehome, arg, NULL); | ||
6145 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
6146 | "copying directory with command rsync -r %s %s\n", | ||
6147 | newservicehome, arg); | ||
6148 | GNUNET_free (newservicehome); | ||
6149 | GNUNET_free (arg); | ||
6150 | if (NULL == proc) | ||
6151 | { | ||
6152 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
6153 | _ | ||
6154 | ("Could not start `%s' process to copy configuration directory.\n"), | ||
6155 | "scp"); | ||
6156 | GNUNET_assert (0); | ||
6157 | } | ||
6158 | GNUNET_OS_process_wait (proc); | ||
6159 | GNUNET_OS_process_destroy (proc); | ||
6160 | } | ||
6161 | /* Now all the configuration files and hostkeys are copied to the remote host. Call the hostkey callback for each peer! */ | ||
6162 | GNUNET_SCHEDULER_add_now (&call_hostkey_callbacks, pg); | ||
6163 | } | ||
6164 | #endif | ||
6165 | return pg; | ||
6166 | } | ||
6167 | |||
6168 | /* | ||
6169 | * Get a daemon by number, so callers don't have to do nasty | ||
6170 | * offsetting operation. | ||
6171 | */ | ||
6172 | struct GNUNET_TESTING_Daemon * | ||
6173 | GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, | ||
6174 | unsigned int position) | ||
6175 | { | ||
6176 | if (position < pg->total) | ||
6177 | return pg->peers[position].daemon; | ||
6178 | return NULL; | ||
6179 | } | ||
6180 | |||
6181 | /* | ||
6182 | * Get a daemon by peer identity, so callers can | ||
6183 | * retrieve the daemon without knowing it's offset. | ||
6184 | * | ||
6185 | * @param pg the peer group to retrieve the daemon from | ||
6186 | * @param peer_id the peer identity of the daemon to retrieve | ||
6187 | * | ||
6188 | * @return the daemon on success, or NULL if no such peer identity is found | ||
6189 | */ | ||
6190 | struct GNUNET_TESTING_Daemon * | ||
6191 | GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, | ||
6192 | const struct GNUNET_PeerIdentity *peer_id) | ||
6193 | { | ||
6194 | unsigned int i; | ||
6195 | |||
6196 | for (i = 0; i < pg->total; i++) | ||
6197 | { | ||
6198 | if (0 == | ||
6199 | memcmp (&pg->peers[i].daemon->id, peer_id, | ||
6200 | sizeof (struct GNUNET_PeerIdentity))) | ||
6201 | return pg->peers[i].daemon; | ||
6202 | } | ||
6203 | return NULL; | ||
6204 | } | ||
6205 | |||
6206 | /** | ||
6207 | * Prototype of a function that will be called when a | ||
6208 | * particular operation was completed the testing library. | ||
6209 | * | ||
6210 | * @param cls closure (a struct RestartContext) | ||
6211 | * @param id id of the peer that was restarted | ||
6212 | * @param cfg handle to the configuration of the peer | ||
6213 | * @param d handle to the daemon that was restarted | ||
6214 | * @param emsg NULL on success | ||
6215 | */ | ||
6216 | static void | ||
6217 | restart_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
6218 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
6219 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
6220 | { | ||
6221 | struct RestartContext *restart_context = cls; | ||
6222 | |||
6223 | if (emsg == NULL) | ||
6224 | { | ||
6225 | restart_context->peers_restarted++; | ||
6226 | } | ||
6227 | else | ||
6228 | { | ||
6229 | restart_context->peers_restart_failed++; | ||
6230 | } | ||
6231 | |||
6232 | if (restart_context->peers_restarted == restart_context->peer_group->total) | ||
6233 | { | ||
6234 | restart_context->callback (restart_context->callback_cls, NULL); | ||
6235 | GNUNET_free (restart_context); | ||
6236 | } | ||
6237 | else if (restart_context->peers_restart_failed + | ||
6238 | restart_context->peers_restarted == | ||
6239 | restart_context->peer_group->total) | ||
6240 | { | ||
6241 | restart_context->callback (restart_context->callback_cls, | ||
6242 | "Failed to restart peers!"); | ||
6243 | GNUNET_free (restart_context); | ||
6244 | } | ||
6245 | |||
6246 | } | ||
6247 | |||
6248 | /** | ||
6249 | * Callback for informing us about a successful | ||
6250 | * or unsuccessful churn stop call. | ||
6251 | * | ||
6252 | * @param cls a ChurnContext | ||
6253 | * @param emsg NULL on success, non-NULL on failure | ||
6254 | * | ||
6255 | */ | ||
6256 | static void | ||
6257 | churn_stop_callback (void *cls, const char *emsg) | ||
6258 | { | ||
6259 | struct ShutdownContext *shutdown_ctx = cls; | ||
6260 | struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls; | ||
6261 | unsigned int total_left; | ||
6262 | char *error_message; | ||
6263 | |||
6264 | error_message = NULL; | ||
6265 | shutdown_ctx->outstanding--; | ||
6266 | |||
6267 | if (emsg != NULL) | ||
6268 | { | ||
6269 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
6270 | "Churn stop callback failed with error `%s'\n", emsg); | ||
6271 | churn_ctx->num_failed_stop++; | ||
6272 | } | ||
6273 | else | ||
6274 | { | ||
6275 | churn_ctx->num_to_stop--; | ||
6276 | } | ||
6277 | |||
6278 | total_left = | ||
6279 | (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + | ||
6280 | (churn_ctx->num_to_start - churn_ctx->num_failed_start); | ||
6281 | |||
6282 | if (total_left == 0) | ||
6283 | { | ||
6284 | if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0)) | ||
6285 | { | ||
6286 | GNUNET_asprintf (&error_message, | ||
6287 | "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", | ||
6288 | churn_ctx->num_failed_start, churn_ctx->num_failed_stop); | ||
6289 | } | ||
6290 | churn_ctx->cb (churn_ctx->cb_cls, error_message); | ||
6291 | GNUNET_free_non_null (error_message); | ||
6292 | GNUNET_free (churn_ctx); | ||
6293 | GNUNET_free (shutdown_ctx); | ||
6294 | } | ||
6295 | } | ||
6296 | |||
6297 | /** | ||
6298 | * Count the number of running peers. | ||
6299 | * | ||
6300 | * @param pg handle for the peer group | ||
6301 | * | ||
6302 | * @return the number of currently running peers in the peer group | ||
6303 | */ | ||
6304 | unsigned int | ||
6305 | GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg) | ||
6306 | { | ||
6307 | unsigned int i; | ||
6308 | unsigned int running = 0; | ||
6309 | |||
6310 | for (i = 0; i < pg->total; i++) | ||
6311 | { | ||
6312 | if (pg->peers[i].daemon->running == GNUNET_YES) | ||
6313 | { | ||
6314 | GNUNET_assert (running != -1); | ||
6315 | running++; | ||
6316 | } | ||
6317 | } | ||
6318 | return running; | ||
6319 | } | ||
6320 | |||
6321 | /** | ||
6322 | * Task to rate limit the number of outstanding peer shutdown | ||
6323 | * requests. This is necessary for making sure we don't do | ||
6324 | * too many ssh connections at once, but is generally nicer | ||
6325 | * to any system as well (graduated task starts, as opposed | ||
6326 | * to calling gnunet-arm N times all at once). | ||
6327 | */ | ||
6328 | static void | ||
6329 | schedule_churn_shutdown_task (void *cls, | ||
6330 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
6331 | { | ||
6332 | struct PeerShutdownContext *peer_shutdown_ctx = cls; | ||
6333 | struct ShutdownContext *shutdown_ctx; | ||
6334 | struct ChurnContext *churn_ctx; | ||
6335 | |||
6336 | GNUNET_assert (peer_shutdown_ctx != NULL); | ||
6337 | shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; | ||
6338 | GNUNET_assert (shutdown_ctx != NULL); | ||
6339 | churn_ctx = (struct ChurnContext *) shutdown_ctx->cb_cls; | ||
6340 | if (shutdown_ctx->outstanding > churn_ctx->pg->max_concurrent_ssh) | ||
6341 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
6342 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
6343 | &schedule_churn_shutdown_task, | ||
6344 | peer_shutdown_ctx); | ||
6345 | else | ||
6346 | { | ||
6347 | shutdown_ctx->outstanding++; | ||
6348 | if (churn_ctx->service != NULL) | ||
6349 | GNUNET_TESTING_daemon_stop_service (peer_shutdown_ctx->daemon, | ||
6350 | churn_ctx->service, | ||
6351 | shutdown_ctx->timeout, | ||
6352 | shutdown_ctx->cb, shutdown_ctx); | ||
6353 | else | ||
6354 | GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, | ||
6355 | shutdown_ctx->timeout, shutdown_ctx->cb, | ||
6356 | shutdown_ctx, GNUNET_NO, GNUNET_YES); | ||
6357 | GNUNET_free (peer_shutdown_ctx); | ||
6358 | } | ||
6359 | } | ||
6360 | |||
6361 | |||
6362 | /** | ||
6363 | * Simulate churn by stopping some peers (and possibly | ||
6364 | * re-starting others if churn is called multiple times). This | ||
6365 | * function can only be used to create leave-join churn (peers "never" | ||
6366 | * leave for good). First "voff" random peers that are currently | ||
6367 | * online will be taken offline; then "von" random peers that are then | ||
6368 | * offline will be put back online. No notifications will be | ||
6369 | * generated for any of these operations except for the callback upon | ||
6370 | * completion. | ||
6371 | * | ||
6372 | * @param pg handle for the peer group | ||
6373 | * @param service the service to churn off/on, NULL to churn peer | ||
6374 | * @param voff number of peers that should go offline | ||
6375 | * @param von number of peers that should come back online; | ||
6376 | * must be zero on first call (since "testbed_start" | ||
6377 | * always starts all of the peers) | ||
6378 | * @param timeout how long to wait for operations to finish before | ||
6379 | * giving up | ||
6380 | * @param cb function to call at the end | ||
6381 | * @param cb_cls closure for cb | ||
6382 | */ | ||
6383 | void | ||
6384 | GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, | ||
6385 | char *service, unsigned int voff, | ||
6386 | unsigned int von, | ||
6387 | struct GNUNET_TIME_Relative timeout, | ||
6388 | GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) | ||
6389 | { | ||
6390 | struct ChurnContext *churn_ctx; | ||
6391 | struct ShutdownContext *shutdown_ctx; | ||
6392 | struct PeerShutdownContext *peer_shutdown_ctx; | ||
6393 | struct PeerRestartContext *peer_restart_ctx; | ||
6394 | struct ChurnRestartContext *churn_startup_ctx; | ||
6395 | |||
6396 | unsigned int running; | ||
6397 | unsigned int stopped; | ||
6398 | unsigned int total_running; | ||
6399 | unsigned int total_stopped; | ||
6400 | unsigned int i; | ||
6401 | unsigned int *running_arr; | ||
6402 | unsigned int *stopped_arr; | ||
6403 | unsigned int *running_permute; | ||
6404 | unsigned int *stopped_permute; | ||
6405 | char *pos; | ||
6406 | |||
6407 | shutdown_ctx = NULL; | ||
6408 | peer_shutdown_ctx = NULL; | ||
6409 | peer_restart_ctx = NULL; | ||
6410 | churn_startup_ctx = NULL; | ||
6411 | |||
6412 | running = 0; | ||
6413 | stopped = 0; | ||
6414 | |||
6415 | if ((von == 0) && (voff == 0)) /* No peers at all? */ | ||
6416 | { | ||
6417 | cb (cb_cls, NULL); | ||
6418 | return; | ||
6419 | } | ||
6420 | |||
6421 | for (i = 0; i < pg->total; i++) | ||
6422 | { | ||
6423 | if (service == NULL) | ||
6424 | { | ||
6425 | if (pg->peers[i].daemon->running == GNUNET_YES) | ||
6426 | { | ||
6427 | GNUNET_assert (running != -1); | ||
6428 | running++; | ||
6429 | } | ||
6430 | else | ||
6431 | { | ||
6432 | GNUNET_assert (stopped != -1); | ||
6433 | stopped++; | ||
6434 | } | ||
6435 | } | ||
6436 | else | ||
6437 | { | ||
6438 | /* FIXME: make churned services a list! */ | ||
6439 | pos = pg->peers[i].daemon->churned_services; | ||
6440 | /* FIXME: while (pos != NULL) */ | ||
6441 | if (pos != NULL) | ||
6442 | { | ||
6443 | #if FIXME | ||
6444 | if (0 == strcasecmp (pos, service)) | ||
6445 | { | ||
6446 | |||
6447 | break; | ||
6448 | } | ||
6449 | #endif | ||
6450 | GNUNET_assert (stopped != -1); | ||
6451 | stopped++; | ||
6452 | /* FIXME: pos = pos->next; */ | ||
6453 | } | ||
6454 | if (pos == NULL) | ||
6455 | { | ||
6456 | GNUNET_assert (running != -1); | ||
6457 | running++; | ||
6458 | } | ||
6459 | } | ||
6460 | } | ||
6461 | |||
6462 | if (voff > running) | ||
6463 | { | ||
6464 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
6465 | "Trying to stop more peers (%d) than are currently running (%d)!\n", | ||
6466 | voff, running); | ||
6467 | cb (cb_cls, "Trying to stop more peers than are currently running!"); | ||
6468 | return; | ||
6469 | } | ||
6470 | |||
6471 | if (von > stopped) | ||
6472 | { | ||
6473 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
6474 | "Trying to start more peers (%d) than are currently stopped (%d)!\n", | ||
6475 | von, stopped); | ||
6476 | cb (cb_cls, "Trying to start more peers than are currently stopped!"); | ||
6477 | return; | ||
6478 | } | ||
6479 | |||
6480 | churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); | ||
6481 | |||
6482 | if (service != NULL) | ||
6483 | churn_ctx->service = GNUNET_strdup (service); | ||
6484 | running_arr = NULL; | ||
6485 | if (running > 0) | ||
6486 | running_arr = GNUNET_malloc (running * sizeof (unsigned int)); | ||
6487 | |||
6488 | stopped_arr = NULL; | ||
6489 | if (stopped > 0) | ||
6490 | stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int)); | ||
6491 | |||
6492 | running_permute = NULL; | ||
6493 | stopped_permute = NULL; | ||
6494 | |||
6495 | if (running > 0) | ||
6496 | running_permute = | ||
6497 | GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, running); | ||
6498 | if (stopped > 0) | ||
6499 | stopped_permute = | ||
6500 | GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, stopped); | ||
6501 | |||
6502 | total_running = running; | ||
6503 | total_stopped = stopped; | ||
6504 | running = 0; | ||
6505 | stopped = 0; | ||
6506 | |||
6507 | churn_ctx->num_to_start = von; | ||
6508 | churn_ctx->num_to_stop = voff; | ||
6509 | churn_ctx->cb = cb; | ||
6510 | churn_ctx->cb_cls = cb_cls; | ||
6511 | churn_ctx->pg = pg; | ||
6512 | |||
6513 | for (i = 0; i < pg->total; i++) | ||
6514 | { | ||
6515 | if (service == NULL) | ||
6516 | { | ||
6517 | if (pg->peers[i].daemon->running == GNUNET_YES) | ||
6518 | { | ||
6519 | GNUNET_assert ((running_arr != NULL) && (total_running > running)); | ||
6520 | running_arr[running] = i; | ||
6521 | running++; | ||
6522 | } | ||
6523 | else | ||
6524 | { | ||
6525 | GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); | ||
6526 | stopped_arr[stopped] = i; | ||
6527 | stopped++; | ||
6528 | } | ||
6529 | } | ||
6530 | else | ||
6531 | { | ||
6532 | /* FIXME: make churned services a list! */ | ||
6533 | pos = pg->peers[i].daemon->churned_services; | ||
6534 | /* FIXME: while (pos != NULL) */ | ||
6535 | if (pos != NULL) | ||
6536 | { | ||
6537 | GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped)); | ||
6538 | stopped_arr[stopped] = i; | ||
6539 | stopped++; | ||
6540 | /* FIXME: pos = pos->next; */ | ||
6541 | } | ||
6542 | if (pos == NULL) | ||
6543 | { | ||
6544 | GNUNET_assert ((running_arr != NULL) && (total_running > running)); | ||
6545 | running_arr[running] = i; | ||
6546 | running++; | ||
6547 | } | ||
6548 | } | ||
6549 | } | ||
6550 | |||
6551 | GNUNET_assert (running >= voff); | ||
6552 | if (voff > 0) | ||
6553 | { | ||
6554 | shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); | ||
6555 | shutdown_ctx->cb = &churn_stop_callback; | ||
6556 | shutdown_ctx->cb_cls = churn_ctx; | ||
6557 | shutdown_ctx->total_peers = voff; | ||
6558 | shutdown_ctx->timeout = timeout; | ||
6559 | } | ||
6560 | |||
6561 | for (i = 0; i < voff; i++) | ||
6562 | { | ||
6563 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peer %d!\n", | ||
6564 | running_arr[running_permute[i]]); | ||
6565 | GNUNET_assert (running_arr != NULL); | ||
6566 | peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); | ||
6567 | peer_shutdown_ctx->daemon = | ||
6568 | pg->peers[running_arr[running_permute[i]]].daemon; | ||
6569 | peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; | ||
6570 | GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task, peer_shutdown_ctx); | ||
6571 | } | ||
6572 | |||
6573 | GNUNET_assert (stopped >= von); | ||
6574 | if (von > 0) | ||
6575 | { | ||
6576 | churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); | ||
6577 | churn_startup_ctx->churn_ctx = churn_ctx; | ||
6578 | churn_startup_ctx->timeout = timeout; | ||
6579 | churn_startup_ctx->pg = pg; | ||
6580 | } | ||
6581 | for (i = 0; i < von; i++) | ||
6582 | { | ||
6583 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting up peer %d!\n", | ||
6584 | stopped_arr[stopped_permute[i]]); | ||
6585 | GNUNET_assert (stopped_arr != NULL); | ||
6586 | peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext)); | ||
6587 | peer_restart_ctx->churn_restart_ctx = churn_startup_ctx; | ||
6588 | peer_restart_ctx->daemon = | ||
6589 | pg->peers[stopped_arr[stopped_permute[i]]].daemon; | ||
6590 | GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx); | ||
6591 | } | ||
6592 | |||
6593 | GNUNET_free_non_null (running_arr); | ||
6594 | GNUNET_free_non_null (stopped_arr); | ||
6595 | GNUNET_free_non_null (running_permute); | ||
6596 | GNUNET_free_non_null (stopped_permute); | ||
6597 | } | ||
6598 | |||
6599 | /* | ||
6600 | * Start a given service for each of the peers in the peer group. | ||
6601 | * | ||
6602 | * @param pg handle for the peer group | ||
6603 | * @param service the service to start | ||
6604 | * @param timeout how long to wait for operations to finish before | ||
6605 | * giving up | ||
6606 | * @param cb function to call once finished | ||
6607 | * @param cb_cls closure for cb | ||
6608 | * | ||
6609 | */ | ||
6610 | void | ||
6611 | GNUNET_TESTING_daemons_start_service (struct GNUNET_TESTING_PeerGroup *pg, | ||
6612 | char *service, | ||
6613 | struct GNUNET_TIME_Relative timeout, | ||
6614 | GNUNET_TESTING_NotifyCompletion cb, | ||
6615 | void *cb_cls) | ||
6616 | { | ||
6617 | struct ServiceStartContext *start_ctx; | ||
6618 | struct PeerServiceStartContext *peer_start_ctx; | ||
6619 | unsigned int i; | ||
6620 | |||
6621 | GNUNET_assert (service != NULL); | ||
6622 | |||
6623 | start_ctx = GNUNET_malloc (sizeof (struct ServiceStartContext)); | ||
6624 | start_ctx->pg = pg; | ||
6625 | start_ctx->remaining = pg->total; | ||
6626 | start_ctx->cb = cb; | ||
6627 | start_ctx->cb_cls = cb_cls; | ||
6628 | start_ctx->service = GNUNET_strdup (service); | ||
6629 | start_ctx->timeout = timeout; | ||
6630 | |||
6631 | for (i = 0; i < pg->total; i++) | ||
6632 | { | ||
6633 | peer_start_ctx = GNUNET_malloc (sizeof (struct PeerServiceStartContext)); | ||
6634 | peer_start_ctx->start_ctx = start_ctx; | ||
6635 | peer_start_ctx->daemon = pg->peers[i].daemon; | ||
6636 | GNUNET_SCHEDULER_add_now (&schedule_service_start, peer_start_ctx); | ||
6637 | } | ||
6638 | } | ||
6639 | |||
6640 | /** | ||
6641 | * Restart all peers in the given group. | ||
6642 | * | ||
6643 | * @param pg the handle to the peer group | ||
6644 | * @param callback function to call on completion (or failure) | ||
6645 | * @param callback_cls closure for the callback function | ||
6646 | */ | ||
6647 | void | ||
6648 | GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, | ||
6649 | GNUNET_TESTING_NotifyCompletion callback, | ||
6650 | void *callback_cls) | ||
6651 | { | ||
6652 | struct RestartContext *restart_context; | ||
6653 | unsigned int off; | ||
6654 | |||
6655 | if (pg->total > 0) | ||
6656 | { | ||
6657 | restart_context = GNUNET_malloc (sizeof (struct RestartContext)); | ||
6658 | restart_context->peer_group = pg; | ||
6659 | restart_context->peers_restarted = 0; | ||
6660 | restart_context->callback = callback; | ||
6661 | restart_context->callback_cls = callback_cls; | ||
6662 | |||
6663 | for (off = 0; off < pg->total; off++) | ||
6664 | { | ||
6665 | GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, | ||
6666 | restart_context); | ||
6667 | } | ||
6668 | } | ||
6669 | } | ||
6670 | |||
6671 | |||
6672 | /** | ||
6673 | * Start or stop an individual peer from the given group. | ||
6674 | * | ||
6675 | * @param pg handle to the peer group | ||
6676 | * @param offset which peer to start or stop | ||
6677 | * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it | ||
6678 | * @param timeout how long to wait for shutdown | ||
6679 | * @param cb function to call at the end | ||
6680 | * @param cb_cls closure for cb | ||
6681 | */ | ||
6682 | void | ||
6683 | GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, | ||
6684 | unsigned int offset, int desired_status, | ||
6685 | struct GNUNET_TIME_Relative timeout, | ||
6686 | GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) | ||
6687 | { | ||
6688 | struct ShutdownContext *shutdown_ctx; | ||
6689 | struct ChurnRestartContext *startup_ctx; | ||
6690 | struct ChurnContext *churn_ctx; | ||
6691 | |||
6692 | if (GNUNET_NO == desired_status) | ||
6693 | { | ||
6694 | if (NULL != pg->peers[offset].daemon) | ||
6695 | { | ||
6696 | shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); | ||
6697 | churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); | ||
6698 | churn_ctx->num_to_start = 0; | ||
6699 | churn_ctx->num_to_stop = 1; | ||
6700 | churn_ctx->cb = cb; | ||
6701 | churn_ctx->cb_cls = cb_cls; | ||
6702 | shutdown_ctx->cb_cls = churn_ctx; | ||
6703 | GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon, timeout, | ||
6704 | &churn_stop_callback, shutdown_ctx, GNUNET_NO, | ||
6705 | GNUNET_YES); | ||
6706 | } | ||
6707 | } | ||
6708 | else if (GNUNET_YES == desired_status) | ||
6709 | { | ||
6710 | if (NULL == pg->peers[offset].daemon) | ||
6711 | { | ||
6712 | startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext)); | ||
6713 | churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext)); | ||
6714 | churn_ctx->num_to_start = 1; | ||
6715 | churn_ctx->num_to_stop = 0; | ||
6716 | churn_ctx->cb = cb; | ||
6717 | churn_ctx->cb_cls = cb_cls; | ||
6718 | startup_ctx->churn_ctx = churn_ctx; | ||
6719 | GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon, timeout, | ||
6720 | &churn_start_callback, startup_ctx); | ||
6721 | } | ||
6722 | } | ||
6723 | else | ||
6724 | GNUNET_break (0); | ||
6725 | } | ||
6726 | |||
6727 | |||
6728 | /** | ||
6729 | * Callback for shutting down peers in a peer group. | ||
6730 | * | ||
6731 | * @param cls closure (struct ShutdownContext) | ||
6732 | * @param emsg NULL on success | ||
6733 | */ | ||
6734 | static void | ||
6735 | internal_shutdown_callback (void *cls, const char *emsg) | ||
6736 | { | ||
6737 | struct PeerShutdownContext *peer_shutdown_ctx = cls; | ||
6738 | struct ShutdownContext *shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; | ||
6739 | unsigned int off; | ||
6740 | int i; | ||
6741 | struct OutstandingSSH *ssh_pos; | ||
6742 | |||
6743 | shutdown_ctx->outstanding--; | ||
6744 | if (peer_shutdown_ctx->daemon->hostname != NULL) | ||
6745 | decrement_outstanding_at_host (peer_shutdown_ctx->daemon->hostname, | ||
6746 | shutdown_ctx->pg); | ||
6747 | |||
6748 | if (emsg == NULL) | ||
6749 | { | ||
6750 | shutdown_ctx->peers_down++; | ||
6751 | } | ||
6752 | else | ||
6753 | { | ||
6754 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "internal_shutdown_callback", | ||
6755 | "Failed to stop a peer: %s\n", emsg); | ||
6756 | shutdown_ctx->peers_failed++; | ||
6757 | } | ||
6758 | |||
6759 | if ((shutdown_ctx->cb != NULL) && | ||
6760 | (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == | ||
6761 | shutdown_ctx->total_peers)) | ||
6762 | { | ||
6763 | if (shutdown_ctx->peers_failed > 0) | ||
6764 | shutdown_ctx->cb (shutdown_ctx->cb_cls, | ||
6765 | "Not all peers successfully shut down!"); | ||
6766 | else | ||
6767 | shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL); | ||
6768 | |||
6769 | for (i = 0; i < shutdown_ctx->pg->total; i++) | ||
6770 | { | ||
6771 | if (shutdown_ctx->pg->peers[i].startup_task != GNUNET_SCHEDULER_NO_TASK) | ||
6772 | GNUNET_SCHEDULER_cancel (shutdown_ctx->pg->peers[i].startup_task); | ||
6773 | } | ||
6774 | GNUNET_free (shutdown_ctx->pg->peers); | ||
6775 | GNUNET_free_non_null (shutdown_ctx->pg->hostkey_data); | ||
6776 | for (off = 0; off < shutdown_ctx->pg->num_hosts; off++) | ||
6777 | { | ||
6778 | GNUNET_free (shutdown_ctx->pg->hosts[off].hostname); | ||
6779 | GNUNET_free_non_null (shutdown_ctx->pg->hosts[off].username); | ||
6780 | } | ||
6781 | GNUNET_free_non_null (shutdown_ctx->pg->hosts); | ||
6782 | while (NULL != (ssh_pos = shutdown_ctx->pg->ssh_head)) | ||
6783 | { | ||
6784 | GNUNET_CONTAINER_DLL_remove (shutdown_ctx->pg->ssh_head, | ||
6785 | shutdown_ctx->pg->ssh_tail, ssh_pos); | ||
6786 | GNUNET_free (ssh_pos); | ||
6787 | } | ||
6788 | GNUNET_free (shutdown_ctx->pg); | ||
6789 | GNUNET_free (shutdown_ctx); | ||
6790 | } | ||
6791 | GNUNET_free (peer_shutdown_ctx); | ||
6792 | } | ||
6793 | |||
6794 | |||
6795 | /** | ||
6796 | * Task to rate limit the number of outstanding peer shutdown | ||
6797 | * requests. This is necessary for making sure we don't do | ||
6798 | * too many ssh connections at once, but is generally nicer | ||
6799 | * to any system as well (graduated task starts, as opposed | ||
6800 | * to calling gnunet-arm N times all at once). | ||
6801 | */ | ||
6802 | static void | ||
6803 | schedule_shutdown_task (void *cls, | ||
6804 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
6805 | { | ||
6806 | struct PeerShutdownContext *peer_shutdown_ctx = cls; | ||
6807 | struct ShutdownContext *shutdown_ctx; | ||
6808 | struct GNUNET_TESTING_Daemon *d; | ||
6809 | |||
6810 | GNUNET_assert (peer_shutdown_ctx != NULL); | ||
6811 | d = peer_shutdown_ctx->daemon; | ||
6812 | shutdown_ctx = peer_shutdown_ctx->shutdown_ctx; | ||
6813 | GNUNET_assert (shutdown_ctx != NULL); | ||
6814 | |||
6815 | if ((shutdown_ctx->outstanding < shutdown_ctx->pg->max_concurrent_ssh) || | ||
6816 | ((d->hostname != NULL) && | ||
6817 | (count_outstanding_at_host | ||
6818 | (d->hostname, | ||
6819 | shutdown_ctx->pg) < shutdown_ctx->pg->max_concurrent_ssh))) | ||
6820 | { | ||
6821 | if (d->hostname != NULL) | ||
6822 | increment_outstanding_at_host (d->hostname, | ||
6823 | shutdown_ctx->pg); | ||
6824 | shutdown_ctx->outstanding++; | ||
6825 | GNUNET_TESTING_daemon_stop (d, | ||
6826 | shutdown_ctx->timeout, | ||
6827 | &internal_shutdown_callback, peer_shutdown_ctx, | ||
6828 | shutdown_ctx->delete_files, GNUNET_NO); | ||
6829 | } | ||
6830 | else | ||
6831 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
6832 | (GNUNET_TIME_UNIT_MILLISECONDS, 100), | ||
6833 | &schedule_shutdown_task, peer_shutdown_ctx); | ||
6834 | |||
6835 | } | ||
6836 | |||
6837 | /** | ||
6838 | * Read a testing hosts file based on a configuration. | ||
6839 | * Returns a DLL of hosts (caller must free!) on success | ||
6840 | * or NULL on failure. | ||
6841 | * | ||
6842 | * @param cfg a configuration with a testing section | ||
6843 | * | ||
6844 | * @return DLL of hosts on success, NULL on failure | ||
6845 | */ | ||
6846 | struct GNUNET_TESTING_Host * | ||
6847 | GNUNET_TESTING_hosts_load (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
6848 | { | ||
6849 | struct GNUNET_TESTING_Host *hosts; | ||
6850 | struct GNUNET_TESTING_Host *temphost; | ||
6851 | char *data; | ||
6852 | char *buf; | ||
6853 | char *hostfile; | ||
6854 | struct stat frstat; | ||
6855 | int count; | ||
6856 | int ret; | ||
6857 | |||
6858 | /* Check for a hostfile containing user@host:port triples */ | ||
6859 | if (GNUNET_OK != | ||
6860 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "hostfile", | ||
6861 | &hostfile)) | ||
6862 | return NULL; | ||
6863 | |||
6864 | hosts = NULL; | ||
6865 | temphost = NULL; | ||
6866 | data = NULL; | ||
6867 | if (hostfile != NULL) | ||
6868 | { | ||
6869 | if (GNUNET_OK != GNUNET_DISK_file_test (hostfile)) | ||
6870 | GNUNET_DISK_fn_write (hostfile, NULL, 0, | ||
6871 | GNUNET_DISK_PERM_USER_READ | | ||
6872 | GNUNET_DISK_PERM_USER_WRITE); | ||
6873 | if ((0 != STAT (hostfile, &frstat)) || (frstat.st_size == 0)) | ||
6874 | { | ||
6875 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
6876 | "Could not open file specified for host list, ending test!"); | ||
6877 | GNUNET_free (hostfile); | ||
6878 | return NULL; | ||
6879 | } | ||
6880 | |||
6881 | data = GNUNET_malloc_large (frstat.st_size); | ||
6882 | GNUNET_assert (data != NULL); | ||
6883 | if (frstat.st_size != GNUNET_DISK_fn_read (hostfile, data, frstat.st_size)) | ||
6884 | { | ||
6885 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
6886 | "Could not read file %s specified for host list, ending test!", | ||
6887 | hostfile); | ||
6888 | GNUNET_free (hostfile); | ||
6889 | GNUNET_free (data); | ||
6890 | return NULL; | ||
6891 | } | ||
6892 | |||
6893 | GNUNET_free_non_null (hostfile); | ||
6894 | |||
6895 | buf = data; | ||
6896 | count = 0; | ||
6897 | while (count < frstat.st_size - 1) | ||
6898 | { | ||
6899 | count++; | ||
6900 | if (((data[count] == '\n')) && (buf != &data[count])) | ||
6901 | { | ||
6902 | data[count] = '\0'; | ||
6903 | temphost = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Host)); | ||
6904 | ret = | ||
6905 | SSCANF (buf, "%a[a-zA-Z0-9_]@%a[a-zA-Z0-9.]:%hd", | ||
6906 | &temphost->username, &temphost->hostname, &temphost->port); | ||
6907 | if (3 == ret) | ||
6908 | { | ||
6909 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
6910 | "Successfully read host %s, port %d and user %s from file\n", | ||
6911 | temphost->hostname, temphost->port, temphost->username); | ||
6912 | } | ||
6913 | else | ||
6914 | { | ||
6915 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
6916 | "Error reading line `%s' in hostfile\n", buf); | ||
6917 | GNUNET_free (temphost); | ||
6918 | buf = &data[count + 1]; | ||
6919 | continue; | ||
6920 | } | ||
6921 | temphost->next = hosts; | ||
6922 | hosts = temphost; | ||
6923 | buf = &data[count + 1]; | ||
6924 | } | ||
6925 | else if ((data[count] == '\n') || (data[count] == '\0')) | ||
6926 | buf = &data[count + 1]; | ||
6927 | } | ||
6928 | } | ||
6929 | GNUNET_free_non_null (data); | ||
6930 | |||
6931 | return hosts; | ||
6932 | } | ||
6933 | |||
6934 | /** | ||
6935 | * Shutdown all peers started in the given group. | ||
6936 | * | ||
6937 | * @param pg handle to the peer group | ||
6938 | * @param timeout how long to wait for shutdown | ||
6939 | * @param cb callback to notify upon success or failure | ||
6940 | * @param cb_cls closure for cb | ||
6941 | */ | ||
6942 | void | ||
6943 | GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, | ||
6944 | struct GNUNET_TIME_Relative timeout, | ||
6945 | GNUNET_TESTING_NotifyCompletion cb, void *cb_cls) | ||
6946 | { | ||
6947 | unsigned int off; | ||
6948 | struct ShutdownContext *shutdown_ctx; | ||
6949 | struct PeerShutdownContext *peer_shutdown_ctx; | ||
6950 | |||
6951 | #if OLD | ||
6952 | struct PeerConnection *conn_iter; | ||
6953 | struct PeerConnection *temp_conn; | ||
6954 | #endif | ||
6955 | struct ConnectContext *cc; | ||
6956 | |||
6957 | GNUNET_assert (pg->total > 0); | ||
6958 | while (NULL != (cc = pg->cc_head)) | ||
6959 | { | ||
6960 | GNUNET_CONTAINER_DLL_remove (pg->cc_head, pg->cc_tail, cc); | ||
6961 | if (GNUNET_SCHEDULER_NO_TASK != cc->task) | ||
6962 | GNUNET_SCHEDULER_cancel (cc->task); | ||
6963 | if (NULL != cc->cc) | ||
6964 | GNUNET_TESTING_daemons_connect_cancel (cc->cc); | ||
6965 | GNUNET_free (cc); | ||
6966 | } | ||
6967 | |||
6968 | shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); | ||
6969 | shutdown_ctx->delete_files = | ||
6970 | GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "DELETE_FILES"); | ||
6971 | shutdown_ctx->cb = cb; | ||
6972 | shutdown_ctx->cb_cls = cb_cls; | ||
6973 | shutdown_ctx->total_peers = pg->total; | ||
6974 | shutdown_ctx->timeout = timeout; | ||
6975 | shutdown_ctx->pg = pg; | ||
6976 | |||
6977 | for (off = 0; off < pg->total; off++) | ||
6978 | { | ||
6979 | GNUNET_assert (NULL != pg->peers[off].daemon); | ||
6980 | peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext)); | ||
6981 | peer_shutdown_ctx->daemon = pg->peers[off].daemon; | ||
6982 | peer_shutdown_ctx->shutdown_ctx = shutdown_ctx; | ||
6983 | GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx); | ||
6984 | |||
6985 | if (NULL != pg->peers[off].cfg) | ||
6986 | { | ||
6987 | GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg); | ||
6988 | pg->peers[off].cfg = NULL; | ||
6989 | } | ||
6990 | #if OLD | ||
6991 | // FIXME Do DLL remove for all pg->peers[off].LIST | ||
6992 | conn_iter = pg->peers[off].allowed_peers_head; | ||
6993 | while (conn_iter != NULL) | ||
6994 | { | ||
6995 | temp_conn = conn_iter->next; | ||
6996 | GNUNET_free (conn_iter); | ||
6997 | conn_iter = temp_conn; | ||
6998 | } | ||
6999 | pg->peers[off].allowed_peers_head = NULL; | ||
7000 | |||
7001 | conn_iter = pg->peers[off].connect_peers_head; | ||
7002 | while (conn_iter != NULL) | ||
7003 | { | ||
7004 | temp_conn = conn_iter->next; | ||
7005 | GNUNET_free (conn_iter); | ||
7006 | conn_iter = temp_conn; | ||
7007 | } | ||
7008 | pg->peers[off].connect_peers_head = NULL; | ||
7009 | |||
7010 | conn_iter = pg->peers[off].blacklisted_peers_head; | ||
7011 | while (conn_iter != NULL) | ||
7012 | { | ||
7013 | temp_conn = conn_iter->next; | ||
7014 | GNUNET_free (conn_iter); | ||
7015 | conn_iter = temp_conn; | ||
7016 | } | ||
7017 | pg->peers[off].blacklisted_peers_head = NULL; | ||
7018 | |||
7019 | conn_iter = pg->peers[off].connect_peers_working_set_head; | ||
7020 | while (conn_iter != NULL) | ||
7021 | { | ||
7022 | temp_conn = conn_iter->next; | ||
7023 | GNUNET_free (conn_iter); | ||
7024 | conn_iter = temp_conn; | ||
7025 | } | ||
7026 | pg->peers[off].connect_peers_working_set_head = NULL; | ||
7027 | #else | ||
7028 | if (pg->peers[off].allowed_peers != NULL) | ||
7029 | GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers); | ||
7030 | if (pg->peers[off].connect_peers != NULL) | ||
7031 | GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers); | ||
7032 | if (pg->peers[off].blacklisted_peers != NULL) | ||
7033 | GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].blacklisted_peers); | ||
7034 | #endif | ||
7035 | } | ||
7036 | } | ||
7037 | |||
7038 | /* end of testing_group.c */ | ||
diff --git a/src/testing/testing_peergroup.c b/src/testing/testing_peergroup.c deleted file mode 100644 index 87504ed6d..000000000 --- a/src/testing/testing_peergroup.c +++ /dev/null | |||
@@ -1,1017 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2008-2011 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file testing/testing_peergroup.c | ||
23 | * @brief API implementation for easy peer group creation | ||
24 | * @author Nathan Evans | ||
25 | * @author Christian Grothoff | ||
26 | * | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_constants.h" | ||
30 | #include "gnunet_arm_service.h" | ||
31 | #include "gnunet_testing_lib.h" | ||
32 | #include "gnunet_core_service.h" | ||
33 | #include "gnunet_disk_lib.h" | ||
34 | |||
35 | /** Globals **/ | ||
36 | #define DEFAULT_CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
37 | |||
38 | #define DEFAULT_CONNECT_ATTEMPTS 2 | ||
39 | |||
40 | /** Struct definitions **/ | ||
41 | |||
42 | struct PeerGroupStartupContext | ||
43 | { | ||
44 | struct GNUNET_TESTING_PeerGroup *pg; | ||
45 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
46 | unsigned int total; | ||
47 | unsigned int peers_left; | ||
48 | unsigned long long max_concurrent_connections; | ||
49 | |||
50 | /** | ||
51 | * Maximum attemps to connect two daemons. | ||
52 | */ | ||
53 | unsigned long long connect_attempts; | ||
54 | |||
55 | /** | ||
56 | * How long to spend trying to establish all the connections? | ||
57 | */ | ||
58 | struct GNUNET_TIME_Relative connect_timeout; | ||
59 | |||
60 | unsigned long long max_concurrent_ssh; | ||
61 | struct GNUNET_TIME_Absolute timeout; | ||
62 | GNUNET_TESTING_NotifyConnection connect_cb; | ||
63 | GNUNET_TESTING_NotifyCompletion peergroup_cb; | ||
64 | |||
65 | /** | ||
66 | * Closure for all peergroup callbacks. | ||
67 | */ | ||
68 | void *cls; | ||
69 | |||
70 | const struct GNUNET_TESTING_Host *hostnames; | ||
71 | |||
72 | /** | ||
73 | * FIXME document | ||
74 | */ | ||
75 | enum GNUNET_TESTING_Topology topology; | ||
76 | |||
77 | float topology_percentage; | ||
78 | |||
79 | float topology_probability; | ||
80 | |||
81 | /** | ||
82 | * FIXME document | ||
83 | */ | ||
84 | enum GNUNET_TESTING_Topology restrict_topology; | ||
85 | |||
86 | /** | ||
87 | * FIXME document | ||
88 | */ | ||
89 | char *restrict_transports; | ||
90 | |||
91 | /** | ||
92 | * Initial connections | ||
93 | */ | ||
94 | enum GNUNET_TESTING_Topology connect_topology; | ||
95 | enum GNUNET_TESTING_TopologyOption connect_topology_option; | ||
96 | double connect_topology_option_modifier; | ||
97 | int verbose; | ||
98 | |||
99 | struct ProgressMeter *hostkey_meter; | ||
100 | struct ProgressMeter *peer_start_meter; | ||
101 | struct ProgressMeter *connect_meter; | ||
102 | |||
103 | /** | ||
104 | * Task used to kill the peergroup. | ||
105 | */ | ||
106 | GNUNET_SCHEDULER_TaskIdentifier die_task; | ||
107 | |||
108 | char *fail_reason; | ||
109 | |||
110 | /** | ||
111 | * Variable used to store the number of connections we should wait for. | ||
112 | */ | ||
113 | unsigned int expected_connections; | ||
114 | |||
115 | /** | ||
116 | * Time when the connecting peers was started. | ||
117 | */ | ||
118 | struct GNUNET_TIME_Absolute connect_start_time; | ||
119 | |||
120 | /** | ||
121 | * The total number of connections that have been created so far. | ||
122 | */ | ||
123 | unsigned int total_connections; | ||
124 | |||
125 | /** | ||
126 | * The total number of connections that have failed so far. | ||
127 | */ | ||
128 | unsigned int failed_connections; | ||
129 | |||
130 | /** | ||
131 | * File handle to write out topology in dot format. | ||
132 | */ | ||
133 | struct GNUNET_DISK_FileHandle *topology_output_file; | ||
134 | }; | ||
135 | |||
136 | struct TopologyOutputContext | ||
137 | { | ||
138 | struct GNUNET_DISK_FileHandle *file; | ||
139 | GNUNET_TESTING_NotifyCompletion notify_cb; | ||
140 | void *notify_cb_cls; | ||
141 | }; | ||
142 | |||
143 | /** | ||
144 | * Simple struct to keep track of progress, and print a | ||
145 | * percentage meter for long running tasks. | ||
146 | */ | ||
147 | struct ProgressMeter | ||
148 | { | ||
149 | /** | ||
150 | * Total number of tasks to complete. | ||
151 | */ | ||
152 | unsigned int total; | ||
153 | |||
154 | /** | ||
155 | * Print percentage done after modnum tasks. | ||
156 | */ | ||
157 | unsigned int modnum; | ||
158 | |||
159 | /** | ||
160 | * Print a . each dotnum tasks. | ||
161 | */ | ||
162 | unsigned int dotnum; | ||
163 | |||
164 | /** | ||
165 | * Total number completed thus far. | ||
166 | */ | ||
167 | unsigned int completed; | ||
168 | |||
169 | /** | ||
170 | * Whether or not to print. | ||
171 | */ | ||
172 | int print; | ||
173 | |||
174 | /** | ||
175 | * Startup string for progress meter. | ||
176 | */ | ||
177 | char *startup_string; | ||
178 | }; | ||
179 | |||
180 | |||
181 | /** Utility functions **/ | ||
182 | |||
183 | /** | ||
184 | * Create a meter to keep track of the progress of some task. | ||
185 | * | ||
186 | * @param total the total number of items to complete | ||
187 | * @param start_string a string to prefix the meter with (if printing) | ||
188 | * @param print GNUNET_YES to print the meter, GNUNET_NO to count | ||
189 | * internally only | ||
190 | * | ||
191 | * @return the progress meter | ||
192 | */ | ||
193 | static struct ProgressMeter * | ||
194 | create_meter (unsigned int total, char *start_string, int print) | ||
195 | { | ||
196 | struct ProgressMeter *ret; | ||
197 | |||
198 | ret = GNUNET_malloc (sizeof (struct ProgressMeter)); | ||
199 | ret->print = print; | ||
200 | ret->total = total; | ||
201 | ret->modnum = (total / 4 == 0) ? 1 : (total / 4); | ||
202 | ret->dotnum = (total / 50) + 1; | ||
203 | if (start_string != NULL) | ||
204 | ret->startup_string = GNUNET_strdup (start_string); | ||
205 | else | ||
206 | ret->startup_string = GNUNET_strdup (""); | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * Update progress meter (increment by one). | ||
213 | * | ||
214 | * @param meter the meter to update and print info for | ||
215 | * | ||
216 | * @return GNUNET_YES if called the total requested, | ||
217 | * GNUNET_NO if more items expected | ||
218 | */ | ||
219 | static int | ||
220 | update_meter (struct ProgressMeter *meter) | ||
221 | { | ||
222 | if (meter->print == GNUNET_YES) | ||
223 | { | ||
224 | if (meter->completed % meter->modnum == 0) | ||
225 | { | ||
226 | if (meter->completed == 0) | ||
227 | { | ||
228 | FPRINTF (stdout, "%sProgress: [0%%", meter->startup_string); | ||
229 | } | ||
230 | else | ||
231 | FPRINTF (stdout, "%d%%", | ||
232 | (int) (((float) meter->completed / meter->total) * 100)); | ||
233 | } | ||
234 | else if (meter->completed % meter->dotnum == 0) | ||
235 | FPRINTF (stdout, "%s", "."); | ||
236 | |||
237 | if (meter->completed + 1 == meter->total) | ||
238 | FPRINTF (stdout, "%d%%]\n", 100); | ||
239 | fflush (stdout); | ||
240 | } | ||
241 | meter->completed++; | ||
242 | |||
243 | if (meter->completed == meter->total) | ||
244 | return GNUNET_YES; | ||
245 | return GNUNET_NO; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * Reset progress meter. | ||
250 | * | ||
251 | * @param meter the meter to reset | ||
252 | * | ||
253 | * @return GNUNET_YES if meter reset, | ||
254 | * GNUNET_SYSERR on error | ||
255 | */ | ||
256 | static int | ||
257 | reset_meter (struct ProgressMeter *meter) | ||
258 | { | ||
259 | if (meter == NULL) | ||
260 | return GNUNET_SYSERR; | ||
261 | |||
262 | meter->completed = 0; | ||
263 | return GNUNET_YES; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * Release resources for meter | ||
268 | * | ||
269 | * @param meter the meter to free | ||
270 | */ | ||
271 | static void | ||
272 | free_meter (struct ProgressMeter *meter) | ||
273 | { | ||
274 | GNUNET_free_non_null (meter->startup_string); | ||
275 | GNUNET_free (meter); | ||
276 | } | ||
277 | |||
278 | |||
279 | /** Functions for creating, starting and connecting the peergroup **/ | ||
280 | |||
281 | /** | ||
282 | * Check whether peers successfully shut down. | ||
283 | */ | ||
284 | static void | ||
285 | internal_shutdown_callback (void *cls, const char *emsg) | ||
286 | { | ||
287 | struct PeerGroupStartupContext *pg_start_ctx = cls; | ||
288 | |||
289 | if (emsg != NULL) | ||
290 | pg_start_ctx->peergroup_cb (pg_start_ctx->cls, emsg); | ||
291 | else | ||
292 | pg_start_ctx->peergroup_cb (pg_start_ctx->cls, pg_start_ctx->fail_reason); | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * Check if the get_handle is being used, if so stop the request. Either | ||
297 | * way, schedule the end_badly_cont function which actually shuts down the | ||
298 | * test. | ||
299 | */ | ||
300 | static void | ||
301 | end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
302 | { | ||
303 | struct PeerGroupStartupContext *pg_start_ctx = cls; | ||
304 | |||
305 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
306 | "Failing peer group startup with error: `%s'!\n", | ||
307 | pg_start_ctx->fail_reason); | ||
308 | |||
309 | GNUNET_TESTING_daemons_stop (pg_start_ctx->pg, | ||
310 | GNUNET_TIME_absolute_get_remaining | ||
311 | (pg_start_ctx->timeout), | ||
312 | &internal_shutdown_callback, pg_start_ctx); | ||
313 | |||
314 | if (pg_start_ctx->hostkey_meter != NULL) | ||
315 | { | ||
316 | free_meter (pg_start_ctx->hostkey_meter); | ||
317 | pg_start_ctx->hostkey_meter = NULL; | ||
318 | } | ||
319 | if (pg_start_ctx->peer_start_meter != NULL) | ||
320 | { | ||
321 | free_meter (pg_start_ctx->peer_start_meter); | ||
322 | pg_start_ctx->peer_start_meter = NULL; | ||
323 | } | ||
324 | if (pg_start_ctx->connect_meter != NULL) | ||
325 | { | ||
326 | free_meter (pg_start_ctx->connect_meter); | ||
327 | pg_start_ctx->connect_meter = NULL; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * This function is called whenever a connection attempt is finished between two of | ||
333 | * the started peers (started with GNUNET_TESTING_daemons_start). The total | ||
334 | * number of times this function is called should equal the number returned | ||
335 | * from the GNUNET_TESTING_connect_topology call. | ||
336 | * | ||
337 | * The emsg variable is NULL on success (peers connected), and non-NULL on | ||
338 | * failure (peers failed to connect). | ||
339 | */ | ||
340 | static void | ||
341 | internal_topology_callback (void *cls, const struct GNUNET_PeerIdentity *first, | ||
342 | const struct GNUNET_PeerIdentity *second, | ||
343 | uint32_t distance, | ||
344 | const struct GNUNET_CONFIGURATION_Handle *first_cfg, | ||
345 | const struct GNUNET_CONFIGURATION_Handle | ||
346 | *second_cfg, | ||
347 | struct GNUNET_TESTING_Daemon *first_daemon, | ||
348 | struct GNUNET_TESTING_Daemon *second_daemon, | ||
349 | const char *emsg) | ||
350 | { | ||
351 | struct PeerGroupStartupContext *pg_start_ctx = cls; | ||
352 | char *temp_str; | ||
353 | char *second_str; | ||
354 | int temp; | ||
355 | |||
356 | #if TIMING | ||
357 | unsigned long long duration; | ||
358 | unsigned long long total_duration; | ||
359 | unsigned int new_connections; | ||
360 | unsigned int new_failed_connections; | ||
361 | double conns_per_sec_recent; | ||
362 | double conns_per_sec_total; | ||
363 | double failed_conns_per_sec_recent; | ||
364 | double failed_conns_per_sec_total; | ||
365 | #endif | ||
366 | |||
367 | #if TIMING | ||
368 | if (GNUNET_TIME_absolute_get_difference | ||
369 | (connect_last_time, | ||
370 | GNUNET_TIME_absolute_get ()).rel_value > | ||
371 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
372 | CONN_UPDATE_DURATION).rel_value) | ||
373 | { | ||
374 | /* Get number of new connections */ | ||
375 | new_connections = total_connections - previous_connections; | ||
376 | |||
377 | /* Get number of new FAILED connections */ | ||
378 | new_failed_connections = failed_connections - previous_failed_connections; | ||
379 | |||
380 | /* Get duration in seconds */ | ||
381 | duration = | ||
382 | GNUNET_TIME_absolute_get_difference (connect_last_time, | ||
383 | GNUNET_TIME_absolute_get | ||
384 | ()).rel_value / 1000; | ||
385 | total_duration = | ||
386 | GNUNET_TIME_absolute_get_difference (connect_start_time, | ||
387 | GNUNET_TIME_absolute_get | ||
388 | ()).rel_value / 1000; | ||
389 | |||
390 | failed_conns_per_sec_recent = (double) new_failed_connections / duration; | ||
391 | failed_conns_per_sec_total = (double) failed_connections / total_duration; | ||
392 | conns_per_sec_recent = (double) new_connections / duration; | ||
393 | conns_per_sec_total = (double) total_connections / total_duration; | ||
394 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
395 | "Recent: %.2f/s, Total: %.2f/s, Recent failed: %.2f/s, total failed %.2f/s\n", | ||
396 | conns_per_sec_recent, CONN_UPDATE_DURATION, conns_per_sec_total, | ||
397 | failed_conns_per_sec_recent, failed_conns_per_sec_total); | ||
398 | connect_last_time = GNUNET_TIME_absolute_get (); | ||
399 | previous_connections = total_connections; | ||
400 | previous_failed_connections = failed_connections; | ||
401 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
402 | "have %u total_connections, %u failed\n", total_connections, | ||
403 | failed_connections); | ||
404 | } | ||
405 | #endif | ||
406 | |||
407 | |||
408 | if (emsg == NULL) | ||
409 | { | ||
410 | pg_start_ctx->total_connections++; | ||
411 | #if VERBOSE > 1 | ||
412 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
413 | "connected peer %s to peer %s, distance %u\n", | ||
414 | first_daemon->shortname, second_daemon->shortname, distance); | ||
415 | #endif | ||
416 | if (pg_start_ctx->topology_output_file != NULL) | ||
417 | { | ||
418 | second_str = GNUNET_strdup (GNUNET_i2s (second)); | ||
419 | temp = | ||
420 | GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", | ||
421 | GNUNET_i2s (first), second_str); | ||
422 | GNUNET_free (second_str); | ||
423 | if (temp > 0) | ||
424 | GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, | ||
425 | temp); | ||
426 | GNUNET_free (temp_str); | ||
427 | } | ||
428 | } | ||
429 | else | ||
430 | { | ||
431 | pg_start_ctx->failed_connections++; | ||
432 | #if VERBOSE | ||
433 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
434 | "Failed to connect peer %s to peer %s with error :\n%s\n", | ||
435 | first_daemon->shortname, second_daemon->shortname, emsg); | ||
436 | |||
437 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
438 | "Failed to connect peer %s to peer %s with error :\n%s\n", | ||
439 | first_daemon->shortname, second_daemon->shortname, emsg); | ||
440 | #endif | ||
441 | } | ||
442 | |||
443 | GNUNET_assert (pg_start_ctx->connect_meter != NULL); | ||
444 | if (pg_start_ctx->connect_cb != NULL) | ||
445 | pg_start_ctx->connect_cb (pg_start_ctx->cls, first, second, distance, | ||
446 | first_cfg, second_cfg, first_daemon, | ||
447 | second_daemon, emsg); | ||
448 | if (GNUNET_YES != update_meter (pg_start_ctx->connect_meter)) | ||
449 | { | ||
450 | /* No finished yet */ | ||
451 | return; | ||
452 | } | ||
453 | #if VERBOSE | ||
454 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
455 | "Created %d total connections, which is our target number! Starting next phase of testing.\n", | ||
456 | pg_start_ctx->total_connections); | ||
457 | #endif | ||
458 | |||
459 | #if TIMING | ||
460 | total_duration = | ||
461 | GNUNET_TIME_absolute_get_difference (connect_start_time, | ||
462 | GNUNET_TIME_absolute_get | ||
463 | ()).rel_value / 1000; | ||
464 | failed_conns_per_sec_total = (double) failed_connections / total_duration; | ||
465 | conns_per_sec_total = (double) total_connections / total_duration; | ||
466 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
467 | "Overall connection info --- Total: %u, Total Failed %u/s\n", | ||
468 | total_connections, failed_connections); | ||
469 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
470 | "Overall connection info --- Total: %.2f/s, Total Failed %.2f/s\n", | ||
471 | conns_per_sec_total, failed_conns_per_sec_total); | ||
472 | #endif | ||
473 | |||
474 | GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); | ||
475 | GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); | ||
476 | |||
477 | /* Call final callback, signifying that the peer group has been started and connected */ | ||
478 | if (pg_start_ctx->peergroup_cb != NULL) | ||
479 | pg_start_ctx->peergroup_cb (pg_start_ctx->cls, NULL); | ||
480 | |||
481 | if (pg_start_ctx->topology_output_file != NULL) | ||
482 | { | ||
483 | temp = GNUNET_asprintf (&temp_str, "}\n"); | ||
484 | if (temp > 0) | ||
485 | GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, | ||
486 | temp); | ||
487 | GNUNET_free (temp_str); | ||
488 | GNUNET_DISK_file_close (pg_start_ctx->topology_output_file); | ||
489 | } | ||
490 | GNUNET_free_non_null (pg_start_ctx->fail_reason); | ||
491 | if (NULL != pg_start_ctx->hostkey_meter) | ||
492 | free_meter(pg_start_ctx->hostkey_meter); | ||
493 | if (NULL != pg_start_ctx->peer_start_meter) | ||
494 | free_meter(pg_start_ctx->peer_start_meter); | ||
495 | if (NULL != pg_start_ctx->connect_meter) | ||
496 | free_meter(pg_start_ctx->connect_meter); | ||
497 | GNUNET_free (pg_start_ctx); | ||
498 | } | ||
499 | |||
500 | |||
501 | /** | ||
502 | * Callback called for each started daemon. | ||
503 | * | ||
504 | * @param cls Clause (PG Context). | ||
505 | * @param id PeerIdentidy of started daemon. | ||
506 | * @param cfg Configuration used by the daemon. | ||
507 | * @param d Handle for the daemon. | ||
508 | * @param emsg Error message, NULL on success. | ||
509 | */ | ||
510 | static void | ||
511 | internal_peers_started_callback (void *cls, | ||
512 | const struct GNUNET_PeerIdentity *id, | ||
513 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
514 | struct GNUNET_TESTING_Daemon *d, | ||
515 | const char *emsg) | ||
516 | { | ||
517 | struct PeerGroupStartupContext *pg_start_ctx = cls; | ||
518 | |||
519 | if (emsg != NULL) | ||
520 | { | ||
521 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
522 | "Failed to start daemon with error: `%s'\n", emsg); | ||
523 | return; | ||
524 | } | ||
525 | GNUNET_assert (id != NULL); | ||
526 | |||
527 | #if VERBOSE > 1 | ||
528 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Started daemon %llu out of %llu\n", | ||
529 | (pg_start_ctx->total - pg_start_ctx->peers_left) + 1, | ||
530 | pg_start_ctx->total); | ||
531 | #endif | ||
532 | |||
533 | pg_start_ctx->peers_left--; | ||
534 | |||
535 | if (NULL == pg_start_ctx->peer_start_meter) | ||
536 | { | ||
537 | /* Cancelled Ctrl-C or error */ | ||
538 | return; | ||
539 | } | ||
540 | if (GNUNET_YES == update_meter (pg_start_ctx->peer_start_meter)) | ||
541 | { | ||
542 | #if VERBOSE | ||
543 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
544 | "All %d daemons started, now connecting peers!\n", | ||
545 | pg_start_ctx->total); | ||
546 | #endif | ||
547 | GNUNET_assert (pg_start_ctx->die_task != GNUNET_SCHEDULER_NO_TASK); | ||
548 | GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); | ||
549 | |||
550 | pg_start_ctx->expected_connections = UINT_MAX; | ||
551 | // FIXME: why whould peers_left be != 0?? Or pg NULL? | ||
552 | if ((pg_start_ctx->pg != NULL) && (pg_start_ctx->peers_left == 0)) | ||
553 | { | ||
554 | pg_start_ctx->connect_start_time = GNUNET_TIME_absolute_get (); | ||
555 | pg_start_ctx->expected_connections = | ||
556 | GNUNET_TESTING_connect_topology (pg_start_ctx->pg, | ||
557 | pg_start_ctx->connect_topology, | ||
558 | pg_start_ctx->connect_topology_option, | ||
559 | pg_start_ctx->connect_topology_option_modifier, | ||
560 | pg_start_ctx->connect_timeout, | ||
561 | pg_start_ctx->connect_attempts, NULL, | ||
562 | NULL); | ||
563 | |||
564 | pg_start_ctx->connect_meter = | ||
565 | create_meter (pg_start_ctx->expected_connections, "Peer connection ", | ||
566 | pg_start_ctx->verbose); | ||
567 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have %d expected connections\n", | ||
568 | pg_start_ctx->expected_connections); | ||
569 | } | ||
570 | |||
571 | if (pg_start_ctx->expected_connections == 0) | ||
572 | { | ||
573 | GNUNET_free_non_null (pg_start_ctx->fail_reason); | ||
574 | pg_start_ctx->fail_reason = | ||
575 | GNUNET_strdup ("from connect topology (bad return)"); | ||
576 | pg_start_ctx->die_task = | ||
577 | GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); | ||
578 | return; | ||
579 | } | ||
580 | |||
581 | GNUNET_free_non_null (pg_start_ctx->fail_reason); | ||
582 | pg_start_ctx->fail_reason = | ||
583 | GNUNET_strdup ("from connect topology (timeout)"); | ||
584 | pg_start_ctx->die_task = | ||
585 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | ||
586 | (pg_start_ctx->timeout), &end_badly, | ||
587 | pg_start_ctx); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * Callback indicating that the hostkey was created for a peer. | ||
593 | * | ||
594 | * @param cls NULL | ||
595 | * @param id the peer identity | ||
596 | * @param d the daemon handle (pretty useless at this point, remove?) | ||
597 | * @param emsg non-null on failure | ||
598 | */ | ||
599 | static void | ||
600 | internal_hostkey_callback (void *cls, const struct GNUNET_PeerIdentity *id, | ||
601 | struct GNUNET_TESTING_Daemon *d, const char *emsg) | ||
602 | { | ||
603 | struct PeerGroupStartupContext *pg_start_ctx = cls; | ||
604 | unsigned int create_expected_connections; | ||
605 | |||
606 | if (emsg != NULL) | ||
607 | { | ||
608 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
609 | "Hostkey callback received error: %s\n", emsg); | ||
610 | } | ||
611 | |||
612 | #if VERBOSE > 1 | ||
613 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
614 | "Hostkey (%d/%d) created for peer `%s'\n", | ||
615 | pg_start_ctx->total - pg_start_ctx->peers_left + 1, | ||
616 | pg_start_ctx->total, GNUNET_i2s (id)); | ||
617 | #endif | ||
618 | |||
619 | pg_start_ctx->peers_left--; | ||
620 | if (GNUNET_YES == update_meter (pg_start_ctx->hostkey_meter)) | ||
621 | { | ||
622 | GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); | ||
623 | GNUNET_free_non_null (pg_start_ctx->fail_reason); | ||
624 | /* Set up task in case topology creation doesn't finish | ||
625 | * within a reasonable amount of time */ | ||
626 | pg_start_ctx->fail_reason = GNUNET_strdup ("from create_topology"); | ||
627 | pg_start_ctx->die_task = | ||
628 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | ||
629 | (pg_start_ctx->timeout), &end_badly, | ||
630 | pg_start_ctx); | ||
631 | pg_start_ctx->peers_left = pg_start_ctx->total; /* Reset counter */ | ||
632 | create_expected_connections = | ||
633 | GNUNET_TESTING_create_topology (pg_start_ctx->pg, | ||
634 | pg_start_ctx->topology, | ||
635 | pg_start_ctx->restrict_topology, | ||
636 | pg_start_ctx->restrict_transports); | ||
637 | if (create_expected_connections > 0) | ||
638 | { | ||
639 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
640 | "Topology set up, have %u expected connections, now starting peers!\n", | ||
641 | create_expected_connections); | ||
642 | GNUNET_TESTING_daemons_continue_startup (pg_start_ctx->pg); | ||
643 | } | ||
644 | else | ||
645 | { | ||
646 | GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); | ||
647 | GNUNET_free_non_null (pg_start_ctx->fail_reason); | ||
648 | pg_start_ctx->fail_reason = | ||
649 | GNUNET_strdup ("from create topology (bad return)"); | ||
650 | pg_start_ctx->die_task = | ||
651 | GNUNET_SCHEDULER_add_now (&end_badly, pg_start_ctx); | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | GNUNET_SCHEDULER_cancel (pg_start_ctx->die_task); | ||
656 | GNUNET_free_non_null (pg_start_ctx->fail_reason); | ||
657 | pg_start_ctx->fail_reason = | ||
658 | GNUNET_strdup ("from continue startup (timeout)"); | ||
659 | pg_start_ctx->die_task = | ||
660 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | ||
661 | (pg_start_ctx->timeout), &end_badly, | ||
662 | pg_start_ctx); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | |||
667 | /** | ||
668 | * Prototype of a callback function indicating that two peers | ||
669 | * are currently connected. | ||
670 | * | ||
671 | * @param cls closure | ||
672 | * @param first peer id for first daemon | ||
673 | * @param second peer id for the second daemon | ||
674 | * @param emsg error message (NULL on success) | ||
675 | */ | ||
676 | void | ||
677 | write_topology_cb (void *cls, const struct GNUNET_PeerIdentity *first, | ||
678 | const struct GNUNET_PeerIdentity *second, const char *emsg) | ||
679 | { | ||
680 | struct TopologyOutputContext *topo_ctx; | ||
681 | int temp; | ||
682 | char *temp_str; | ||
683 | char *temp_pid2; | ||
684 | |||
685 | topo_ctx = (struct TopologyOutputContext *) cls; | ||
686 | GNUNET_assert (topo_ctx->file != NULL); | ||
687 | if ((emsg == NULL) && (first != NULL) && (second != NULL)) | ||
688 | { | ||
689 | GNUNET_assert (first != NULL); | ||
690 | GNUNET_assert (second != NULL); | ||
691 | temp_pid2 = GNUNET_strdup (GNUNET_i2s (second)); | ||
692 | temp = | ||
693 | GNUNET_asprintf (&temp_str, "\t\"%s\" -- \"%s\"\n", GNUNET_i2s (first), | ||
694 | temp_pid2); | ||
695 | GNUNET_free (temp_pid2); | ||
696 | GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); | ||
697 | } | ||
698 | else if ((emsg == NULL) && (first == NULL) && (second == NULL)) | ||
699 | { | ||
700 | temp = GNUNET_asprintf (&temp_str, "}\n"); | ||
701 | GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); | ||
702 | GNUNET_DISK_file_close (topo_ctx->file); | ||
703 | topo_ctx->notify_cb (topo_ctx->notify_cb_cls, NULL); | ||
704 | GNUNET_free (topo_ctx); | ||
705 | } | ||
706 | else | ||
707 | { | ||
708 | temp = GNUNET_asprintf (&temp_str, "}\n"); | ||
709 | GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); | ||
710 | GNUNET_DISK_file_close (topo_ctx->file); | ||
711 | topo_ctx->notify_cb (topo_ctx->notify_cb_cls, emsg); | ||
712 | GNUNET_free (topo_ctx); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | /** | ||
717 | * Print current topology to a graphviz readable file. | ||
718 | * | ||
719 | * @param pg a currently running peergroup to print to file | ||
720 | * @param output_filename the file to write the topology to | ||
721 | * @param notify_cb callback to call upon completion or failure | ||
722 | * @param notify_cb_cls closure for notify_cb | ||
723 | * | ||
724 | */ | ||
725 | void | ||
726 | GNUNET_TESTING_peergroup_topology_to_file (struct GNUNET_TESTING_PeerGroup *pg, | ||
727 | const char *output_filename, | ||
728 | GNUNET_TESTING_NotifyCompletion | ||
729 | notify_cb, void *notify_cb_cls) | ||
730 | { | ||
731 | struct TopologyOutputContext *topo_ctx; | ||
732 | int temp; | ||
733 | char *temp_str; | ||
734 | |||
735 | topo_ctx = GNUNET_malloc (sizeof (struct TopologyOutputContext)); | ||
736 | |||
737 | topo_ctx->notify_cb = notify_cb; | ||
738 | topo_ctx->notify_cb_cls = notify_cb_cls; | ||
739 | topo_ctx->file = | ||
740 | GNUNET_DISK_file_open (output_filename, | ||
741 | GNUNET_DISK_OPEN_READWRITE | | ||
742 | GNUNET_DISK_OPEN_CREATE, | ||
743 | GNUNET_DISK_PERM_USER_READ | | ||
744 | GNUNET_DISK_PERM_USER_WRITE); | ||
745 | if (topo_ctx->file == NULL) | ||
746 | { | ||
747 | notify_cb (notify_cb_cls, "Failed to open output file!"); | ||
748 | GNUNET_free (topo_ctx); | ||
749 | return; | ||
750 | } | ||
751 | |||
752 | temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); | ||
753 | if (temp > 0) | ||
754 | GNUNET_DISK_file_write (topo_ctx->file, temp_str, temp); | ||
755 | GNUNET_free_non_null (temp_str); | ||
756 | GNUNET_TESTING_get_topology (pg, &write_topology_cb, topo_ctx); | ||
757 | } | ||
758 | |||
759 | /** | ||
760 | * Start a peer group with a given number of peers. Notify | ||
761 | * on completion of peer startup and connection based on given | ||
762 | * topological constraints. Optionally notify on each | ||
763 | * established connection. | ||
764 | * | ||
765 | * @param cfg configuration template to use | ||
766 | * @param total number of daemons to start | ||
767 | * @param timeout total time allowed for peers to start | ||
768 | * @param connect_cb function to call each time two daemons are connected | ||
769 | * @param peergroup_cb function to call once all peers are up and connected | ||
770 | * @param peergroup_cls closure for peergroup callbacks | ||
771 | * @param hostnames linked list of host structs to use to start peers on | ||
772 | * (NULL to run on localhost only) | ||
773 | * | ||
774 | * @return NULL on error, otherwise handle to control peer group | ||
775 | */ | ||
776 | struct GNUNET_TESTING_PeerGroup * | ||
777 | GNUNET_TESTING_peergroup_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
778 | unsigned int total, | ||
779 | struct GNUNET_TIME_Relative timeout, | ||
780 | GNUNET_TESTING_NotifyConnection connect_cb, | ||
781 | GNUNET_TESTING_NotifyCompletion peergroup_cb, | ||
782 | void *peergroup_cls, | ||
783 | const struct GNUNET_TESTING_Host *hostnames) | ||
784 | { | ||
785 | struct PeerGroupStartupContext *pg_start_ctx; | ||
786 | char *temp_str; | ||
787 | int temp; | ||
788 | struct GNUNET_TIME_Relative rtimeout; | ||
789 | |||
790 | GNUNET_assert (total > 0); | ||
791 | GNUNET_assert (cfg != NULL); | ||
792 | |||
793 | pg_start_ctx = GNUNET_malloc (sizeof (struct PeerGroupStartupContext)); | ||
794 | |||
795 | if (GNUNET_OK != | ||
796 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", "connect_attempts", | ||
797 | &pg_start_ctx->connect_attempts)) | ||
798 | { | ||
799 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
800 | "testing", "connect_attempts"); | ||
801 | GNUNET_free (pg_start_ctx); | ||
802 | return NULL; | ||
803 | } | ||
804 | |||
805 | if (GNUNET_OK != | ||
806 | GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "CONNECT_TIMEOUT", | ||
807 | &pg_start_ctx->connect_timeout)) | ||
808 | { | ||
809 | pg_start_ctx->connect_timeout = DEFAULT_CONNECT_TIMEOUT; | ||
810 | } | ||
811 | |||
812 | if (GNUNET_OK != | ||
813 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", | ||
814 | "max_outstanding_connections", | ||
815 | &pg_start_ctx->max_concurrent_connections)) | ||
816 | { | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
818 | "testing", "max_outstanding_connections"); | ||
819 | GNUNET_free (pg_start_ctx); | ||
820 | return NULL; | ||
821 | } | ||
822 | |||
823 | if (GNUNET_OK != | ||
824 | GNUNET_CONFIGURATION_get_value_number (cfg, "testing", | ||
825 | "max_concurrent_ssh", | ||
826 | &pg_start_ctx->max_concurrent_ssh)) | ||
827 | { | ||
828 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
829 | "testing", "max_concurrent_ssh"); | ||
830 | GNUNET_free (pg_start_ctx); | ||
831 | return NULL; | ||
832 | } | ||
833 | |||
834 | if (GNUNET_SYSERR == | ||
835 | (pg_start_ctx->verbose = | ||
836 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "testing", | ||
837 | "use_progressbars"))) | ||
838 | { | ||
839 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
840 | "testing", "use_progressbars"); | ||
841 | GNUNET_free (pg_start_ctx); | ||
842 | return NULL; | ||
843 | } | ||
844 | |||
845 | if (GNUNET_OK != | ||
846 | GNUNET_CONFIGURATION_get_value_time (cfg, "testing", "PEERGROUP_TIMEOUT", | ||
847 | &rtimeout)) | ||
848 | { | ||
849 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Must provide option %s:%s!\n", | ||
850 | "testing", "PEERGROUP_TIMEOUT"); | ||
851 | GNUNET_free (pg_start_ctx); | ||
852 | return NULL; | ||
853 | } | ||
854 | pg_start_ctx->timeout = GNUNET_TIME_relative_to_absolute (rtimeout); | ||
855 | |||
856 | |||
857 | /* Read topology related options from the configuration file */ | ||
858 | temp_str = NULL; | ||
859 | if ((GNUNET_YES == | ||
860 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "topology", | ||
861 | &temp_str)) && | ||
862 | (GNUNET_NO == | ||
863 | GNUNET_TESTING_topology_get (&pg_start_ctx->topology, temp_str))) | ||
864 | { | ||
865 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
866 | "Invalid topology `%s' given for section %s option %s\n", | ||
867 | temp_str, "TESTING", "TOPOLOGY"); | ||
868 | pg_start_ctx->topology = GNUNET_TESTING_TOPOLOGY_CLIQUE; /* Defaults to NONE, so set better default here */ | ||
869 | } | ||
870 | GNUNET_free_non_null (temp_str); | ||
871 | |||
872 | if (GNUNET_YES == | ||
873 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
874 | "topology_output_file", &temp_str)) | ||
875 | { | ||
876 | pg_start_ctx->topology_output_file = | ||
877 | GNUNET_DISK_file_open (temp_str, | ||
878 | GNUNET_DISK_OPEN_READWRITE | | ||
879 | GNUNET_DISK_OPEN_CREATE, | ||
880 | GNUNET_DISK_PERM_USER_READ | | ||
881 | GNUNET_DISK_PERM_USER_WRITE); | ||
882 | if (pg_start_ctx->topology_output_file != NULL) | ||
883 | { | ||
884 | GNUNET_free (temp_str); | ||
885 | temp = GNUNET_asprintf (&temp_str, "strict graph G {\n"); | ||
886 | if (temp > 0) | ||
887 | GNUNET_DISK_file_write (pg_start_ctx->topology_output_file, temp_str, | ||
888 | temp); | ||
889 | } | ||
890 | GNUNET_free (temp_str); | ||
891 | } | ||
892 | |||
893 | if (GNUNET_OK != | ||
894 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "percentage", | ||
895 | &temp_str)) | ||
896 | pg_start_ctx->topology_percentage = 0.5; | ||
897 | else | ||
898 | { | ||
899 | pg_start_ctx->topology_percentage = atof (temp_str); | ||
900 | GNUNET_free (temp_str); | ||
901 | } | ||
902 | |||
903 | if (GNUNET_OK != | ||
904 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", "probability", | ||
905 | &temp_str)) | ||
906 | pg_start_ctx->topology_probability = 0.5; | ||
907 | else | ||
908 | { | ||
909 | pg_start_ctx->topology_probability = atof (temp_str); | ||
910 | GNUNET_free (temp_str); | ||
911 | } | ||
912 | |||
913 | if ((GNUNET_YES == | ||
914 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
915 | "connect_topology", &temp_str)) && | ||
916 | (GNUNET_NO == | ||
917 | GNUNET_TESTING_topology_get (&pg_start_ctx->connect_topology, temp_str))) | ||
918 | { | ||
919 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
920 | "Invalid connect topology `%s' given for section %s option %s\n", | ||
921 | temp_str, "TESTING", "CONNECT_TOPOLOGY"); | ||
922 | } | ||
923 | GNUNET_free_non_null (temp_str); | ||
924 | |||
925 | if ((GNUNET_YES == | ||
926 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
927 | "connect_topology_option", | ||
928 | &temp_str)) && | ||
929 | (GNUNET_NO == | ||
930 | GNUNET_TESTING_topology_option_get | ||
931 | (&pg_start_ctx->connect_topology_option, temp_str))) | ||
932 | { | ||
933 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
934 | "Invalid connect topology option `%s' given for section %s option %s\n", | ||
935 | temp_str, "TESTING", "CONNECT_TOPOLOGY_OPTION"); | ||
936 | pg_start_ctx->connect_topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_ALL; /* Defaults to NONE, set to ALL */ | ||
937 | } | ||
938 | GNUNET_free_non_null (temp_str); | ||
939 | |||
940 | if (GNUNET_YES == | ||
941 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
942 | "connect_topology_option_modifier", | ||
943 | &temp_str)) | ||
944 | { | ||
945 | if (SSCANF | ||
946 | (temp_str, "%lf", &pg_start_ctx->connect_topology_option_modifier) != 1) | ||
947 | { | ||
948 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
949 | _ | ||
950 | ("Invalid value `%s' for option `%s' in section `%s': expected float\n"), | ||
951 | temp_str, "connect_topology_option_modifier", "TESTING"); | ||
952 | GNUNET_free (temp_str); | ||
953 | GNUNET_free (pg_start_ctx); | ||
954 | return NULL; | ||
955 | } | ||
956 | GNUNET_free (temp_str); | ||
957 | } | ||
958 | |||
959 | if (GNUNET_YES != | ||
960 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
961 | "blacklist_transports", | ||
962 | &pg_start_ctx->restrict_transports)) | ||
963 | pg_start_ctx->restrict_transports = NULL; | ||
964 | |||
965 | pg_start_ctx->restrict_topology = GNUNET_TESTING_TOPOLOGY_NONE; | ||
966 | if ((GNUNET_YES == | ||
967 | GNUNET_CONFIGURATION_get_value_string (cfg, "testing", | ||
968 | "blacklist_topology", &temp_str)) | ||
969 | && (GNUNET_NO == | ||
970 | GNUNET_TESTING_topology_get (&pg_start_ctx->restrict_topology, | ||
971 | temp_str))) | ||
972 | { | ||
973 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
974 | "Invalid topology `%s' given for section %s option %s\n", | ||
975 | temp_str, "TESTING", "BLACKLIST_TOPOLOGY"); | ||
976 | } | ||
977 | |||
978 | GNUNET_free_non_null (temp_str); | ||
979 | |||
980 | pg_start_ctx->cfg = cfg; | ||
981 | pg_start_ctx->total = total; | ||
982 | pg_start_ctx->peers_left = total; | ||
983 | pg_start_ctx->connect_cb = connect_cb; | ||
984 | pg_start_ctx->peergroup_cb = peergroup_cb; | ||
985 | pg_start_ctx->cls = peergroup_cls; | ||
986 | pg_start_ctx->hostnames = hostnames; | ||
987 | pg_start_ctx->hostkey_meter = | ||
988 | create_meter (pg_start_ctx->peers_left, "Hostkeys created ", | ||
989 | pg_start_ctx->verbose); | ||
990 | pg_start_ctx->peer_start_meter = | ||
991 | create_meter (pg_start_ctx->peers_left, "Peers started ", | ||
992 | pg_start_ctx->verbose); | ||
993 | /* Make compilers happy */ | ||
994 | reset_meter (pg_start_ctx->peer_start_meter); | ||
995 | pg_start_ctx->fail_reason = | ||
996 | GNUNET_strdup | ||
997 | ("didn't generate all hostkeys within allowed startup time!"); | ||
998 | pg_start_ctx->die_task = | ||
999 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | ||
1000 | (pg_start_ctx->timeout), &end_badly, | ||
1001 | pg_start_ctx); | ||
1002 | |||
1003 | pg_start_ctx->pg = | ||
1004 | GNUNET_TESTING_daemons_start (pg_start_ctx->cfg, pg_start_ctx->peers_left, | ||
1005 | pg_start_ctx->max_concurrent_connections, | ||
1006 | pg_start_ctx->max_concurrent_ssh, | ||
1007 | GNUNET_TIME_absolute_get_remaining | ||
1008 | (pg_start_ctx->timeout), | ||
1009 | &internal_hostkey_callback, pg_start_ctx, | ||
1010 | &internal_peers_started_callback, | ||
1011 | pg_start_ctx, &internal_topology_callback, | ||
1012 | pg_start_ctx, pg_start_ctx->hostnames); | ||
1013 | |||
1014 | return pg_start_ctx->pg; | ||
1015 | } | ||
1016 | |||
1017 | /* end of testing_peergroup.c */ | ||